Wyłącz / Sprawdź pozorowaną lokalizację (zapobiegaj podszywaniu się pod GPS)

90

Szukam najlepszego sposobu zapobiegania fałszowaniu danych GPS na urządzeniach z Androidem / wykrywania takich przypadków. Jakieś sugestie, jak to osiągnąć i co można zrobić, aby temu zapobiec? Zgaduję, że użytkownik musi włączyć pozorowane lokalizacje, aby sfałszować GPS, jeśli tak się stanie, to może sfałszować GPS?

Myślę, że musiałbym po prostu wykryć, czy Mock Locations są włączone? Jakieś inne sugestie?

Chrispix
źródło
2
Myślę, że pyta o funkcję Location Spoofing dostępną w widoku DDMS w Eclipse.
Shawn Walton
2
Mam grę opartą na lokalizacji, w której nie chcę, aby ludzie oszukiwali, więc różdżkę blokuję podszywanie się. Rozumiem, że może się to zdarzyć na dwa sposoby. Włączenie pozorowanych lokalizacji i tworzenie niestandardowego obrazu, który powoduje podszywanie się na niskim poziomie i ignoruje ustawienie fałszowania w aplikacji Ustawienia. Próbuję znaleźć dostawcę Settings.System Provider for MockLocations lub sprawdzam, czy zostanie włączony (z odbiornikiem w środku aplikacji).
Chrispix,

Odpowiedzi:

125

Przeprowadziłem pewne dochodzenie i udostępniłem tutaj swoje wyniki, może to być przydatne dla innych.

Najpierw możemy sprawdzić, czy opcja MockSetting jest włączona

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

Po drugie, możemy sprawdzić, czy na urządzeniu są inne aplikacje, które używają android.permission.ACCESS_MOCK_LOCATION(Aplikacje do fałszowania lokalizacji)

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

Jeśli obie powyższe metody, pierwsza i druga, są prawdziwe, istnieje duże prawdopodobieństwo, że lokalizacja może być sfałszowana lub fałszywa.

Teraz można uniknąć podszywania się za pomocą interfejsu API Location Manager.

Możemy usunąć dostawcę testów przed zażądaniem aktualizacji lokalizacji od obu dostawców (sieć i 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);

Widziałem, że removeTestProvider (~) działa bardzo dobrze w stosunku do Jelly Bean i nowszych wersji. To API wydawało się niewiarygodne aż do Ice Cream Sandwich.

Jambaaz
źródło
Bardzo ciekawe obserwacje. Szczególnie ostatnia +1 za udostępnienie tego.
ar-g
2
Uwaga dotycząca metody removeTestProvider. Jeśli zezwolisz Menedżerowi lokalizacji na pracę w tle, użytkownik może przejść do fałszywej aplikacji i ponownie uruchomić pozorowaną lokalizację. Twój menedżer lokalizacji zacznie wtedy otrzymywać pozorowane lokalizacje, dopóki nie zadzwonisz ponownie do removeTestProvider.
Timur_C
4
Również Twoja aplikacja musi mieć android.permission.ACCESS_MOCK_LOCATIONpozwolenie na removeTestProviderdziałanie, co moim zdaniem jest największą wadą.
Timur_C
18
Dziękuję za odpowiedź! tylko punkt: w Androidzie 6.0 ALLOW_MOCK_LOCATION jest przestarzała. W rzeczywistości nie ma również pola wyboru dla pozorowanej lokalizacji. Można sprawdzić, czy lokalizacja jest fałszywa, czy nie, bezpośrednio z obiektu lokalizacji
Silwester
2
@Blackkara W końcu go nie użyłem. Kiedyś niestandardową kombinację isMockSettingsON(), Location.isFromMockProvider()a areThereMockPermissionApps()czarną listę aplikacji. Istnieje wiele preinstalowanych aplikacji systemowych z ACCESS_MOCK_LOCATION zezwoleniem, na przykład na urządzeniach HTC i Samsung. Biała lista wszystkich legalnych aplikacji byłaby lepsza, ale w moim przypadku dobrze działała czarna lista najpopularniejszych aplikacji do fałszowania lokalizacji. Sprawdziłem też, czy urządzenie jest zrootowane.
Timur_C
45

Od API 18 obiekt Location ma metodę .isFromMockProvider (), dzięki czemu można odfiltrować fałszywe lokalizacje.

