寻找在Android上防止/检测GPS欺骗的最佳方法。有关如何实现此目标以及可以采取什么措施来阻止它的任何建议?我猜用户必须打开模拟位置才能欺骗GPS,如果这样做了,那么他们就可以欺骗GPS吗?
我想我只需要检测模拟位置是否已启用?还有其他建议吗?
寻找在Android上防止/检测GPS欺骗的最佳方法。有关如何实现此目标以及可以采取什么措施来阻止它的任何建议?我猜用户必须打开模拟位置才能欺骗GPS,如果这样做了,那么他们就可以欺骗GPS吗?
我想我只需要检测模拟位置是否已启用?还有其他建议吗?
我已经进行了一些调查,并在这里分享我的结果,这可能对其他人有用。
首先,我们可以检查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);
我已经看到,在Jelly Bean及以后的版本中,removeTestProvider(〜)非常有效。 直到Ice Cream Sandwich,该API似乎不可靠。
Flutter更新:使用Geolocator并检查Position
对象的isMocked
属性。
android.permission.ACCESS_MOCK_LOCATION
权限,以使removeTestProvider
功能正常工作,我认为这是最大的不利因素。 - Timur_CisMockSettingsON()
、Location.isFromMockProvider()
和 areThereMockPermissionApps()
,以及一份应用黑名单。例如在HTC和三星设备上,有很多预安装的系统应用程序具有 ACCESS_MOCK_LOCATION
权限。白名单上列出所有合法应用程序是更好的选择,但在我的情况下,大多数受欢迎的位置欺骗应用程序的黑名单效果很好。我还检查了设备是否已root。 - Timur_Cboolean 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”);
- charles-allen// 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
。 - CodesInChaos几年后我偶然发现了这个帖子。在2016年,大多数Android设备的API级别将>=18,因此应该依赖于Location.isFromMockProvider(),正如Fernando所指出的。
我在不同的Android设备和发行版上广泛实验了虚假/模拟位置。不幸的是,.isFromMockProvider()并不是100%可靠的。不时会出现一次虚假定位未被标记为模拟。这似乎是由于Google位置API中的一些错误的内部融合逻辑所致。
如果您想了解更多信息,我写了一篇详细的博客文章。总之,如果您从位置API订阅位置更新,然后打开一个虚拟GPS应用程序并将每个Location.toString()的结果打印到控制台,则会看到像这样的内容:
请注意,在位置更新流中,有一个位置坐标与其他位置相同,但未被标记为模拟,并且其位置精度要差得多。
为解决这个问题,我编写了一个实用程序类,可以可靠地抑制所有现代Android版本(API级别15及以上)的模拟位置:
LocationAssistant - 无忧无虑地在Android上更新位置
基本上,它会“不信任”上一个已知的模拟位置以内1km的非模拟位置,并将它们标记为模拟位置。直到到达了大量的非模拟位置。 LocationAssistant不仅可以拒绝模拟位置,还可以减轻设置和订阅位置更新的大部分麻烦。
要只接收真实位置更新(即抑制模拟位置),请按以下方式使用:
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欺骗)而言,基本上就这些了。
当然,在rooted的操作系统中,你仍然可以找到一些无法被普通应用程序检测到的欺骗位置信息的方法。
试试这段代码,它非常简单而且有用.
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;
}
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();
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();
}
这个脚本适用于所有版本的安卓系统,我经过多次搜索才找到它。
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
}
@Override
public void onLocationChanged (Location location){
boolean isMockLocation = location.isFromMockProvider();
}
将此粘贴到您的活动/您想要验证虚假/模拟GPS的位置
try {
if (areThereMockPermissionApps(mContext)) {
Log.e(TAG, " - " + "Yup its use fake gps");
List<String> mFakeList = new ArrayList<>();
mFakeList = getListOfFakeLocationAppsInstalled(mContext); // this will return the fake app list
for (int a = 0; a < mFakeList.size(); a++) {
Log.e(TAG, mFakeList.size() + " - " + "NameList ----- " + mFakeList.get(a));
}
} else
Log.e(TAG, " - " + "Nope its not use fake gps");
} catch (Exception w) {
w.printStackTrace();
}
在这里,您可以获取设备中安装的虚假/模拟应用程序列表。
private List<String> getListOfFakeLocationAppsInstalled(Context context) {
List<String> fakeApps = new ArrayList<>();
try {
List<String> runningApps = new ArrayList<>();
final PackageManager pm = getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo packageInfo : packages) {
runningApps.add(packageInfo.packageName);
} // the getLaunchIntentForPackage returns an intent that you can use with startActivity()
for (String app : runningApps) {
if (!isSystemPackage(context, app) && hasAppPermission(context, app, "android.permission.ACCESS_MOCK_LOCATION")) {
fakeApps.add(getApplicationName(context, app));
}
}
} catch (Exception w) {
w.printStackTrace();
}
return fakeApps;
}
将此方法粘贴到您的 Helper/同一类中
public static boolean areThereMockPermissionApps(Context context) {
int count = 0;
try {
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 (PackageManager.NameNotFoundException e) {
Log.e("MockDeductionAgilanbu", "Got exception --- " + e.getMessage());
}
}
} catch (Exception w) {
w.printStackTrace();
}
if (count > 0)
return true;
return false;
}