Вимкнути / перевірити на фіктивне розташування (запобігти підробці GPS)


90

Шукаємо найкращий спосіб запобігти / виявити підробку GPS на Android. Будь-які пропозиції щодо того, як це робиться, і що можна зробити, щоб це зупинити? Я здогадуюсь, що користувач повинен увімкнути фіктивні місця для підробки GPS, якщо це зроблено, то він може підробити GPS?

Думаю, мені потрібно було б просто виявити, чи ввімкнені фіктивні локації? Будь-які інші пропозиції?


2
Я думаю, він запитує про функцію спуфінгу місцезнаходження, доступну у поданні DDMS у Eclipse.
Шон Уолтон,

2
У мене є гра, яка базується на розташуванні, і я не хочу, щоб люди обманювали, тому я палицею заблокував підробку, я розумію, це може статися одним із двох способів .. Якщо ввімкнути фіктивні локації та створити власне зображення, яке робить підробку на низькому рівні та ігнорує налаштування підробки в програмі налаштувань. Спроба знайти Налаштування. Системний провайдер для MockLocations, або перевірити, чи він увімкнений (зі слухачем посередині програми).
Chrispix

Відповіді:


125

Я провів деяке дослідження та поділився своїми результатами тут, це може бути корисно для інших.

Спочатку ми можемо перевірити, чи ввімкнено опцію MockSetting

public static boolean isMockSettingsON(Context context) {
    // returns true if mock location enabled, false if not enabled.
    if (Settings.Secure.getString(context.getContentResolver(),
                                Settings.Secure.ALLOW_MOCK_LOCATION).equals("0"))
        return false;
    else
        return true;
}

По-друге, ми можемо перевірити, чи є на пристрої інші програми, які використовують android.permission.ACCESS_MOCK_LOCATION(Програми підміни місця)

public static boolean areThereMockPermissionApps(Context context) {
    int count = 0;

    PackageManager pm = context.getPackageManager();
    List<ApplicationInfo> packages =
        pm.getInstalledApplications(PackageManager.GET_META_DATA);

    for (ApplicationInfo applicationInfo : packages) {
        try {
            PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName,
                                                        PackageManager.GET_PERMISSIONS);

            // Get Permissions
            String[] requestedPermissions = packageInfo.requestedPermissions;

            if (requestedPermissions != null) {
                for (int i = 0; i < requestedPermissions.length; i++) {
                    if (requestedPermissions[i]
                        .equals("android.permission.ACCESS_MOCK_LOCATION")
                        && !applicationInfo.packageName.equals(context.getPackageName())) {
                        count++;
                    }
                }
            }
        } catch (NameNotFoundException e) {
            Log.e("Got exception " , e.getMessage());
        }
    }

    if (count > 0)
        return true;
    return false;
}

Якщо обидва вищезазначені методи, перший і другий, відповідають дійсності, тоді є велика ймовірність того, що місцеположення може бути підробленим або підробленим.

Тепер підробки можна уникнути, використовуючи API менеджера місцезнаходжень.

Ми можемо видалити тестового постачальника, перш ніж запитувати оновлення місцезнаходження від обох постачальників (мережа та GPS)

LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);

try {
    Log.d(TAG ,"Removing Test providers")
    lm.removeTestProvider(LocationManager.GPS_PROVIDER);
} catch (IllegalArgumentException error) {
    Log.d(TAG,"Got exception in removing test  provider");
}

lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener);

Я бачив, що removeTestProvider (~) дуже добре працює над Jelly Bean та наступними версіями. Цей API виявився ненадійним до морозива.


Дуже цікаві спостереження. Особливо останній +1 за те, що поділився цим.
ar-g

2
Зверніть увагу на метод removeTestProvider. Якщо ви дозволите диспетчеру місцезнаходжень працювати у фоновому режимі, користувач може перейти до знущання програми та перезапустити насмішку. Потім ваш менеджер місцеположень почне отримувати фіктивні місця, поки ви знову не зателефонуєте removeTestProvider.
Timur_C

4
Також ваш додаток повинен мати android.permission.ACCESS_MOCK_LOCATIONдозвіл removeTestProviderна роботу, що, на мою думку, є найбільшим недоліком.
Timur_C

