Fictitious address. How to change geolocation on Android to spoof applications.

Tomcat

Professional
Messages
2,656
Reputation
10
Reaction score
647
Points
113
949c84ca01c2a9d9ed53a.png


In Android, there is a wonderful opportunity to assign any program by the provider of geocoordinates, and the whole system will use the latitude and longitude that it gives. In this article I will show you how to use it and how to write a program for spoofing GPS coordinates yourself.
The idea came to me in the process of writing the article “We monitor monitoring. What's inside the application for isolation at home”- that's when I discovered the ability to change the coordinate provider in the operating system, which opens up many interesting possibilities for users.
From the user's point of view, everything is very simple: you just need to install a special application, then enable developer mode in the settings and select the installed application as the provider of the fictitious location. There are a great variety of such programs - from simple to quite spreading, which can not only replace coordinates with the given ones, but also change them according to a schedule or play pre-recorded tracks in order to imitate the movement of the phone along a certain route. In general, drive in the request "Fake GPS" and choose according to your taste.

I warn you right away: the reliability of this method is not very high. If you wish, you can programmatically track the presence of such a supplier program on your phone, and if the program is serious, then you may not be able to fool it just like that.
I wanted to figure out exactly how this mechanism works and create my own spoofing application. And I started by looking at how this algorithm is implemented in one of the free applications. Don't read the documentation, right?

Reverse FakeGPS​

The FakeGPS 5.0.0 application was taken as a guinea pig. Externally, the application is a map on which you can set a marker to an arbitrary point and, using the "Start" and "Stop" buttons, start or stop the translation of the coordinates of the selected point.
Armed with the JEB Decompiler, open up and watch. The first thing that catches your eye is the presence of a permit in the manifesto android.permission.ACCESS_MOCK_LOCATION.

Code:
<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" />

In the main activity, nothing interesting was found, the usual initialization and configuration, but there is a service with a self-explanatory name FakeGPSService.
01.jpg


Let's try to break through the jungle of obfuscation and see what is interesting in it.
The method onCreate contains the following code:

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);
}

If it is simpler, then we initialize with a LocationManager value this.getSystemService("location"), then we remove the test provider "gps" with the function removeTestProvider and add it again using the function addTestProvider, not forgetting to enable it with the function after that setTestProviderEnabled("gps", true). That's it, the test provider has been added and enabled. And then, when the user changes the coordinates, we create and set a new location in the function onEventMainThread:

Code:
// Create
long 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 ());

// And install
try {
   this.d.setTestProviderLocation (this.f, v3);
   Log.d ("GpsMockProvider", v3.toString ());
} catch (IllegalArgumentException unused_ex) {
}

It seems that everything is more or less clear, you can start writing your own provider of fictitious locations

Writing the code​

I must say right away that I do not set myself the task of creating a ready-to-use application. I will make a mockup with a minimal set of functions that will demonstrate the efficiency of the given method. So we will hardcode fictitious coordinates and set them once when creating a provider. Who cares, he himself will finish to the required level.
So, launch Android Studio and create a project with an empty activity.
02.jpg


We add it to the manifest android.permission.ACCESS_MOCK_LOCATION, after which the Studio begins to swear that this permission is available only to system applications, and it can only be added to the test manifest. Here you don't have to bother, but simply press the Alt + Shift + Enter and Alt-Enter buttons, following the prompts, and Studio will do everything for us. Then we add two buttons to the start activity.

Code:
<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 appropriate code.

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 a test provider
    mLocationManager.addTestProvider (LocationManager.GPS_PROVIDER, false, false,
      false, false, true, true,
      true, android.location.Criteria.POWER_LOW, android.location.Criteria.ACCURACY_FINE);

    // Turn on the test provider
    mLocationManager.setTestProviderEnabled (LocationManager.GPS_PROVIDER, true);

    // Set a dummy point
    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 our test provider
    mLocationManager.removeTestProvider (LocationManager.GPS_PROVIDER);
  }
}

We compile and install. Then we go to the developer settings on the phone, select our application as a provider of fictitious locations, shaking with excitement (why, we just wrote our own location provider!), Launch our application with our hands and press the "Add GPS Provider "button.
Nothing happens. Actually, nothing should happen.
If the application is launched not for the first time, then it may crash due to the fact that a test provider with the same name has already been created. Then you need to re-launch the application and delete the provider with the "Remove GPS Provider" button, and then re-create it with the "Add GPS Provider" button.
I deliberately did not add handling of such errors so as not to clutter up the code, we are writing the layout, not the final version. However, you can send pull requests, a link to GitHub will be at the end of the article

Testing​

We minimize the application and proceed to the tests. We launch Yandex Maps and find ourselves exactly on Red Square, at zero kilometer, as planned. Hooray, it worked!
Well, it almost worked out. If we try to launch Google Maps, for some reason we find ourselves on the Komsomol square in the city of Uryupinsk. Rather, it is clear why we get there, it is not clear why our TestProvider does not work.
To be honest, I was looking for the answer to this question for several days, but everything turned out to be quite simple - you need to turn off Google geolocation in the phone settings. This setting allows you not to bother with the choice of the provider: the phone itself decides from which source to take coordinates. It starts with the most accurate ones, that is, GPS, then, if satellite positioning is not available, goes to base stations, then over Wi-Fi networks, and then supposedly even uses an accelerometer to find itself in space.
So, let's try - turn off Google geolocation and launch Maps.
It worked, we are back on Red Square.
So, this method allows you to replace real GPS coordinates with fictitious ones, but I would like to solve the problem completely - replace the location completely, without any discounts. Interestingly, our guinea pig FakeGPS works correctly regardless of Google geolocation settings. Well, let's dig further.

Correcting errors​

Looking at the service a FakeGPSService little more closely, I noticed that a certain one is still used there GoogleApiClient. I confess that during the initial analysis, I immediately decided that it was needed for advertising, and did not pay attention to it anymore. And there are also these two methods:

Code:
LocationServices.FusedLocationApi.setMockMode()
LocationServices.FusedLocationApi.setMockLocation()

It seems that this is what you need. Googling the documentation (you still can't get away from it!), We find out that it is a FusedLocationApi little outdated and it is recommended to use it instead FusedLocationProviderClient.
Well, let's try. Add the following line to the dependencies section of the build.gradle file:

Code:
implementation 'com.google.android.gms: play-services-location: 17.0.0'

Interestingly, after adding this line, the size of the application grows from 11 KB to 1 MB with a tail.
Add a AddGPS couple of lines to the end of the function.

Code:
LocationServices.getFusedLocationProviderClient(this).setMockMode(true);
LocationServices.getFusedLocationProviderClient(this).setMockLocation(newLocation);

Compile and run - now it works fine in Google Maps with geolocation enabled, and in Yandex Maps. Victory!
 
Top