Disabilita / Verifica posizione fittizia (previene lo spoofing GPS)


90

Cercando di trovare il modo migliore per prevenire / rilevare lo spoofing GPS su Android. Qualche suggerimento su come farlo e cosa si può fare per fermarlo? Immagino che l'utente debba attivare posizioni fittizie per falsificare il GPS, se ciò viene fatto, possono falsificare il GPS?

Immagino che dovrei rilevare solo se le posizioni fittizie sono abilitate? Qualche altro suggerimento?


2
Penso che stia chiedendo informazioni sulla funzione Spoofing di posizione disponibile nella vista DDMS in Eclipse.
Shawn Walton

2
Ho un gioco basato sulla posizione sul quale non voglio che la gente tradisca, quindi cerco di bloccare lo spoofing, la mia comprensione è che può accadere in due modi ... Avere posizioni fittizie abilitate e costruire un'immagine personalizzata che fa spoofing di basso livello e ignora l'impostazione di spoofing nell'app delle impostazioni. Cercando di trovare Settings.System Provider per MockLocations, o cercando di vedere se viene abilitato (con un listener al centro dell'app).
Chrispix

Risposte:


125

Ho svolto alcune indagini e ho condiviso i miei risultati qui, questo potrebbe essere utile per altri.

Innanzitutto, possiamo verificare se l'opzione MockSetting è attivata

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

In secondo luogo, possiamo verificare se nel dispositivo sono presenti altre app che utilizzano android.permission.ACCESS_MOCK_LOCATION(App di spoofing della posizione)

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

Se entrambi i metodi sopra, primo e secondo sono veri, allora ci sono buone probabilità che la posizione possa essere falsificata o falsificata.

Ora, lo spoofing può essere evitato utilizzando l'API di Location Manager.

Possiamo rimuovere il provider di test prima di richiedere gli aggiornamenti della posizione da entrambi i provider (rete e 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);

Ho visto che removeTestProvider (~) funziona molto bene su Jelly Bean e versioni successive. Questa API sembrava essere inaffidabile fino a Ice Cream Sandwich.


Osservazioni molto interessanti. Soprattutto l'ultimo +1 per aver condiviso questo.
ar-g

2
Nota sul metodo removeTestProvider. Se consenti al Gestore posizione di funzionare in background, l'utente può andare all'app fittizia e riavviare la posizione fittizia. Il tuo gestore della posizione inizierà quindi a ricevere posizioni fittizie finché non chiamerai di nuovo removeTestProvider.
Timur_C

4
Anche la tua app deve avere l' android.permission.ACCESS_MOCK_LOCATIONautorizzazione per removeTestProviderfunzionare, che penso sia il più grande svantaggio.
Timur_C

18
Grazie per la risposta! solo un punto: in Android 6.0 ALLOW_MOCK_LOCATION è deprecato. E in realtà non c'è nemmeno una casella di controllo per la posizione fittizia. È possibile verificare se la posizione è falsa o non corretta dall'oggetto posizione: location.isFromMockProvider ()
Silwester,

2
@Blackkara non l'ho usato dopotutto. Ho usato una combinazione personalizzata di isMockSettingsON(), Location.isFromMockProvider()e areThereMockPermissionApps()con una lista nera di applicazioni. Ci sono molte app di sistema preinstallate con ACCESS_MOCK_LOCATION autorizzazione, ad esempio sui dispositivi HTC e Samsung. Una lista bianca di tutte le app legittime sarebbe migliore, ma una lista nera delle app di spoofing della posizione più popolari ha funzionato bene nel mio caso. E ho anche controllato se il dispositivo era rootato.
Timur_C

45

Dall'API 18, l'oggetto Location ha il metodo .isFromMockProvider () in modo da poter filtrare le posizioni false.

Se vuoi supportare le versioni precedenti alla 18, è possibile usare qualcosa di simile:

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

