Desactivar / verificar ubicación simulada (evitar la suplantación de GPS)

90

Buscando encontrar la mejor manera de prevenir / detectar la suplantación de GPS en Android. ¿Alguna sugerencia sobre cómo se logra esto y qué se puede hacer para detenerlo? Supongo que el usuario tiene que activar las ubicaciones simuladas para falsificar el GPS, si esto se hace, ¿pueden falsificar el GPS?

Supongo que tendría que detectar si las ubicaciones simuladas están habilitadas. ¿Cualquier otra sugerencia?

Chrispix
fuente
2
Creo que está preguntando sobre la función de suplantación de ubicación disponible en la vista DDMS en Eclipse.
Shawn Walton
2
Tengo un juego basado en la ubicación en el que no quiero que la gente engañe, por lo que utilizo la varita para bloquear la suplantación de identidad, tengo entendido que puede suceder de dos maneras ... Tener ubicaciones simuladas habilitadas y crear una imagen personalizada que haga suplantación de bajo nivel e ignora la configuración de suplantación de identidad en la aplicación de configuración. Intentando encontrar el Proveedor de sistema de configuración para MockLocations, o buscando si se habilita (con un oyente en el medio de la aplicación).
Chrispix

Respuestas:

125

He hecho algunas investigaciones y comparto mis resultados aquí, esto puede ser útil para otros.

Primero, podemos verificar si la opción MockSetting está encendida

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

En segundo lugar, podemos verificar si hay otras aplicaciones en el dispositivo que estén usando android.permission.ACCESS_MOCK_LOCATION(Aplicaciones de suplantación de ubicación)

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

Si los dos métodos anteriores, el primero y el segundo, son verdaderos, entonces hay buenas posibilidades de que la ubicación sea falsa o falsa.

Ahora, la suplantación de identidad se puede evitar utilizando la API de Location Manager.

Podemos eliminar el proveedor de prueba antes de solicitar las actualizaciones de ubicación de ambos proveedores (Red y 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);

He visto que removeTestProvider (~) funciona muy bien sobre Jelly Bean y versiones posteriores. Esta API parecía no ser confiable hasta Ice Cream Sandwich.

Jambaaz
fuente
Observaciones muy interesantes. Especialmente el último +1 por compartir esto.
ar-g
2
Nota sobre el método removeTestProvider. Si permite que el Administrador de ubicaciones funcione en segundo plano, el usuario puede ir a la aplicación simulada y reiniciar la ubicación simulada. Su administrador de ubicación comenzará a recibir ubicaciones simuladas hasta que llame a removeTestProvider nuevamente.
Timur_C
4
Además, su aplicación debe tener android.permission.ACCESS_MOCK_LOCATIONpermiso para removeTestProviderfuncionar, lo que creo que es la mayor desventaja.
Timur_C
18
¡gracias por la respuesta! solo un punto: en Android 6.0 ALLOW_MOCK_LOCATION está obsoleto. Y en realidad tampoco hay una casilla de verificación para la ubicación simulada. Se puede verificar si la ubicación es falsa o no correcta desde el objeto de ubicación
Silwester
2
@Blackkara No lo usé después de todo. He utilizado una combinación personalizada de isMockSettingsON(), Location.isFromMockProvider()y areThereMockPermissionApps()con una lista de negro de aplicaciones. Hay muchas aplicaciones de sistema preinstaladas con ACCESS_MOCK_LOCATION permiso, por ejemplo, en dispositivos HTC y Samsung. Sería mejor una lista blanca de todas las aplicaciones legítimas, pero una lista negra de las aplicaciones de suplantación de ubicación más populares funcionó bien en mi caso. Y también verifiqué si el dispositivo estaba rooteado.
Timur_C
45

Desde API 18, el objeto Location tiene el método .isFromMockProvider () para que pueda filtrar ubicaciones falsas.