18
дякую за відповідь! просто точка: в Android 6.0 ALLOW_MOCK_LOCATION застаріло. І насправді також немає прапорця для фіктивного розташування. Можна перевірити, чи місцеположення є фальшивим чи не від об’єкта розташування
Silwester

2
@Blackkara Я врешті не використовував його. Я використовував індивідуальні комбінації isMockSettingsON(), Location.isFromMockProvider()і areThereMockPermissionApps()з чорним списком додатків. Є багато попередньо встановлених системних програм з ACCESS_MOCK_LOCATION дозволом, наприклад на пристроях HTC та Samsung. Білий список усіх законних додатків був би кращим, але чорний список найпопулярніших програм підміни розташування в моєму випадку добре працював. І я також перевірив, чи пристрій укорінено.
Timur_C

45

Починаючи з API 18, об'єкт Location має метод .isFromMockProvider (), щоб ви могли відфільтрувати фальшиві місця.

Якщо ви хочете підтримувати версії до 18 років, можна скористатися приблизно таким чином:

boolean isMock = false;
if (android.os.Build.VERSION.SDK_INT >= 18) {
    isMock = location.isFromMockProvider();
} else {
    isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
}

Я впевнений, що ваш другий вираз є зворотним (поверніть true, коли має повернути false). Я думаю, це повинно бути:isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
AjahnCharles

3
Ласкаво просимо. Дякуємо за розміщення більш сучасної відповіді! Дійсно, це правильна відповідь на сьогодні.
AjahnCharles

1
Як ми можемо це зробити без об'єкта "location" для SDK вище 18?
Аджит Шарма

35

Здається, єдиний спосіб зробити це - запобігти підробці місцеположення, запобігаючи MockLocations. З іншого боку, є деякі користувачі, які використовують Bluetooth-пристрої GPS для отримання кращого сигналу; вони не зможуть користуватися програмою, оскільки їм потрібно використовувати фіктивні місця.

Для цього я зробив наступне:

// returns true if mock location enabled, false if not enabled.
if (Settings.Secure.getString(getContentResolver(),
       Settings.Secure.ALLOW_MOCK_LOCATION).equals("0")) 
       return false; 
       else return true;

4
Це не дурний доказ. Користувачі на некоренованому пристрої все ще можуть встановити фіктивне розташування, без будь-якого часу в майбутньому, а потім відключити фіктивне розташування, а фіктивне місце все ще активне. Навіть гірше, вони можуть називати фіктивне місце тим самим іменем провайдера, що і мережа / GPS, і це, мабуть, витягує з цього ..
Chrispix

3
Крім того, підроблений GPS не вимагає встановлення фіктивного розташування на корінних пристроях.
Пол Ламмертсма,

Завжди міг перевірити, чи не встановлено додаток fake.gps :)
Chrispix,

11
Ви можете використовувати return !xзамість if(x) return false; else return true.
CodesInChaos

Насправді підроблене розташування змінить налаштування фіктивного розташування навіть на корінних пристроях.
PageNotFound

25

Натрапив на цю нитку через пару років. У 2016 році більшість пристроїв Android матимуть рівень API> = 18 і, отже, повинні покладатися на Location.isFromMockProvider (), як зазначив Фернандо .

Я багато експериментував з фальшивими / макетними локаціями на різних пристроях Android та дистрибутивах. На жаль, .isFromMockProvider () не є 100% надійним. Час від часу фальшиве місце не буде позначено як знущання . Здається, це пов’язано з деякою помилковою внутрішньою логікою синтезу в Google Location API.

Про це я написав докладний допис у блозі , якщо ви хочете дізнатись більше. Підводячи підсумок, якщо ви підписалися на оновлення місцезнаходжень з API розташування, а потім увімкнули підроблену програму GPS і надрукували результат кожного Location.toString () на консолі, ви побачите щось подібне:

введіть тут опис зображення

Зверніть увагу, що в потоці оновлень місцезнаходжень одне місцезнаходження має ті самі координати, що й інші, але не позначене як макет і має набагато гіршу точність розташування.

