ปิดการใช้งาน / ตรวจสอบตำแหน่งจำลอง (ป้องกันการปลอมแปลง gps)


92

กำลังค้นหาวิธีที่ดีที่สุดในการป้องกัน / ตรวจจับการปลอมแปลง GPS บน Android ข้อเสนอแนะใด ๆ เกี่ยวกับวิธีการนี้สำเร็จและสิ่งที่สามารถทำได้เพื่อหยุดมัน? ฉันเดาว่าผู้ใช้ต้องเปิดตำแหน่งจำลองเพื่อหลอก GPS ถ้าเสร็จแล้วพวกเขาสามารถปลอม GPS ได้หรือไม่?

ฉันเดาว่าฉันจะต้องตรวจสอบว่ามีการเปิดใช้งาน Mock Locations หรือไม่? ข้อเสนอแนะอื่น ๆ ?


2
ฉันคิดว่าเขากำลังถามเกี่ยวกับฟังก์ชันการปลอมแปลงตำแหน่งที่มีอยู่ในมุมมอง DDMS ใน Eclipse
Shawn Walton

2
ฉันมีเกมตามสถานที่ซึ่งฉันไม่ต้องการให้คนโกงดังนั้นฉันจึงพยายามที่จะป้องกันการปลอมแปลงความเข้าใจของฉันคือมันสามารถเกิดขึ้นได้หนึ่งในสองวิธี .. การเปิดใช้ตำแหน่งจำลองและการสร้างรูปภาพที่กำหนดเองซึ่งทำการปลอมแปลงระดับต่ำ และไม่คำนึงถึงการตั้งค่าการปลอมแปลงในแอปการตั้งค่า พยายามค้นหาการตั้งค่าผู้ให้บริการระบบสำหรับ MockLocations หรือต้องการดูว่าเปิดใช้งานอยู่หรือไม่ (โดยมีฟังอยู่ตรงกลางแอป)
Chrispix

คำตอบ:


127

ฉันได้ทำการตรวจสอบและแบ่งปันผลลัพธ์ของฉันที่นี่ซึ่งอาจเป็นประโยชน์สำหรับคนอื่น ๆ

ขั้นแรกเราสามารถตรวจสอบว่าตัวเลือก 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 ของ Location Manager

เราสามารถลบผู้ให้บริการทดสอบก่อนที่จะขอการอัปเดตตำแหน่งจากทั้งผู้ให้บริการ (เครือข่ายและ 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 นี้จะไม่น่าเชื่อถือจนถึง Ice Cream Sandwich


ข้อสังเกตที่น่าสนใจมาก โดยเฉพาะอย่างยิ่ง +1 สุดท้ายสำหรับการแบ่งปันสิ่งนี้
ar-g

2
หมายเหตุเกี่ยวกับวิธี removeTestProvider หากคุณอนุญาตให้ตัวจัดการตำแหน่งทำงานในพื้นหลังผู้ใช้สามารถไปที่แอปจำลองและรีสตาร์ทตำแหน่งจำลองได้ ผู้จัดการสถานที่ของคุณจะเริ่มรับตำแหน่งจำลองจนกว่าคุณจะโทรหา removeTestProvider อีกครั้ง
Timur_C

4
นอกจากนี้แอปของคุณต้องได้android.permission.ACCESS_MOCK_LOCATIONรับอนุญาตremoveTestProviderให้ทำงานซึ่งฉันคิดว่าเป็นข้อเสียที่ใหญ่ที่สุด
Timur_C

18
ขอบคุณสำหรับคำตอบ! เพียงประเด็น: ใน Android 6.0 ALLOW_MOCK_LOCATION เลิกใช้งานแล้ว และจริงๆแล้วไม่มีช่องทำเครื่องหมายสำหรับตำแหน่งจำลองเช่นกัน สามารถตรวจสอบได้ว่าตำแหน่งที่ตั้งเป็นของปลอมหรือไม่จากวัตถุตำแหน่ง
Silwester

3
@ Blackkara ไม่ได้ใช้เลยค่ะ ฉันใช้การรวมกันที่กำหนดเองของisMockSettingsON(), Location.isFromMockProvider()และareThereMockPermissionApps()มีรายชื่อสีดำของปพลิเคชัน มีแอประบบที่ติดตั้งไว้ล่วงหน้าจำนวนมากที่ACCESS_MOCK_LOCATION ได้รับอนุญาตเช่นบนอุปกรณ์ HTC และ Samsung รายการที่อนุญาตของแอปที่ถูกต้องตามกฎหมายทั้งหมดจะดีกว่า แต่บัญชีดำของแอปปลอมแปลงตำแหน่งที่เป็นที่นิยมมากที่สุดทำงานได้ดีในกรณีของฉัน และฉันยังตรวจสอบด้วยว่าอุปกรณ์ถูกรูทหรือไม่
Timur_C

46

ตั้งแต่ 18 API วัตถุสถานที่มีวิธีการ.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");
charles-allen

3
ยินดีต้อนรับ ขอขอบคุณที่โพสต์คำตอบที่ทันสมัยกว่านี้! นี่คือคำตอบที่ถูกต้อง ณ วันนี้จริงๆ
charles-allen

1
เราจะทำได้อย่างไรโดยไม่มีวัตถุ "ตำแหน่ง" สำหรับ SDK ที่สูงกว่า 18
Ajit Sharma

35

ดูเหมือนว่าวิธีเดียวที่จะทำได้คือการป้องกันการปลอมแปลงตำแหน่งที่ป้องกัน MockLocations ข้อเสียคือมีผู้ใช้บางรายที่ใช้อุปกรณ์ Bluetooth 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;

4
นี่ไม่ใช่ข้อพิสูจน์ที่โง่เขลา ผู้ใช้บนอุปกรณ์ที่ไม่ได้รูทยังคงสามารถตั้งค่าตำแหน่งจำลองโดยไม่มีเวลาในอนาคตจากนั้นปิดใช้งานตำแหน่งจำลองและตำแหน่งจำลองยังคงทำงานอยู่ ที่แย่กว่านั้นคือพวกเขาสามารถเรียกตำแหน่งจำลองเป็นชื่อผู้ให้บริการเดียวกันกับ Network / Gps และดูเหมือนว่ามันจะดึงออกมาจากที่ ..
Chrispix

3
นอกจากนี้Fake GPSไม่ต้องการการตั้งค่าตำแหน่งจำลองบนอุปกรณ์ที่รูท
Paul Lammertsma

สามารถตรวจสอบได้ตลอดเวลาว่าไม่ได้ติดตั้งแอป fake.gps :)
Chrispix