Si desea admitir versiones anteriores a la 18, es posible usar algo como esto:

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
fuente
Estoy bastante seguro de que su segunda expresión está al revés (devuelva verdadero cuando debería devolver falso). Creo que debería ser:isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
AjahnCharles
3
De nada. ¡Gracias por publicar una respuesta más moderna! Realmente esta es la respuesta correcta a día de hoy.
AjahnCharles
1
¿Cómo podemos hacerlo sin el objeto "ubicación" para SDK por encima de 18?
Ajit Sharma
35

Parece que la única forma de hacer esto es evitar que la suplantación de ubicación evite MockLocations. El lado negativo es que hay algunos usuarios que usan dispositivos GPS Bluetooth para obtener una mejor señal, no podrán usar la aplicación ya que están obligados a usar las ubicaciones simuladas.

Para hacer esto, hice lo siguiente:

// 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
fuente
4
Sin embargo, esto no es infalible. Los usuarios de un dispositivo no rooteado aún pueden establecer una ubicación simulada, con un tiempo en el futuro, luego deshabilitar las ubicaciones simuladas, y la ubicación simulada seguirá activa. Peor aún, pueden llamar a la ubicación simulada con el mismo nombre de proveedor que Network / Gps y aparentemente se extrae de eso ..
Chrispix
3
Además, Fake GPS no requiere la configuración de ubicación simulada en dispositivos rooteados.
Paul Lammertsma
Siempre se puede verificar que la aplicación fake.gps no esté instalada :)
Chrispix
11
Puede usar en return !xlugar de if(x) return false; else return true.
CodesInChaos
De hecho, la ubicación falsa cambiará la configuración de la ubicación simulada incluso en dispositivos rooteados.
PageNotFound
25

Me encontré con este hilo un par de años después. En 2016, la mayoría de los dispositivos Android tendrán un nivel de API> = 18 y, por lo tanto, deberían confiar en Location.isFromMockProvider () como lo señaló Fernando .

Experimenté extensamente con ubicaciones falsas / simuladas en diferentes dispositivos y distribuciones de Android. Desafortunadamente .isFromMockProvider () no es 100% confiable. De vez en cuando, una ubicación falsa no se etiquetará como simulada . Esto parece deberse a una lógica de fusión interna errónea en la API de ubicación de Google.

Escribí una publicación de blog detallada sobre esto , si desea obtener más información. En resumen, si se suscribe a las actualizaciones de ubicación desde la API de ubicación, luego enciende una aplicación GPS falsa e imprime el resultado de cada Location.toString () en la consola, verá algo como esto:

ingrese la descripción de la imagen aquí

Observe cómo, en el flujo de actualizaciones de ubicación, una ubicación tiene las mismas coordenadas que las demás, pero no está marcada como una simulación y tiene una precisión de ubicación mucho más pobre.

Para remediar este problema, escribí una clase de utilidad que se ubicaciones de prueba fiable a suprimir en todas las versiones de Android modernos (API nivel 15 en adelante):

LocationAssistant: actualizaciones de ubicación sin complicaciones en Android

Básicamente, "desconfía" de las ubicaciones no simuladas que se encuentran dentro de 1 km de la última ubicación simulada conocida y también las etiqueta como simuladas. Lo hace hasta que haya llegado un número significativo de ubicaciones no simuladas. El LocationAssistant no sólo puede rechazar ubicaciones de prueba, sino que también se desahoga de la mayor parte de la molestia de crear y suscribirse a las actualizaciones de ubicación.

Para recibir solo actualizaciones de ubicación reales (es decir, suprimir simulacros), utilícelo de la siguiente manera:

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()ahora solo se invocará con información de ubicación real. Hay algunos métodos más de escucha que necesita implementar, pero en el contexto de su pregunta (cómo evitar la suplantación de GPS), básicamente es así.

Por supuesto, con un sistema operativo rooteado, aún puede encontrar formas de falsificar información de ubicación que son imposibles de detectar para las aplicaciones normales.

