
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.06.01 — First contact. Attacks on chip-based cards
Virtually all modern bank cards are equipped with a special chip that stores data required to make payments. This article discusses fraud techniques used…
Full article →
2023.06.08 — Cold boot attack. Dumping RAM with a USB flash drive
Even if you take efforts to protect the safety of your data, don't attach sheets with passwords to the monitor, encrypt your hard drive, and always lock your…
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 →
2022.02.15 — EVE-NG: Building a cyberpolygon for hacking experiments
Virtualization tools are required in many situations: testing of security utilities, personnel training in attack scenarios or network infrastructure protection, etc. Some admins reinvent the wheel by…
Full article →
2023.02.13 — Ethernet Abyss. Network pentesting at the data link layer
When you attack a network at the data link layer, you can 'leapfrog' over all protection mechanisms set at higher levels. This article will walk…
Full article →
2022.12.15 — What Challenges To Overcome with the Help of Automated e2e Testing?
This is an external third-party advertising publication. Every good developer will tell you that software development is a complex task. It's a tricky process requiring…
Full article →
2023.03.03 — Infiltration and exfiltration. Data transmission techniques used in pentesting
Imagine a situation: you managed to penetrate the network perimeter and gained access to a server. This server is part of the company's internal network, and, in theory, you could…
Full article →
2022.06.01 — Log4HELL! Everything you must know about Log4Shell
Up until recently, just a few people (aside from specialists) were aware of the Log4j logging utility. However, a vulnerability found in this library attracted to it…
Full article →
2023.02.13 — First Contact: Attacks on Google Pay, Samsung Pay, and Apple Pay
Electronic wallets, such as Google Pay, Samsung Pay, and Apple Pay, are considered the most advanced and secure payment tools. However, these systems are also…
Full article →
2022.06.01 — Cybercrime story. Analyzing Plaso timelines with Timesketch
When you investigate an incident, it's critical to establish the exact time of the attack and method used to compromise the system. This enables you to track the entire chain of operations…
Full article →