Sono abbastanza sicuro che la tua seconda espressione sia al contrario (restituisci true quando dovrebbe restituire false). Penso che dovrebbe essere:isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
AjahnCharles

3
Prego. Grazie per aver pubblicato una risposta più moderna! Questa è davvero la risposta corretta a partire da oggi.
AjahnCharles

1
Come possiamo farlo senza l'oggetto "location" per SDK superiore a 18?
Ajit Sharma

35

Sembra che l'unico modo per farlo sia impedire che lo spoofing della posizione prevenga MockLocations. Il lato negativo è che alcuni utenti utilizzano dispositivi GPS Bluetooth per ottenere un segnale migliore, non saranno in grado di utilizzare l'app poiché sono tenuti a utilizzare le posizioni fittizie.

Per fare ciò, ho fatto quanto segue:

// 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
Questo però non è infallibile. Gli utenti su un dispositivo senza root possono ancora impostare una posizione fittizia, con un tempo futuro, quindi disabilitare le posizioni fittizie e la posizione fittizia è ancora attiva. Ancora peggio, possono chiamare la posizione fittizia con lo stesso nome del provider di Rete / Gps e apparentemente ne
deriva

3
Inoltre, Fake GPS non richiede l'impostazione della posizione fittizia sui dispositivi rooted.
Paul Lammertsma

Potrei sempre controllare che l'app fake.gps non sia installata :)
Chrispix

11
Puoi usare return !xinvece di if(x) return false; else return true.
CodesInChaos

In effetti, la posizione falsa cambierà l'impostazione della posizione fittizia anche sui dispositivi rooted.
PageNotFound

25

Sono incappato in questo thread un paio di anni dopo. Nel 2016, la maggior parte dei dispositivi Android avrà un livello API> = 18 e dovrebbe quindi fare affidamento su Location.isFromMockProvider (), come sottolineato da Fernando .

Ho ampiamente sperimentato con posizioni false / fittizie su diversi dispositivi Android e distribuzioni. Sfortunatamente .isFromMockProvider () non è affidabile al 100%. Di tanto in tanto, un luogo falso non verrà etichettato come finto . Ciò sembra essere dovuto a una logica di fusione interna errata nell'API di Google Location.

Ho scritto un post dettagliato sul blog su questo , se vuoi saperne di più. Per riassumere, se ti iscrivi agli aggiornamenti di posizione dall'API di posizione, quindi accendi un'app GPS falsa e stampa il risultato di ogni Location.toString () sulla console, vedrai qualcosa del genere:

inserisci qui la descrizione dell'immagine

Si noti come, nel flusso di aggiornamenti della posizione, una posizione ha le stesse coordinate delle altre, ma non viene contrassegnata come una finta e ha una precisione della posizione molto inferiore.

Per rimediare a questo problema, ho scritto una classe di utilità che sarà posizioni simulate in modo affidabile Sopprimere in tutte le versioni di Android moderni (livello di API 15 in su):

LocationAssistant - Aggiornamenti di posizione senza problemi su Android

Fondamentalmente, "diffida" di posizioni non fittizie che si trovano entro 1 km dall'ultima posizione fittizia nota e le etichetta anche come fittizie. Lo fa fino a quando non arriva un numero significativo di posizioni non fittizie. Il LocationAssistant non può solo respingere posizioni simulate, ma si alleggerisce anche dalla maggior parte dei problemi di configurazione e la sottoscrizione di aggiornamenti di posizione.

Per ricevere solo aggiornamenti reali sulla posizione (cioè sopprimere i mock), usalo come segue:

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()ora verrà richiamato solo con informazioni sulla posizione reale. Ci sono altri metodi di ascolto che devi implementare, ma nel contesto della tua domanda (come prevenire lo spoofing GPS) è fondamentalmente questo.

Ovviamente, con un sistema operativo rooted puoi ancora trovare modi per falsificare le informazioni sulla posizione che sono impossibili da rilevare per le normali app.