Щоб усунути цю проблему, я написав допоміжний клас , який буде надійно придушувати Mock місця у всіх сучасних версіях Android (рівень API 15 і вище):

LocationAssistant - Безпроблемні оновлення місцезнаходження на Android

По суті, він "не довіряє" непромисловим локаціям, що знаходяться в радіусі 1 км від останнього відомого макетного місця, а також позначає їх як макет. Він робить це, поки не прибуде значна кількість непромислових місць. LocationAssistant може не тільки відмовитися від фіктивних місць розташування, а й розвантажує вас від більшості клопоту настройки і підписок на оновлення розташування.

Щоб отримувати лише реальні оновлення місцезнаходження (тобто придушувати макети), використовуйте їх наступним чином:

public class MyActivity extends Activity implements LocationAssistant.Listener {

    private LocationAssistant assistant;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // You can specify a different accuracy and interval here.
        // The last parameter (allowMockLocations) must be 'false' to suppress mock locations.  
        assistant = new LocationAssistant(this, this, LocationAssistant.Accuracy.HIGH, 5000, false);
    }

    @Override
    protected void onResume() {
        super.onResume();
        assistant.start();
    }

    @Override
    protected void onPause() {
        assistant.stop();
        super.onPause();
    }

    @Override
    public void onNewLocationAvailable(Location location) {
        // No mock locations arriving here
    }

    ...
}

onNewLocationAvailable()тепер буде викликано лише реальну інформацію про місцезнаходження. Існує ще кілька методів прослуховування, які потрібно застосувати, але в контексті вашого запитання (як запобігти спуфінгу GPS) це в основному це.

Звичайно, з корінною ОС ви все ще можете знайти способи підробки інформації про місцезнаходження, які неможливо виявити звичайним програмам.


Вам слід коротко підсумувати пов’язану публікацію в блозі (де не вдаєтьсяFromMockProvider).
AjahnCharles

@CodeConfident - дякую за зауваження! Не знаю, що я повинен додати. Другий абзац моєї відповіді - це резюме допису в блозі. .isFromMockProvider виходить з ладу епізодично і непередбачувано. У статті я просто детальніше описую кроки, які я зробив, щоб виявити та виправити це.
KlaasNotЗнайдено

Ну, я був змушений перейти до вашої статті, щоб зрозуміти, яка, на мою думку, суперечить наміру SO. Найкращою моєю пропозицією було б: (1) вставити свій знімок, який показує прихильне місце (не позначене як макет) і (2) швидко зауважити свою логіку щодо їх усунення (ігнорувати в межах 1 км від макету)
AjahnCharles

Гаразд, зрозуміло. Я думаю, що в контексті OP специфіка, чому .isFromMockProvider () ненадійний, не надто актуальна. Але я спробую додати деталі, про які ви згадали, для загального зображення. Дякуємо за відгук!
KlaasNotЗнайдено

1
Що робити, якщо у користувача не встановлено Службу Google Play?
Юрій Чернишов

6

Якщо ви випадково знали загальне розташування стільникових веж, ви можете перевірити, чи відповідає поточна башта стільницеві вказаному розташуванню (в межах похибки чогось великого, наприклад, 10 або більше миль).

Наприклад, якщо ваш додаток розблоковує функції, лише якщо користувач знаходиться у певному місці (наприклад, у вашому магазині), ви можете перевірити GPS, а також стільникові вишки. В даний час жоден додаток для спуфінгу gps також не підробляє стільникові вишки, тому ви могли побачити, чи хтось по всій країні просто намагається підробити ваші спеціальні функції (я, наприклад, думаю про додаток Disney Mobile Magic).

Ось як додаток Llama за замовчуванням керує місцезнаходженням, оскільки перевірка ідентифікаторів стільникових башт набагато менш інтенсивна, ніж gps. Це не корисно для дуже конкретних місць, але якщо дім та робота знаходяться в декількох милях від них, він може дуже легко розрізнити два загальних місця.

Звичайно, для цього потрібно, щоб користувач взагалі мав сигнал стільникового зв’язку. І вам доведеться знати всі ідентифікатори стільникових веж у цьому районі - про всіх провайдерів мережі - або ви ризикуєте отримати помилково негативний результат.