KlaasNotFound
fuente
Debe resumir brevemente la publicación del blog vinculada (donde falla isFromMockProvider).
AjahnCharles
@CodeConfident - ¡gracias por el comentario! Sin embargo, no estoy seguro de qué debo agregar. El segundo párrafo de mi respuesta es el resumen de la publicación del blog. .isFromMockProvider falla esporádicamente e impredeciblemente. En el artículo solo describo con más detalle los pasos que tomé para descubrir y remediar esto.
KlaasNotFound
Bueno, me vi obligado a saltar a su artículo para entender cuál, en mi opinión, va en contra de la intención de SO. Mi mejor sugerencia sería: (1) inserte su foto que muestra la ubicación poco fiable (no marcada como una simulación) y (2) anote rápidamente su lógica para eliminarlos (ignore dentro de 1 km de una simulación)
AjahnCharles
Ok, te entiendo. Creo que en el contexto del OP, los detalles de por qué .isFromMockProvider () no es confiable no son demasiado relevantes. Pero intentaré agregar los detalles que mencionaste para un panorama más amplio. ¡Gracias por la respuesta!
KlaasNotFound
1
¿Qué pasa si el usuario no tiene instalado Google Play Service?
Yuriy Chernyshov
6

Si conocía la ubicación general de las torres de telefonía celular, puede verificar si la torre de telefonía celular actual coincide con la ubicación dada (dentro de un margen de error de algo grande, como 10 o más millas).

Por ejemplo, si su aplicación desbloquea funciones solo si el usuario se encuentra en una ubicación específica (su tienda, por ejemplo), puede verificar tanto los gps como las torres de telefonía celular. Actualmente, ninguna aplicación de suplantación de GPS también falsifica las torres de telefonía celular, por lo que podría ver si alguien en todo el país simplemente está tratando de burlarse de sus funciones especiales (estoy pensando en la aplicación Disney Mobile Magic, por ejemplo).

Así es como la aplicación Llama administra la ubicación de forma predeterminada, ya que la verificación de los identificadores de las torres de telefonía celular consume mucha menos batería que el GPS. No es útil para ubicaciones muy específicas, pero si la casa y el trabajo están a varias millas de distancia, puede distinguir entre las dos ubicaciones generales con mucha facilidad.

Por supuesto, esto requeriría que el usuario tuviera una señal celular. Y tendría que conocer todos los identificadores de torres de telefonía móvil de la zona, de todos los proveedores de la red, o correría el riesgo de obtener un falso negativo.

Stephen Schrauger
fuente
1
Gracias, es una muy buena idea. Puede que tenga que investigar eso. Gracias
Chrispix
3

prueba este código es muy simple y útil

  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
fuente
Esta es una versión mucho mejor del método isMockLocationEnabled anterior.
setzamora
AppOpsManager.checkOp () arroja SecurityException si la aplicación se ha configurado para fallar en esta operación. Como: java.lang.SecurityException: el nombre del paquete de uid 11151 no tiene permitido realizar MOCK_LOCATION. Este método está a punto de detectar "si su aplicación puede simular ubicaciones". Pero no "si se burlan de las ubicaciones recibidas".
Sergio
@Sergio por "si tu aplicación puede simular ubicaciones" te refieres a si la aplicación actual tiene permiso para simular ubicaciones, ¿verdad?
Victor Laerte
@VictorLaerte He pasado un contexto de un tema: / Correcto. Pero la pregunta era: "cómo detectar si una ubicación recibida es simulada o es de un proveedor simulado". O cómo ignorar ubicaciones falsas.
Sergio
2

Este script funciona para todas las versiones de Android y lo encuentro después de muchas búsquedas

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
fuente
1

Puede agregar una verificación adicional basada en la triangulación de la torre celular o la información de los puntos de acceso Wifi utilizando la API de geolocalización de Google Maps

La forma más sencilla de obtener información sobre 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();

Puede comparar sus resultados con el sitio

Para obtener información sobre los puntos de acceso 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();
}
yoAlex5
fuente