Tắt / Kiểm tra Vị trí giả (ngăn giả mạo gps)


90

Đang tìm cách tốt nhất để ngăn chặn / phát hiện giả mạo GPS trên Android. Bất kỳ đề xuất nào về cách thực hiện điều này và có thể làm gì để ngăn chặn nó? Tôi đoán người dùng phải bật các vị trí giả để giả mạo GPS, nếu điều này được thực hiện, thì họ có thể giả mạo GPS?

Tôi đoán tôi sẽ chỉ cần phát hiện xem Vị trí giả đã được bật chưa? Bất cứ một đề nghị nào khác?


2
Tôi nghĩ anh ấy đang hỏi về chức năng Giả mạo vị trí có sẵn trong chế độ xem DDMS trong Eclipse.
Shawn Walton

2
Tôi có một trò chơi dựa trên vị trí mà tôi không muốn mọi người lừa dối, vì vậy tôi cố gắng chặn việc giả mạo, tôi hiểu là nó có thể xảy ra theo một trong hai cách .. Bật vị trí giả và xây dựng hình ảnh tùy chỉnh chống giả mạo ở cấp độ thấp và bỏ qua cài đặt giả mạo trong ứng dụng cài đặt. Đang cố gắng tìm Nhà cung cấp Cài đặt Hệ thống cho MockLocations hoặc xem liệu nó có được bật hay không (với một trình nghe ở giữa ứng dụng).
Chrispix

Câu trả lời:


125

Tôi đã thực hiện một số cuộc điều tra và chia sẻ kết quả của mình ở đây, điều này có thể hữu ích cho những người khác.

Đầu tiên, chúng ta có thể kiểm tra xem tùy chọn MockSetting đã được BẬT chưa

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

Thứ hai, chúng tôi có thể kiểm tra xem có ứng dụng nào khác trong thiết bị đang sử dụng không android.permission.ACCESS_MOCK_LOCATION(Ứng dụng giả mạo vị trí)

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

Nếu cả hai phương pháp trên, thứ nhất và thứ hai đều đúng, thì rất có thể vị trí đó có thể bị giả mạo hoặc giả mạo.

Giờ đây, có thể tránh được việc giả mạo bằng cách sử dụng API của Trình quản lý vị trí.

Chúng tôi có thể xóa nhà cung cấp thử nghiệm trước khi yêu cầu cập nhật vị trí từ cả hai nhà cung cấp (Mạng và 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);

Tôi đã thấy rằng removeTestProvider (~) hoạt động rất tốt trên phiên bản Jelly Bean trở đi. API này dường như không đáng tin cậy cho đến Ice Cream Sandwich.


Những quan sát rất thú vị. Đặc biệt là +1 cuối cùng để chia sẻ điều này.
ar-g

2
Lưu ý về phương thức removeTestProvider. Nếu bạn cho phép Trình quản lý vị trí hoạt động trong nền, người dùng có thể truy cập ứng dụng giả và khởi động lại vị trí chế nhạo. Trình quản lý vị trí của bạn sau đó sẽ bắt đầu nhận các vị trí giả cho đến khi bạn gọi lại removeTestProvider.
Timur_C

4
Ngoài ra, ứng dụng của bạn phải có android.permission.ACCESS_MOCK_LOCATIONquyền removeTestProviderđể hoạt động, điều mà tôi nghĩ là bất lợi lớn nhất.
Timur_C

18
cảm ơn vì câu trả lời! chỉ là một điểm: trong Android 6.0 ALLOW_MOCK_LOCATION không được dùng nữa. Và thực ra cũng không có hộp kiểm cho vị trí giả. Người ta có thể kiểm tra xem vị trí là giả mạo hoặc không đúng đối tượng từ vị trí: location.isFromMockProvider ()
Silwester

2
@Blackkara Rốt cuộc tôi đã không sử dụng nó. Tôi sử dụng một sự kết hợp tùy chỉnh của isMockSettingsON(), Location.isFromMockProvider()areThereMockPermissionApps()với một danh sách đen của ứng dụng. Có rất nhiều ứng dụng hệ thống được cài đặt sẵn có ACCESS_MOCK_LOCATION quyền, ví dụ như trên các thiết bị HTC và Samsung. Một danh sách trắng của tất cả các ứng dụng hợp pháp sẽ tốt hơn nhưng một danh sách đen các ứng dụng giả mạo vị trí phổ biến nhất đã hoạt động tốt trong trường hợp của tôi. Và tôi cũng đã kiểm tra xem máy đã được root chưa.
Timur_C

45

Kể từ API 18, đối tượng Location có phương thức .isFromMockProvider () để bạn có thể lọc ra các vị trí giả mạo.

Nếu bạn muốn hỗ trợ các phiên bản trước 18, có thể sử dụng một cái gì đó như sau:

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

