寻求寻找预防/检测Android上GPS欺骗的最佳方法。关于如何实现此目标的任何建议,以及可以采取哪些措施来阻止它?我猜用户必须打开模拟位置来欺骗GPS,如果这样做,那么他们可以欺骗GPS吗?
我想我只需要检测是否启用了模拟位置?还有其他建议吗?
寻求寻找预防/检测Android上GPS欺骗的最佳方法。关于如何实现此目标的任何建议,以及可以采取哪些措施来阻止它?我猜用户必须打开模拟位置来欺骗GPS,如果这样做,那么他们可以欺骗GPS吗?
我想我只需要检测是否启用了模拟位置?还有其他建议吗?
Answers:
我进行了一些调查并在这里分享我的结果,这可能对其他人有用。
首先,我们可以检查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似乎并不可靠。
android.permission.ACCESS_MOCK_LOCATION
许可removeTestProvider
,我认为这是最大的缺点。
isMockSettingsON()
,Location.isFromMockProvider()
并areThereMockPermissionApps()
使用了黑名单的应用程序。有很多预先安装的具有ACCESS_MOCK_LOCATION
权限的系统应用程序,例如在HTC和Samsung设备上。将所有合法应用程序列入白名单会更好,但就我而言,最流行的位置欺骗应用程序的黑名单效果很好。我还检查了设备是否已植根。
从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");
}
isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
看来,做到这一点的唯一方法是防止位置欺骗防止MockLocations。不利的一面是,有些用户在使用蓝牙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;
return !x
代替if(x) return false; else return true
。
几年后偶然发现了这个线程。在2016年,大多数Android设备的API级别将大于等于18,因此应依赖Fernando指出的Location.isFromMockProvider()。
我在不同的Android设备和发行版上对假/模拟位置进行了广泛的实验。不幸的是.isFromMockProvider()并非100%可靠。每隔一段时间,虚假位置将不会被标记为模拟。这似乎是由于Google Location API中的某些内部融合逻辑所致。
如果您想了解更多信息,我写了一篇详细的博客文章。总而言之,如果您通过Location API订阅了位置更新,然后打开了一个伪造的GPS应用程序并将每个Location.toString()的结果打印到控制台,您将看到类似以下内容:
请注意,在位置更新流中,一个位置如何与其他位置具有相同的坐标,但是没有标记为模拟位置,并且位置精度更差。
为了解决这个问题,我编写了一个实用程序类,该类将可靠地禁止所有现代Android版本(API级别15及更高版本)中的Mock位置:
LocationAssistant-Android上无障碍的位置更新
基本上,它“不信任”距离最后一个已知模拟位置1公里以内的非模拟位置,并将它们标记为模拟位置。它会执行此操作,直到到达大量的非模拟位置为止。该LocationAssistant不仅可以拒绝模拟地点,但也unburdens你最建立和订阅位置更新的麻烦。
要仅接收真实位置更新(即抑制模拟),请按以下方式使用它:
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欺骗)的上下文中,基本上就是这样。
当然,有了扎根的操作系统,您仍然可以找到欺骗位置信息的方法,而普通应用程序则无法检测到。
如果您偶然知道蜂窝塔的一般位置,则可以检查当前蜂窝塔是否与给定的位置相匹配(误差范围在10英里或10英里以上)。
例如,如果您的应用仅在用户位于特定位置(例如,您的商店)时才解锁功能,则可以检查gps以及手机信号塔。目前,没有gps欺骗应用程序还欺骗手机发射塔,因此您可以看到全国各地是否有人只是在试图将自己的方式欺骗到您的特殊功能中(例如,我想到的是Disney Mobile Magic应用程序)。
这是Llama应用程序默认情况下管理位置的方式,因为检查基站信号塔ID的电量比GPS少得多。它对非常特定的位置没有用,但是如果家和工作地点相距几英里,则可以很容易地区分两个位置。
当然,这将要求用户完全具有小区信号。而且您将必须知道该区域中所有网络提供商上的所有手机信号塔ID,否则您将冒着假阴性的风险。
试试这个代码,它非常简单和有用
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;
}
此脚本适用于所有版本的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
}
您可以使用Google Maps Geolocation API根据手机发射塔三角测量或Wifi接入点信息添加其他检查
获取有关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();
您可以将结果与网站进行比较
获取有关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();
}