11
คุณสามารถใช้return !xแทนif(x) return false; else return true.
CodesInChaos

ในความเป็นจริงตำแหน่งปลอมจะเปลี่ยนการตั้งค่าตำแหน่งจำลองแม้ในอุปกรณ์ที่รูท
PageNotFound

26

สะดุดกับหัวข้อนี้สองสามปีต่อมา ในปี 2559 อุปกรณ์ Android ส่วนใหญ่จะมีระดับ API> = 18 ดังนั้นจึงควรพึ่งพาLocation.isFromMockProvider ()ตามที่Fernandoชี้ไว้ไว้

ฉันทดลองกับสถานที่ปลอม / จำลองบนอุปกรณ์ Android และ Distros ต่างๆ น่าเสียดายที่. isFromMockProvider ()ไม่น่าเชื่อถือ 100% ในบางครั้งสถานที่ปลอมจะไม่ถูกระบุว่าเป็นการจำลองสถานที่ของปลอมจะไม่ถูกระบุว่าเป็นเยาะเย้ยสิ่งนี้น่าจะเกิดจากตรรกะฟิวชันภายในที่ผิดพลาดใน Google Location API

ฉันเขียนบล็อกโพสต์โดยละเอียดเกี่ยวกับเรื่องนี้หากคุณต้องการเรียนรู้เพิ่มเติม สรุปได้ว่าหากคุณสมัครรับข้อมูลการอัปเดตตำแหน่งจาก Location API จากนั้นเปิดแอป GPS ปลอมและพิมพ์ผลลัพธ์ของLocation.toString ()แต่ละรายการไปยังคอนโซลคุณจะเห็นสิ่งนี้:

ป้อนคำอธิบายภาพที่นี่

สังเกตว่าในสตรีมของการอัปเดตตำแหน่งสถานที่หนึ่งแห่งมีพิกัดเดียวกันกับที่อื่น ๆ แต่ไม่ได้ถูกตั้งค่าสถานะว่าเป็นการจำลองและมีความแม่นยำของตำแหน่งที่ต่ำกว่ามาก

เพื่อแก้ไขปัญหานี้ฉันได้เขียนคลาสยูทิลิตี้ที่จะระงับตำแหน่งจำลองใน Android เวอร์ชันใหม่ทั้งหมดได้อย่างน่าเชื่อถือ (API ระดับ 15 ขึ้นไป):

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) โดยพื้นฐานแล้ว

แน่นอนว่าด้วยระบบปฏิบัติการที่รูทคุณยังคงสามารถค้นหาวิธีการปลอมแปลงข้อมูลตำแหน่งซึ่งเป็นไปไม่ได้ที่แอปทั่วไปจะตรวจจับได้


คุณควรสรุปสั้น ๆ ของบล็อกโพสต์ที่เชื่อมโยง (โดยที่ isFromMockProvider ล้มเหลว)
charles-allen

@CodeConfident - ขอบคุณสำหรับคำพูด! ไม่แน่ใจว่าควรเพิ่มอะไรดี ย่อหน้าที่สองของคำตอบของฉันคือสรุปของโพสต์บล็อก .isFromMockProviderล้มเหลวเป็นพัก ๆ และคาดเดาไม่ได้ ในบทความฉันอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับขั้นตอนที่ฉันใช้เพื่อค้นหาและแก้ไขปัญหานี้
KlaasNotFound