1
Дякую, це досить гарна ідея. Можливо, мені доведеться це вивчити. Дякую
Chrispix

3

спробуйте цей код дуже простий і корисний

  public boolean isMockLocationEnabled() {
        boolean isMockLocation = false;
        try {
            //if marshmallow
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                AppOpsManager opsManager = (AppOpsManager) getApplicationContext().getSystemService(Context.APP_OPS_SERVICE);
                isMockLocation = (opsManager.checkOp(AppOpsManager.OPSTR_MOCK_LOCATION, android.os.Process.myUid(), BuildConfig.APPLICATION_ID)== AppOpsManager.MODE_ALLOWED);
            } else {
                // in marshmallow this will always return true
                isMockLocation = !android.provider.Settings.Secure.getString(getApplicationContext().getContentResolver(), "mock_location").equals("0");
            }
        } catch (Exception e) {
            return isMockLocation;
        }
        return isMockLocation;
    }

Це набагато краща версія методу isMockLocationEnabled вище.
setzamora

AppOpsManager.checkOp () викидає SecurityException Якщо програму було налаштовано на збій у цій операції. Як: java.lang.SecurityException: ім'я пакета з ідентифікатора uid 11151 заборонено виконувати MOCK_LOCATION. Цей метод збирається виявити, "якщо ваш додаток може знущатися над місцезнаходженнями". Але не "якщо над отриманими адресами знущаються".
Серхіо

@Sergio під "якщо ваш додаток може знущатися над місцезнаходженнями", ви маєте на увазі, якщо поточний додаток має дозвіл на знущання над місцезнаходженнями, так?
Віктор Лаерте

@VictorLaerte Останній контекст теми: / Правильно. Але питання було: "як виявити, якщо отримане місце знущається чи надходить від макетного провайдера". Або як ігнорувати фальшиві місця.
Серхіо

2

Цей сценарій працює для всіх версій Android, і я знаходжу його після багатьох пошуків

LocationManager locMan;
    String[] mockProviders = {LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER};

    try {
        locMan = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        for (String p : mockProviders) {
            if (p.contentEquals(LocationManager.GPS_PROVIDER))
                locMan.addTestProvider(p, false, false, false, false, true, true, true, 1,
                        android.hardware.SensorManager.SENSOR_STATUS_ACCURACY_HIGH);
            else
                locMan.addTestProvider(p, false, false, false, false, true, true, true, 1,
                        android.hardware.SensorManager.SENSOR_STATUS_ACCURACY_LOW);

            locMan.setTestProviderEnabled(p, true);
            locMan.setTestProviderStatus(p, android.location.LocationProvider.AVAILABLE, Bundle.EMPTY,
                    java.lang.System.currentTimeMillis());
        }
    } catch (Exception ignored) {
        // here you should show dialog which is mean the mock location is not enable
    }

1

Ви можете додати додаткову перевірку на основі тріангуляції стільникової вежі або інформації про точки доступу Wi-Fi за допомогою API геолокації Google Maps

Найпростіший спосіб отримати інформацію про CellTowers

final TelephonyManager telephonyManager = (TelephonyManager) appContext.getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = telephonyManager.getNetworkOperator();
int mcc = Integer.parseInt(networkOperator.substring(0, 3));
int mnc = Integer.parseInt(networkOperator.substring(3));
String operatorName = telephonyManager.getNetworkOperatorName();
final GsmCellLocation cellLocation = (GsmCellLocation) telephonyManager.getCellLocation();
int cid = cellLocation.getCid();
int lac = cellLocation.getLac();

Ви можете порівняти свої результати з веб-сайтом

Щоб отримати інформацію про точки доступу Wi-Fi

final WifiManager mWifiManager = (WifiManager) appContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);

if (mWifiManager != null && mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {

    // register WiFi scan results receiver
    IntentFilter filter = new IntentFilter();
    filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                List<ScanResult> results = mWifiManager.getScanResults();//<-result list
            }
        };

        appContext.registerReceiver(broadcastReceiver, filter);

        // start WiFi Scan
        mWifiManager.startScan();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.