Jeśli chcesz wspierać wersje starsze niż 18, możesz użyć czegoś takiego:

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");
}
Fernando
źródło
Jestem prawie pewien, że twoje drugie wyrażenie jest odwrócone (zwróć true, gdy powinno zwrócić false). Myślę, że powinno być:isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
AjahnCharles
3
Nie ma za co. Dziękujemy za przesłanie bardziej nowoczesnej odpowiedzi! Naprawdę jest to poprawna odpowiedź na dziś.
AjahnCharles
1
Jak możemy to zrobić bez obiektu „location” dla SDK powyżej 18?
Ajit Sharma
35

Wygląda na to, że jedynym sposobem na to jest zapobieganie fałszowaniu lokalizacji przed MockLocations. Wadą jest to, że niektórzy użytkownicy używają urządzeń GPS Bluetooth, aby uzyskać lepszy sygnał, nie będą mogli korzystać z aplikacji, ponieważ są zobowiązani do korzystania z pozorowanych lokalizacji.

Aby to zrobić, wykonałem następujące czynności:

// 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;
Chrispix
źródło
4
Nie jest to jednak głupi dowód. Użytkownicy na niezrootowanym urządzeniu mogą nadal ustawić pozorowaną lokalizację w czasie w przyszłości, a następnie wyłączyć pozorowane lokalizacje, a pozorowana lokalizacja jest nadal aktywna. Co gorsza, mogą nazwać pozorowaną lokalizację taką samą nazwą dostawcy jak Sieć / GPS i najwyraźniej z tego wynika ...
Chrispix
3
Co więcej, Fałszywy GPS nie wymaga ustawienia pozorowanej lokalizacji na zrootowanych urządzeniach.
Paul Lammertsma
Zawsze można sprawdzić, czy aplikacja fake.gps nie jest zainstalowana :)
Chrispix
11
Możesz użyć return !xzamiast if(x) return false; else return true.
CodesInChaos
W rzeczywistości fałszywa lokalizacja zmieni ustawienie pozorowanej lokalizacji nawet na zrootowanych urządzeniach.
PageNotFound
25

Natknąłem się na ten wątek kilka lat później. W 2016 r. Większość urządzeń z Androidem będzie miała poziom API> = 18 i dlatego powinno polegać na Location.isFromMockProvider (), jak wskazał Fernando .

Intensywnie eksperymentowałem z fałszywymi / pozorowanymi lokalizacjami na różnych urządzeniach z Androidem i dystrybucjach. Niestety .isFromMockProvider () nie jest w 100% wiarygodne. Od czasu do czasu fałszywa lokalizacja nie będzie oznaczona jako pozorna . Wydaje się, że jest to spowodowane błędną wewnętrzną logiką fuzji w Google Location API.

Napisałem na ten temat szczegółowy post na blogu , jeśli chcesz dowiedzieć się więcej. Podsumowując, jeśli subskrybujesz aktualizacje lokalizacji z interfejsu API lokalizacji, a następnie włączasz fałszywą aplikację GPS i drukujesz wynik każdego Location.toString () na konsoli, zobaczysz coś takiego:

wprowadź opis obrazu tutaj

Zwróć uwagę, że w strumieniu aktualizacji lokalizacji jedna lokalizacja ma te same współrzędne co inne, ale nie jest oznaczona jako pozorna i ma znacznie gorszą dokładność lokalizacji.

Aby rozwiązać ten problem, napisałem klasę narzędzi, która niezawodnie blokuje lokalizacje Mock we wszystkich nowoczesnych wersjach Androida (poziom API 15 i nowsze):

LocationAssistant - Bezproblemowe aktualizacje lokalizacji na Androida

Zasadniczo „nie ufa” niezamierzonym lokalizacjom, które znajdują się w promieniu 1 km od ostatniej znanej pozorowanej lokalizacji, a także określa je jako pozorowane. Robi to, dopóki nie pojawi się znaczna liczba nieudanych lokalizacji. LocationAssistant można nie tylko odrzucić pozorowanie lokalizacji, ale także odciąża cię z większości kłopotów konfigurowania i subskrypcji aktualizacji lokalizacji.

Aby otrzymywać tylko prawdziwe aktualizacje lokalizacji (tj. Pomijać fałszywe informacje), użyj ich w następujący sposób:

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()będą teraz wywoływane tylko z prawdziwymi informacjami o lokalizacji. Jest jeszcze kilka metod nasłuchujących, które musisz wdrożyć, ale w kontekście twojego pytania (jak zapobiegać fałszowaniu GPS) to w zasadzie wszystko.

Oczywiście w przypadku zrootowanego systemu operacyjnego nadal można znaleźć sposoby fałszowania informacji o lokalizacji, których normalne aplikacje nie mogą wykryć.