Tôi khá chắc chắn rằng biểu thức thứ hai của bạn là ngược (trả về true khi nó phải trả về false). Tôi nghĩ rằng nó nên là:isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
AjahnCharles

3
Không có gì. Cảm ơn bạn đã đăng một câu trả lời hiện đại hơn! Thực sự đây là câu trả lời chính xác cho đến ngày hôm nay.
AjahnCharles,

1
Làm cách nào chúng tôi có thể làm điều đó mà không có đối tượng "vị trí" cho SDK trên 18?
Ajit Sharma

35

Có vẻ như cách duy nhất để làm điều này là ngăn chặn Giả mạo vị trí ngăn MockLocations. Mặt trái là có một số người dùng sử dụng thiết bị GPS Bluetooth để có tín hiệu tốt hơn, họ sẽ không thể sử dụng ứng dụng vì họ được yêu cầu sử dụng các vị trí giả.

Để làm điều này, tôi đã làm như sau:

// 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
Đây không phải là bằng chứng ngu ngốc. Người dùng trên thiết bị không root vẫn có thể đặt vị trí giả, tùy thời điểm trong tương lai, sau đó tắt các vị trí giả và vị trí giả vẫn hoạt động. Thậm chí tệ hơn, họ có thể gọi các vị trí mô phỏng tên nhà cung cấp tương tự như mạng / Gps và nó dường như kéo từ đó ..
Chrispix

3
Hơn nữa, GPS giả không yêu cầu cài đặt vị trí giả trên các thiết bị đã root.
Paul Lammertsma

Luôn luôn có thể kiểm tra để xác minh rằng ứng dụng fake.gps chưa được cài đặt :)
Chrispix

11
Bạn có thể sử dụng return !xthay thế if(x) return false; else return true.
CodesInChaos

Trên thực tế, vị trí giả mạo sẽ thay đổi cài đặt vị trí giả ngay cả trên các thiết bị đã root.
PageNotFound

25

Tình cờ gặp chủ đề này một vài năm sau đó. Vào năm 2016, hầu hết các thiết bị Android sẽ có cấp độ API> = 18 và do đó phải dựa vào Location.isFromMockProvider () như Fernando đã chỉ ra .

Tôi đã thử nghiệm rộng rãi với các vị trí giả / nhái trên các thiết bị Android và bản phân phối khác nhau. Rất tiếc .isFromMockProvider () không đáng tin cậy 100%. Thỉnh thoảng, một địa điểm giả mạo sẽ không được dán nhãn là giả mạo . Điều này dường như là do một số logic kết hợp nội bộ sai trong API Vị trí của Google.

Tôi đã viết một bài blog chi tiết về điều này , nếu bạn muốn tìm hiểu thêm. Tóm lại, nếu bạn đăng ký cập nhật vị trí từ API Vị trí, sau đó bật một ứng dụng GPS giả và in kết quả của từng Location.toString () vào bảng điều khiển, bạn sẽ thấy một cái gì đó như sau:

nhập mô tả hình ảnh ở đây

Lưu ý rằng, trong luồng cập nhật vị trí, một vị trí có cùng tọa độ với các vị trí khác, nhưng không bị gắn cờ là mô phỏng và có độ chính xác vị trí kém hơn nhiều.

Để khắc phục sự cố này, tôi đã viết một lớp tiện ích sẽ ngăn chặn vị trí Mock một cách đáng tin cậy trên tất cả các phiên bản Android hiện đại (API cấp 15 trở lên):

LocationAssistant - Cập nhật vị trí không có rắc rối trên Android

Về cơ bản, nó "làm mất lòng tin" các vị trí không phải là giả nằm trong vòng 1 km tính từ vị trí giả được biết đến cuối cùng và cũng gắn nhãn chúng là giả. Nó thực hiện điều này cho đến khi một số lượng đáng kể các vị trí không phải giả đã đến. Các LocationAssistant có thể không chỉ loại bỏ các địa điểm giả, mà còn unburdens bạn từ hầu hết các rắc rối của thành lập và đăng ký vào cập nhật vị trí.

Để chỉ nhận thông tin cập nhật về vị trí thực (tức là ngăn chặn chế độ giả), hãy sử dụng nó như sau:

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()bây giờ sẽ chỉ được gọi với thông tin vị trí thực. Có một số phương pháp lắng nghe khác mà bạn cần thực hiện, nhưng trong bối cảnh câu hỏi của bạn (làm thế nào để ngăn chặn việc giả mạo GPS) về cơ bản thì đây là nó.

Tất nhiên, với một hệ điều hành đã root, bạn vẫn có thể tìm cách giả mạo thông tin vị trí mà các ứng dụng thông thường không thể phát hiện được.


Bạn nên tóm tắt ngắn gọn bài đăng trên blog được liên kết (trường hợp isFromMockProvider bị lỗi).
AjahnCharles

