Deshabilitar / Comprobar la ubicación simulada (evitar gps spoofing)

Buscando la mejor forma de prevenir / detectar spoofing 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, ¿entonces pueden falsificar el GPS?

¿Supongo que necesitaría detectar si las ubicaciones falsas están habilitadas? ¿Cualquier otra sugerencia?

He realizado una investigación y compartido mis resultados aquí, esto puede ser útil para otros.

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

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 utilicen android.permission.ACCESS_MOCK_LOCATION (aplicaciones de spoofing de ubicación)

 public static boolean areThereMockPermissionApps(Context context) { int count = 0; PackageManager pm = context.getPackageManager(); List 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 pueda ser falsa o simulada.

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

Podemos eliminar al proveedor de la 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 con Jelly Bean y su versión en adelante. Esta API parecía no ser confiable hasta Ice Cream Sandwich.

Parece que la única forma de hacerlo es evitar que Location Spoofing evite MockLocations. El inconveniente es que hay algunos usuarios que usan dispositivos Bluetooth con GPS 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; 

Desde la API 18, el objeto Ubicación tiene el método .isFromMockProvider () para que pueda filtrar las ubicaciones falsas.

Si desea admitir versiones anteriores a 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"); } 

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

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

Escribí una publicación detallada del blog sobre esto , si quieres saber más. En resumen, si te suscribes a las actualizaciones de ubicación de la API de ubicación, luego enciendes una aplicación GPS falsa e imprimes el resultado de cada Location.toString () a la consola, verás algo como esto:

enter image description here

Observe cómo, en la secuencia de actualizaciones de ubicación, una ubicación tiene las mismas coordenadas que las otras, 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 suprimirá de manera confiable las ubicaciones de Mock en todas las versiones modernas de Android (API de nivel 15 y superior):

LocationAssistant: actualizaciones de ubicación sin problemas en Android

Básicamente, “desconfía” de las ubicaciones que no son de prueba que se encuentran a 1 km de la última ubicación simulada conocida y también las etiqueta como simulacro. Hace esto hasta que haya llegado un número significativo de ubicaciones no simuladas. El asistente de ubicación no solo puede rechazar ubicaciones simuladas, sino que también le libera de la mayor parte de la molestia de configurar y suscribirse a actualizaciones de ubicación.

Para recibir solo actualizaciones de ubicación reales (es decir, suprimir burlas), úselo 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 de escucha más que debe implementar, pero en el contexto de su pregunta (cómo evitar la suplantación GPS) esto es básicamente eso.

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

Si conocía la ubicación general de las torres celulares, podría verificar si la torre 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 las gps como las torres de telefonía móvil. Actualmente, ninguna aplicación de gps spoofing también parodia las torres de telefonía celular, por lo que se puede ver si alguien en todo el país simplemente está tratando de engañar a sus características especiales (estoy pensando en la aplicación Disney Mobile Magic, por ejemplo).

Así es como la aplicación Llama gestiona la ubicación de forma predeterminada, ya que la comprobación de los ID de las células de la célula consume mucho menos batería que los gps. No es útil para ubicaciones muy específicas, pero si el hogar y el trabajo están a varias millas de distancia, puede distinguir fácilmente entre las dos ubicaciones generales.

Por supuesto, esto requeriría que el usuario tenga una señal de celular en absoluto. Y tendría que conocer todos los ID de las torres de telefonía en el área, en todos los proveedores de la red, o correría el riesgo de un falso negativo.

Este script está funcionando 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 } 

Puede agregar un cheque adicional basado en la triangulación de la torre de la célula o la información de 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 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 results = mWifiManager.getScanResults();//<-result list } }; appContext.registerReceiver(broadcastReceiver, filter); // start WiFi Scan mWifiManager.startScan(); } 

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