Dovresti riassumere brevemente il post del blog collegato (dove isFromMockProvider fallisce).
AjahnCharles

@CodeConfident - grazie per l'osservazione! Non sono sicuro di cosa dovrei aggiungere però. Il secondo paragrafo della mia risposta è il riassunto del post del blog. .isFromMockProvider fallisce sporadicamente e in modo imprevedibile. Nell'articolo descrivo più in dettaglio i passaggi che ho seguito per scoprire e rimediare a questo.
KlaasNotFound

Beh, sono stato costretto a saltare al tuo articolo per capire quale secondo me va contro l'intenzione di SO. Il mio miglior suggerimento sarebbe: (1) inserisci la tua foto che mostra la posizione pericolosa (non contrassegnata come una finta) e (2) prendi nota rapidamente della tua logica per eliminarli (ignora entro 1 km da una finta)
AjahnCharles

Ok, capito. Penso che nel contesto dell'OP, le specifiche del perché .isFromMockProvider () è inaffidabile non siano troppo rilevanti. Ma cercherò di aggiungere i dettagli che hai menzionato per un quadro più ampio. Grazie per il feedback!
KlaasNotFound

1
Cosa succede se l'utente non ha installato il servizio Google Play?
Yuriy Chernyshov

6

Se ti è capitato di conoscere la posizione generale delle torri cellulari, puoi verificare se la torre cellulare corrente corrisponde alla posizione fornita (entro un margine di errore di qualcosa di grande, come 10 o più miglia).

Ad esempio, se la tua app sblocca funzionalità solo se l'utente si trova in una posizione specifica (il tuo negozio, ad esempio), potresti controllare sia i GPS che i ripetitori. Al momento, nessuna app di spoofing GPS falsifica anche le torri cellulari, quindi potresti vedere se qualcuno in tutto il paese sta semplicemente cercando di farsi strada nelle tue funzioni speciali (penso all'app Disney Mobile Magic, per un esempio).

Questo è il modo in cui l'app Llama gestisce la posizione per impostazione predefinita, poiché il controllo degli ID delle torri cellulari consuma molto meno batteria rispetto al GPS. Non è utile per luoghi molto specifici, ma se casa e lavoro sono a diversi chilometri di distanza, può distinguere molto facilmente tra le due posizioni generali.

Naturalmente, ciò richiederebbe all'utente di avere un segnale cellulare. E dovresti conoscere tutti gli ID delle torri cellulari della zona, di tutti i fornitori di rete, o corri il rischio di un falso negativo.


1
Grazie, è una buona idea. Potrei doverlo esaminare. Grazie
Chrispix

3

prova questo codice è molto semplice e utile

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

Questa è una versione molto migliore del metodo isMockLocationEnabled sopra.
setzamora

AppOpsManager.checkOp () genera SecurityException Se l'app è stata configurata per l'arresto anomalo su questa operazione. Come: java.lang.SecurityException: packagename da uid 11151 non è autorizzato a eseguire MOCK_LOCATION. Questo metodo sta per rilevare "se la tua app può simulare posizioni". Ma non "se le località ricevute vengono derise".
Sergio

@Sergio per "se la tua app può simulare le posizioni" intendi se l'app corrente ha il permesso di simulare le posizioni, giusto?
Victor Laerte

@VictorLaerte Ho per ultimo un contesto di un argomento: / Giusto. Ma la domanda era: "come rilevare se una posizione ricevuta viene derisa o proviene da un fornitore fittizio". O come ignorare le posizioni false.
Sergio

2

Questo script funziona per tutte le versioni di Android e lo trovo dopo molte ricerche

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

Puoi aggiungere un controllo aggiuntivo in base alla triangolazione della torre cellulare o alle informazioni sui punti di accesso WiFi utilizzando l' API di geolocalizzazione di Google Maps

Il modo più semplice per ottenere informazioni su 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();

Puoi confrontare i tuoi risultati con il sito

Per ottenere informazioni sui punti di accesso Wifi

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();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.