Создание приложения для подмены местоположения Андроид

Создание приложения для подмены местоположения Андроид

В Android существует замечательная возможность назначать поставщиком геокоординат любую программу, и вся система будет использовать те широту и долготу, которые она выдаст. В этой статье я покажу, как этим пользоваться и как самому написать программу для спуфинга координат GPS.

Идея родилась у меня в процессе написания статьи «Анализ приложения «Социальной мониторинг» » — именно тогда я обнаружил возможность менять поставщика координат в операционной системе, что открывает для пользователей много интересных возможностей.

С точки зрения юзера все очень просто: нужно лишь установить специальное приложение, затем включить в настройках режим разработчика и выбрать установленное приложение в качестве поставщика фиктивного местоположения. Таких программ великое множество — от простеньких до довольно развесистых, умеющих не только подменять координаты на заданные, но и менять их по расписанию или проигрывать заранее записанные треки, чтобы имитировать движение телефона по какому-то маршруту. В общем, вбивай запрос «Fake GPS» и выбирай по вкусу.

Сразу предупреждаю: надежность этого метода не очень высокая. При желании можно программно отследить наличие на телефоне такой программы-поставщика, и если программа серьезная, то просто так обдурить ее может не получиться.

Я же захотел разобраться, как именно работает этот механизм, и создать собственное приложение для спуфинга. А начал я с того, что посмотрел, как этот алгоритм реализован в одном из бесплатных приложений. Не читать же документацию, верно?

Реверс FakeGPS

В качестве подопытного кролика было взято приложение FakeGPS 5.0.0. Внешне приложение представляет собой карту, на которой можно установить маркер в произвольную точку и с помощью кнопок «Старт» и «Стоп» запускать или останавливать трансляцию координат выбранной точки. (см. также Подмена местоположения на Android)

Вооружившись JEB Decompiler, открываем и смотрим. Первое, что бросается в глаза, — это наличие в манифесте пермишена android.permission.ACCESS_MOCK_LOCATION.

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

В основной активити ничего интересного не обнаружено, обычная инициализация и настройка, но есть сервис с говорящим названием FakeGPSService.

Реверс приложения для подмены местоположения Андроид Реверс FakeGPS

Попытаемся прорваться сквозь дебри обфускации и посмотреть, что в нем есть интересного.

В методе onCreate имеется такой код:

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

Если проще, то инициализируем LocationManager значением this.getSystemService(«location»), затем удаляем тестового провайдера
«gps» функцией removeTestProvider и добавляем заново с помощью функции addTestProvider, не забывая после этого включить его функцией setTestProviderEnabled(«gps», true). Всё, тестовый провайдер добавлен и включен. А далее при изменении пользователем координат создаем и устанавливаем новое местоположение в функции onEventMainThread:

// Создаем
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());

// И устанавливаем
try {
  this.d.setTestProviderLocation(this.f, v3);
  Log.d("GpsMockProvider", v3.toString());
} catch(IllegalArgumentException unused_ex) {
}

Вроде бы все более-менее ясно, можно приступать к написанию своего провайдера фиктивных местоположений.

Еще по теме: Инструменты для взлома и реверсинга приложений Android

Пишем приложение для подмены местоположения Андроид

Сразу скажу, я не ставлю перед собой задачи создать готовое к практическому использованию приложение. Я буду делать макет с минимальным набором функций, который продемонстрирует работоспособность приведенного способа. Так что фиктивные координаты будем задавать жестко в коде и устанавливать их один раз при создании провайдера. Кому интересно, тот уже сам допилит до нужного уровня.

Итак, запускаем Android Studio и создаем проект с пустой активити.

Пишем приложение для подмены местоположения Андроид

Добавляем в манифест android.permission.ACCESS_MOCK_LOCATION, после чего «Студия» начинает ругаться, что это разрешение доступно только системным приложениям, да еще может быть добавлено только в тестовый манифест. Тут можно не заморачиваться, а просто понажимать кнопки Alt+Shift+Enter и Alt-Enter, следуя подсказкам, и «Студия» сама все сделает за нас. Затем добавляем на стартовую активити две кнопки.

<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="Удалить провайдер GPS" />
  <Button
    android:id="@+id/btnAddGPS"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="AddGPS"
    android:text="Добавить провайдер GPS" />     