KlaasNotFound
źródło
Powinieneś krótko podsumować linkowany wpis na blogu (gdzie nie działa isFromMockProvider).
AjahnCharles
@CodeConfident - dzięki za uwagę! Nie jestem pewien, co powinienem dodać. Drugi akapit mojej odpowiedzi to podsumowanie wpisu na blogu. .isFromMockProvider zawiesza się sporadycznie i nieprzewidywalnie. W artykule opisuję bardziej szczegółowo kroki, które podjąłem, aby to odkryć i naprawić.
KlaasNotFound
Cóż, byłem zmuszony przejść do twojego artykułu, aby zrozumieć, który według mnie jest sprzeczny z intencją SO. Moja najlepsza propozycja będzie: (1) włożyć pic, który pokazuje podejrzanie lokalizacja (nie oznaczone jako makiety) i (2) szybko zauważyć logiki dla ich wyeliminowania (ignorowania zasięgu 1km od mock)
AjahnCharles
Ok, rozumiem. Myślę, że w kontekście PO szczegóły, dlaczego .isFromMockProvider () jest niewiarygodne, nie są zbyt istotne. Ale spróbuję dodać szczegóły, o których wspomniałeś, aby uzyskać większy obraz. Dzięki za opinie!
KlaasNotZnaleziono
1
Co się stanie, jeśli użytkownik nie ma zainstalowanej usługi Google Play?
Yuriy Chernyshov
6

Jeśli zdarzyło Ci się znać ogólną lokalizację wież komórkowych, możesz sprawdzić, czy bieżąca wieża komórkowa pasuje do podanej lokalizacji (z marginesem błędu czegoś dużego, na przykład 10 lub więcej mil).

Na przykład, jeśli Twoja aplikacja odblokowuje funkcje tylko wtedy, gdy użytkownik znajduje się w określonej lokalizacji (na przykład w Twoim sklepie), możesz sprawdzić GPS, a także wieże komórkowe. Obecnie żadna aplikacja do fałszowania GPS nie fałszuje również wież komórkowych, więc możesz zobaczyć, czy ktoś w całym kraju po prostu próbuje sfałszować swoje specjalne funkcje (mam na myśli aplikację Disney Mobile Magic, na przykład).

W ten sposób aplikacja Lama domyślnie zarządza lokalizacją, ponieważ sprawdzanie identyfikatorów wież komórkowych jest znacznie mniej energochłonne niż GPS. Nie jest to przydatne w przypadku bardzo konkretnych lokalizacji, ale jeśli dom i praca są oddalone o kilka mil, można bardzo łatwo rozróżnić te dwie główne lokalizacje.

Oczywiście wymagałoby to od użytkownika w ogóle posiadania sygnału komórkowego. I musiałbyś znać wszystkie identyfikatory wież komórkowych w okolicy - u wszystkich dostawców sieci - w przeciwnym razie ryzykowałbyś fałszywie ujemnym.

Stephen Schrauger
źródło
1
Dzięki, to całkiem niezły pomysł. Może będę musiał się temu przyjrzeć. Dzięki
Chrispix
3

wypróbuj ten kod, jest bardzo prosty i przydatny

  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;
    }
Mostafa Pirhayati
źródło
To jest znacznie lepsza wersja metody isMockLocationEnabled powyżej.
setzamora
AppOpsManager.checkOp () zgłasza wyjątek SecurityException, jeśli aplikacja została skonfigurowana do awarii podczas tej operacji. Na przykład: java.lang.SecurityException: nazwa pakietu z UID 11151 nie może wykonać MOCK_LOCATION. Ta metoda wkrótce wykryje, „czy Twoja aplikacja może kpić z lokalizacji”. Ale nie „jeśli otrzymane lokalizacje są wyszydzane”.
Sergio
@Sergio przez „jeśli twoja aplikacja może kpić z lokalizacji”, masz na myśli, że obecna aplikacja ma uprawnienia do wyszydzania lokalizacji, prawda?
Victor Laerte
@VictorLaerte Ostatni kontekst tematu: / Dobrze. Ale pytanie brzmiało: „jak wykryć, czy odebrana lokalizacja jest wyszydzona, czy też pochodzi od pozorowanego dostawcy”. Albo jak ignorować fałszywe lokalizacje.
Sergio
2

Ten skrypt działa dla wszystkich wersji Androida i znajduję go po wielu poszukiwaniach

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
    }
Ali
źródło
1

Możesz dodać dodatkowe sprawdzenie w oparciu o triangulację wieży komórkowej lub informacje o punktach dostępu Wi-Fi za pomocą interfejsu API geolokalizacji Map Google

Najprostszy sposób na uzyskanie informacji o 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();

Możesz porównać swoje wyniki z witryną

Aby uzyskać informacje o punktach dostępu 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();
}
yoAlex5
źródło