ฉันถูกบังคับให้ข้ามไปที่บทความของคุณเพื่อทำความเข้าใจว่าฉันรู้สึกว่ามันขัดกับความตั้งใจของ SO ข้อเสนอแนะที่ดีที่สุดของฉันคือ: (1) แทรกรูปภาพของคุณที่แสดงตำแหน่งที่หลบ (ไม่ถูกตั้งค่าสถานะว่าเป็นการล้อเลียน) และ (2) สังเกตตรรกะของคุณอย่างรวดเร็วในการกำจัดสิ่งเหล่านี้ (ละเว้นภายใน 1 กม. จากการเยาะเย้ย)
charles-allen

ตกลง gotcha ฉันคิดว่าในบริบทของ OP ข้อมูลเฉพาะของสาเหตุที่. isFromMockProvider ()ไม่น่าเชื่อถือนั้นไม่เกี่ยวข้องมากเกินไป แต่ฉันจะพยายามเพิ่มรายละเอียดที่คุณกล่าวถึงเพื่อให้ได้ภาพที่ใหญ่ขึ้น ขอบคุณสำหรับความคิดเห็น!
KlaasNotFound

1
จะเกิดอะไรขึ้นหากผู้ใช้ไม่ได้ติดตั้งบริการ Google Play?
Yuriy Chernyshov

6

หากคุณทราบตำแหน่งทั่วไปของเสาสัญญาณคุณสามารถตรวจสอบเพื่อดูว่าหอส่งสัญญาณปัจจุบันตรงกับตำแหน่งที่ระบุไว้หรือไม่ (ภายในระยะข้อผิดพลาดของสิ่งที่มีขนาดใหญ่เช่น 10 ไมล์ขึ้นไป)

ตัวอย่างเช่นหากแอปของคุณปลดล็อกคุณลักษณะเฉพาะในกรณีที่ผู้ใช้อยู่ในสถานที่เฉพาะ (เช่นร้านค้าของคุณ) คุณสามารถตรวจสอบ GPS และเสาสัญญาณได้ ขณะนี้ไม่มีแอปพลิเคชันปลอมแปลง gps ที่หลอกลวงเสาสัญญาณดังนั้นคุณสามารถดูได้ว่ามีใครบางคนทั่วประเทศพยายามปลอมแปลงวิธีการใช้คุณสมบัติพิเศษของคุณหรือไม่ (ฉันกำลังนึกถึงแอป Disney Mobile Magic เป็นตัวอย่างหนึ่ง)

นี่คือวิธีที่แอป Llama จัดการตำแหน่งตามค่าเริ่มต้นเนื่องจากการตรวจสอบรหัสหอเซลล์นั้นใช้แบตเตอรี่น้อยกว่า gps มาก ไม่มีประโยชน์สำหรับสถานที่ที่เฉพาะเจาะจงมากนัก แต่ถ้าบ้านและที่ทำงานอยู่ห่างออกไปหลายไมล์ก็สามารถแยกความแตกต่างระหว่างสถานที่ทั่วไปทั้งสองได้อย่างง่ายดาย

แน่นอนว่าสิ่งนี้จะต้องให้ผู้ใช้มีสัญญาณมือถือเลย และคุณจะต้องรู้รหัสเสาสัญญาณทั้งหมดในพื้นที่ - ในผู้ให้บริการเครือข่ายทั้งหมด - มิฉะนั้นคุณจะเสี่ยงต่อการติดลบที่ผิดพลาด


1
ขอบคุณนั่นเป็นความคิดที่ดีทีเดียว ฉันอาจต้องมองเข้าไปในนั้น ขอบคุณ
Chrispix

3

ลองใช้รหัสนี้ง่ายและมีประโยชน์

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

นี่เป็นวิธีการ isMockLocationEnabled เวอร์ชันที่ดีกว่ามาก
setzamora

AppOpsManager.checkOp () พ่น SecurityException หากแอปได้รับการกำหนดค่าให้หยุดทำงานบน op นี้ เช่น: java.lang.SecurityException: packagename จาก uid 11151 ไม่อนุญาตให้ดำเนินการ MOCK_LOCATION วิธีนี้กำลังตรวจจับ "หากแอปของคุณสามารถจำลองสถานที่ได้" แต่ไม่ใช่ "หากสถานที่ที่ได้รับถูกล้อเลียน"
Sergio

@Sergio โดย "ถ้าแอปของคุณสามารถเยาะเย้ยสถานที่ได้" คุณหมายถึงว่าแอปปัจจุบันได้รับอนุญาตให้จำลองสถานที่ใช่ไหม
Victor Laerte

@VictorLaerte ฉันมีบริบทของหัวข้อสุดท้าย: / ขวา แต่คำถามคือ: "วิธีตรวจสอบว่าสถานที่ที่ได้รับถูกจำลองหรือมาจากผู้ให้บริการจำลอง" หรือวิธีละเว้นสถานที่ปลอม
Sergio

2

Scrip นี้ใช้งานได้กับ 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
    }

1

คุณสามารถเพิ่มการตรวจสอบเพิ่มเติมตามการระบุตำแหน่งของเสาสัญญาณมือถือหรือข้อมูลจุดเชื่อมต่อ Wifi โดยใช้Google Maps Geolocation API

วิธีที่ง่ายที่สุดในการรับข้อมูลเกี่ยวกับ 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();
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.