
From the user’s perspective, the task is pretty simple: you install a special app, then enable developer mode in the settings, and make the installed application the provider of fictitious coodrinates. There are plenty of such programs: from very primitive to sophisticated ones that not only substitute coordinates with arbitrary values, but can also change them according to a schedule or play prerecorded tracks, thus, simulating movement along a certain route. So, all you have to do is search Google Play for “Fake GPS” and select an app to your taste.
Too bad, this method is not very reliable. The presence of such an app on your phone can be detected at the software level, and some programs won’t be fooled by it.
I decided to find out how the GPS substitution mechanism works and create my own spoofing application. First of all, I checked how this algorithm is implemented in one of the free apps.
Reversing FakeGPS
I used the FakeGPS 5.0.0 app. It looks like a map: you set a marker at an arbitrary point of this map and start or stop the transmission of coordinates of the selected point using the “Start” and “Stop” buttons.
I launch JEB Decompiler and start examining the program. The presence of android.
in the manifest immediately attracts my attention.
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /><uses-permission android:name="android.permission.WRITE_SETTINGS" /><uses-permission android:name="com.android.vending.BILLING" />
Nothing of interest can be found in the main activity (just the ordinary initialization and setup procedures), but there is also a service called FakeGPSService
.

I try to break through the obfuscation and see what it’s all about.
The onCreate
method includes the following code:
this.f = "gps";this.d = (LocationManager)this.getSystemService("location");try { if(this.d == null) { goto label_46; } this.d.removeTestProvider(this.f); goto label_46;} catch(IllegalArgumentException | NullPointerException unused_ex) { goto label_46;}label_46:if(this.d != null) { this.d.addTestProvider(this.f, false, false, false, false, true, false, false, 0, 5); this.d.setTestProviderEnabled(this.f, true);}
In other words, LocationManager
is initialized by the this.
value; then the test "gps"
provider is removed by the removeTestProvider
function; and then I add the provider again using theaddTestProvider
function and enable it with the setTestProviderEnabled(
function. Voila, the test provider has been added and enabled! Now I can create and set new locations using the onEventMainThread
function:
// Create locationlong v1 = System.currentTimeMillis();Location v3 = new Location("");v3.setProvider("gps");v3.setLatitude(arg10.latitude);v3.setLongitude(arg10.longitude);v3.setAltitude(((double)FakeGPSService.p));v3.setBearing(((float)FakeGPSService.q));v3.setTime(v1);v3.setAccuracy(((float)FakeGPSService.o));v3.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());// Set locationtry { this.d.setTestProviderLocation(this.f, v3); Log.d("GpsMockProvider", v3.toString());} catch(IllegalArgumentException unused_ex) {}
Everything seems to be clear, and I start writing my own GPS spoofer.
Coding
Important: my goal wasn’t to produce a ready-to-use app. I just wanted to create a mockup with a minimum set of functions in order to demonstrate the efficiency of the selected method. Accordingly, the fake coordinates will be hardcoded in the GPS provider and set once and forever in the course of its creation.
I launch Android Studio and create a project with an empty activity.

Then I add android.
to the manifest – and Android Studio immediately tells me that this permission is available only for system apps and can be added only to the test manifest. I follow the tips by pressing the [Alt+Shift+Enter] and [Alt-Enter] combinations, and Android Studio does all the job for me. Then I add two buttons to the start activity…
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <Button android:id="@+id/btnDelGPS" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="DelGPS" android:text="Remove GPS provider" /> <Button android:id="@+id/btnAddGPS" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="AddGPS" android:text="Add GPS provider" /></LinearLayout>
…and add the respective code.
public class MainActivity extends Activity { LocationManager mLocationManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize LocationManager mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); } public void AddGPS(View view) { // Add test provider mLocationManager.addTestProvider(LocationManager.GPS_PROVIDER, false, false, false, false, true, true, true, android.location.Criteria.POWER_LOW, android.location.Criteria.ACCURACY_FINE); // Enable test provider mLocationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true); // Set fake location Location newLocation = new Location(LocationManager.GPS_PROVIDER); newLocation.setLatitude(55.75578); newLocation.setLongitude(37.61786); newLocation.setTime(System.currentTimeMillis()); newLocation.setAccuracy(25); newLocation.setElapsedRealtimeNanos(System.nanoTime()); mLocationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, newLocation); } public void DelGPS(View view) { // Remove my test provider mLocationManager.removeTestProvider(LocationManager.GPS_PROVIDER); }}
Finally, I compile and install the program. Then I go to developer options on my phone, select my app as the provider of fake locations, launch it, and press the “Add GPS provider” button.”




Expectedly, nothing happens.
If an app is launched not for the first time, it may crash because a test provider of the same name already exists. In such a situation, you have to relaunch the app, delete the provider using the “Remove GPS provider” button, and then create it again using the “Add GPS provider” button.
I deliberately didn’t include handling of such errors into my program to avoid cluttering up its code. Again, I am writing a mockup, not the final version. However, you are welcome to send pull requests; the link to the project page on GitHub can be found in the end of the article.
Testing
I minimize the app and start testing it. First, I launch Yandex.Maps and get right to the Red Square – exactly as I wanted. Success!


However, when I use Google Maps, I somehow get to Komsomol Square in Uryupinsk. In fact, I know why I ended up there; what I don’t know is why my TestProvider isn’t working properly…
I had searched for the answer to this question for several days, and it turned out to be quite simple: all I had to do was disable the Google geolocation in the phone settings. This function relieves you from the need to specify the GPS provider manually: the phone automatically selects the source of coordinates. It starts with the most accurate sources (i.e. GPS); if satellite positioning is not available, the phone switches to base stations, then to Wi-Fi networks, and then it reportedly uses an accelerometer to determine the location.
I disable Google geolocation and launch Maps.


It’s working, I am on the Red Square again!
So, this method allows to substitute real GPS coordinates with fake ones, but I want to solve the problem fundamentally (i.e. be able to change the location without any additional tricks). Interestingly, the tested app, FakeGPS, operates correctly regardless of the Google geolocation settings. Therefore, I continue my research.
Fixing errors
I examine FakeGPSService
in more detail and notice that it uses some GoogleApiClient
. During the initial analysis, I thought that this client was used for advertisement and ignored it. But now I see that it includes two methods:
LocationServices.FusedLocationApi.setMockMode()LocationServices.FusedLocationApi.setMockLocation()
Apparently, this is what I need. I search Google for documentation, review it, and find out that FusedLocationApi
is considered obsolete, and FusedLocationProviderClient
should be used instead of it.
So, I add the following string to the dependencies
section of the build.
file:
implementation 'com.google.android.gms:play-services-location:17.0.0'
Interestingly, after the addition of this string, the app size increased from 11 KB to more than 1 MB.
I also add two strings in the end of the AddGPS
function:
LocationServices.getFusedLocationProviderClient(this).setMockMode(true);LocationServices.getFusedLocationProviderClient(this).setMockLocation(newLocation);
Then I compile and run the program, and it operates correctly both in Google Maps (with enabled geolocation) and in Yandex.Maps. Victory!

2022.01.12 — First contact. Attacks against contactless cards
Contactless payment cards are very convenient: you just tap the terminal with your card, and a few seconds later, your phone rings indicating that…
Full article →
2022.06.01 — Routing nightmare. How to pentest OSPF and EIGRP dynamic routing protocols
The magic and charm of dynamic routing protocols can be deceptive: admins trust them implicitly and often forget to properly configure security systems embedded in these protocols. In this…
Full article →
2023.04.19 — Kung fu enumeration. Data collection in attacked systems
In penetration testing, there's a world of difference between reconnaissance (recon) and data collection (enum). Recon involves passive actions; while enum, active ones. During recon,…
Full article →
2023.06.08 — Croc-in-the-middle. Using crocodile clips do dump traffic from twisted pair cable
Some people say that eavesdropping is bad. But for many security specialists, traffic sniffing is a profession, not a hobby. For some reason, it's believed…
Full article →
2022.01.11 — Persistence cheatsheet. How to establish persistence on the target host and detect a compromise of your own system
Once you have got a shell on the target host, the first thing you have to do is make your presence in the system 'persistent'. In many real-life situations,…
Full article →
2022.06.03 — Playful Xamarin. Researching and hacking a C# mobile app
Java or Kotlin are not the only languages you can use to create apps for Android. C# programmers can develop mobile apps using the Xamarin open-source…
Full article →
2022.06.01 — F#ck AMSI! How to bypass Antimalware Scan Interface and infect Windows
Is the phrase "This script contains malicious content and has been blocked by your antivirus software" familiar to you? It's generated by Antimalware Scan Interface…
Full article →
2023.07.29 — Invisible device. Penetrating into a local network with an 'undetectable' hacker gadget
Unauthorized access to someone else's device can be gained not only through a USB port, but also via an Ethernet connection - after all, Ethernet sockets…
Full article →
2022.01.11 — Pentest in your own way. How to create a new testing methodology using OSCP and Hack The Box machines
Each aspiring pentester or information security enthusiast wants to advance at some point from reading exciting write-ups to practical tasks. How to do this in the best way…
Full article →
2023.07.07 — Evil Ethernet. BadUSB-ETH attack in detail
If you have a chance to plug a specially crafted device to a USB port of the target computer, you can completely intercept its traffic, collect cookies…
Full article →