@CodeConfident - cảm ơn bạn đã nhận xét! Tuy nhiên, không chắc tôi nên thêm gì. Đoạn thứ hai của câu trả lời của tôi phần tóm tắt của bài đăng trên blog. .isFromMockProvider bị lỗi thường xuyên và không thể đoán trước. Trong bài viết tôi chỉ mô tả chi tiết hơn các bước tôi đã thực hiện để phát hiện và khắc phục điều này.
KlaasNotFound

Vâng, tôi buộc phải chuyển đến bài viết của bạn để hiểu điều mà tôi cảm thấy như nó đi ngược lại ý định của SO. Gợi ý tốt nhất của tôi sẽ là: (1) chèn pic của bạn mà chương trình vị trí tinh ranh (không gắn cờ là một mô hình) và (2) một cách nhanh chóng lưu ý logic của bạn để loại bỏ chúng (bỏ qua trong vòng 1km của một mock)
AjahnCharles

Ok, gotcha. Tôi nghĩ rằng trong bối cảnh của OP, các chi tiết cụ thể về lý do tại sao .isFromMockProvider () không đáng tin cậy không quá phù hợp. Nhưng tôi sẽ cố gắng thêm các chi tiết bạn đã đề cập cho bức tranh lớn hơn. Cảm ơn vì bạn đã phản hồi!
KlaasNotFound

1
Điều gì xảy ra nếu người dùng chưa cài đặt Dịch vụ Google Play?
Yuriy Chernyshov

6

Nếu bạn tình cờ biết được vị trí chung của các tháp di động, bạn có thể kiểm tra xem các tháp di động hiện nay phù hợp với vị trí nhất định (trong một biên độ lỗi của một cái gì đó lớn, giống như 10 hoặc nhiều dặm).

Ví dụ: nếu ứng dụng của bạn chỉ mở khóa các tính năng khi người dùng ở một vị trí cụ thể (ví dụ: cửa hàng của bạn), bạn có thể kiểm tra gps cũng như tháp di động. Hiện tại, không có ứng dụng giả mạo gps nào cũng giả mạo tháp di động, vì vậy bạn có thể biết liệu ai đó trên toàn quốc đang cố gắng giả mạo theo cách của họ vào các tính năng đặc biệt của bạn (ví dụ: tôi đang nghĩ đến ứng dụng Disney Mobile Magic).

Đây là cách ứng dụng Llama quản lý vị trí theo mặc định, vì việc kiểm tra id tháp di động ít tốn pin hơn nhiều so với gps. Nó không phải là hữu ích cho các địa điểm rất cụ thể, nhưng nếu gia đình và công việc một vài dặm, nó có thể phân biệt giữa hai địa điểm chung rất dễ dàng.

Tất nhiên, điều này sẽ yêu cầu người dùng phải có tín hiệu di động. Và bạn sẽ phải biết tất cả id tháp di động trong khu vực - trên tất cả các nhà cung cấp mạng - nếu không bạn sẽ gặp rủi ro âm tính giả.


1
Cảm ơn, đó là một ý tưởng khá hay. Tôi có thể phải xem xét điều đó. Cảm ơn
Chrispix

3

hãy thử mã này rất đơn giản và hữu ích

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

Đây là phiên bản tốt hơn nhiều của phương thức isMockLocationEnabled ở trên.
setzamora

AppOpsManager.checkOp () ném SecurityException Nếu ứng dụng đã được định cấu hình để gặp sự cố trên tùy chọn này. Như: java.lang.SecurityException: tên gói từ uid 11151 không được phép thực hiện MOCK_LOCATION. Phương pháp này nhằm phát hiện "nếu ứng dụng của bạn có thể giả mạo các vị trí". Nhưng không phải là "nếu địa điểm nhận được là chế nhạo".
Sergio

@Sergio bởi "nếu ứng dụng của bạn có thể chế nhạo vị trí", ý bạn là nếu ứng dụng hiện tại có quyền giả mạo vị trí, phải không?
Victor Laerte

@VictorLaerte Lần cuối cùng tôi viết bối cảnh của một chủ đề: / Đúng. Nhưng câu hỏi đặt ra là: "làm thế nào để phát hiện xem một vị trí nhận được là giả mạo hay là từ một nhà cung cấp giả". Hoặc làm thế nào để bỏ qua các địa điểm giả mạo.
Sergio

2

Tập lệnh này đang hoạt động cho tất cả các phiên bản của Android và tôi tìm thấy nó sau nhiều lần tìm kiếm

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

Bạn có thể thêm kiểm tra bổ sung dựa trên tam giác tháp di động hoặc thông tin Điểm truy cập Wi-Fi bằng API vị trí địa lý của Google Maps

Cách đơn giản nhất để nhận thông tin về 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();

Bạn có thể so sánh kết quả của mình với trang web

Để nhận thông tin về Điểm truy cập Wi-Fi

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();
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.