</LinearLayout>

И добавляем соответствующий код.

public class MainActivity extends Activity {
  LocationManager mLocationManager;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Инициализируем LocationManager
    mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
  }
  public void AddGPS(View view) {
    // Добавляем тестовый провайдер
    mLocationManager.addTestProvider(LocationManager.GPS_PROVIDER, false, false,
      false, false, true, true,
      true, android.location.Criteria.POWER_LOW, android.location.Criteria.ACCURACY_FINE);

    // Включаем тестовый провайдер
    mLocationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);

    // Задаем фиктивную точку
    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) {
    // Удаляем наш тестовый провайдер
    mLocationManager.removeTestProvider(LocationManager.GPS_PROVIDER);
  }
}

Компилируем и устанавливаем. Затем идем в настройки разработчика на телефоне, выбираем наше приложение в качестве поставщика фиктивных местоположений, трясущимися от волнения (как же, мы же только что написали собственный поставщик местоположений!) руками запускаем наше приложение и жмем кнопку «Добавить провайдер GPS».

спуфинг местоположения android

 

спуфинг местоположения андроид

Ничего не происходит. Ничего, собственно, и не должно происходить.

Если приложение запускается не первый раз, то возможно падение из-за того, что тестовый провайдер с таким именем уже создан. Тогда надо повторно запустить приложение и удалить провайдер кнопкой «Удалить провайдер GPS», а затем создать его заново кнопкой «Добавить провайдер GPS».

Я намеренно не стал добавлять обработку таких ошибок, чтобы не засорять код, мы же пишем макет, а не финальную версию. Впрочем, можешь присылать пулл-реквесты, ссылка на GitHub будет в конце статьи.

Тестируем приложение для подмены местоположения Андроид

Сворачиваем приложение и приступаем к тестам. Запускаем «Яндекс Карты» и попадаем точно на Красную площадь, в нулевой километр, как и было задумано. Ура, получилось!

написать приложение для подмены местоположение Андроид

Ну, почти получилось. Если попробовать запустить Google Maps, почему-то мы попадаем на площадь Комсомола в городе Урюпинске. Вернее, понятно, почему попадаем, непонятно, почему не работает наш TestProvider.

Скажу честно, ответ на этот вопрос я искал несколько дней, но все оказалось довольно просто — надо отключить в настройках телефона геолокацию Google. Эта настройка позволяет не заморачиваться с выбором провайдера: телефон сам решает, из какого источника брать координаты. Начинает с самых точных, то есть GPS, затем, если спутниковое позиционирование недоступно, переходит к базовым станциям, затем по сетям Wi-Fi, а затем якобы даже использует акселерометр, чтобы найти себя в пространстве.

Итак, пробуем — отключаем геолокацию Google и запускаем «Карты».

создать программу для подмены местоположение Андроид

Сработало, мы снова на Красной площади.

Итак, этот способ позволяет подменять реальные координаты GPS фиктивными, но хотелось бы решить задачу полностью — подменять местоположение начисто, без всяких скидок. Что интересно, наш подопытный кролик FakeGPS работает корректно независимо от настроек геолокации Google. Что ж, будем ковырять дальше.

Исправление ошибок

Присмотревшись к сервису FakeGPSService чуть более внимательно, я заметил, что там еще используется некий GoogleApiClient. Признаюсь, при первичном анализе я с ходу решил, что он нужен для рекламы, и не стал больше обращать на него внимание. А еще там есть вот эти два метода:

  • LocationServices.FusedLocationApi.setMockMode(),
  • LocationServices.FusedLocationApi.setMockLocation().

Кажется, это то, что нужно. Погуглив документацию (от нее все же не уйти!), выясняем, что FusedLocationApi немножко устарел и вместо него рекомендуется использовать FusedLocationProviderClient.

Что же, попробуем. Добавляем в раздел dependencies файла build.gradle такую строчку:

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

Интересно, что после добавления этой строчки объем приложения вырастает с 11 Кбайт до 1 Мбайта с хвостиком.

В конец функции AddGPS дописываем пару строк.

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

Компилируем и запускаем — теперь нормально работает и в Google Maps с включенной геолокацией, и в «Яндекс Картах». Победа!

ВКонтакте
OK
Telegram
WhatsApp
Viber

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *