Author: geneblue
Blog: https://geneblue.github.io/
什么是虚拟定位
简而言之,利用软硬件更改手机系统的定位数据,从而让目标 app 获取错误的定位信息
虚拟定位常用场景
- 上下班打卡
- 代购
- 朋友圈装逼
- 打车软件司机端抢单
- 社交类软件,附近人,把妹,钓凯子
凡是和位置相关的应用,均有一定的应用场景,尽情发挥群众的智慧
虚拟定位原理
经过调研 iOS 虚拟定位大概有三类技术路线:
动态库注入
iOS 越狱后,安装使用具备虚拟定位功能的越狱插件。在上帝模式下,越狱插件可以肆意劫持系统函数。或者在非越狱环境下,砸壳目标 app ipa 文件,重打包注入动态库。这两种方式本质是一致的,都是为了 app 进程运行时,注入运行动态库。
劫持 CoreLocation
中以下常用的获取定位信息的函数,即可篡改正常的定位数据:
1
2
3
4
5
6
7
8
9CLLocationManager->delegate()
CLLocationManager->initialize()
CLLocationManager->setDelegate()
CLLocationManager->startMonitoringSignificantLocationChanges()
CLLocationManager->startUpdatingHeading()
CLLocationManager->startUpdatingLocation()
CLLocationManager->stopMonitoringSignificantLocationChanges()
CLLocationManager->stopUpdatingHeading()
CLLocationManager->stopUpdatingLocation()
电脑端软件
做过 iOS 开发的同学,可以观察一下 xcode 上有一个 Simulate
location
的调试功能,这是方便 app 开发过程中测试定位代码。
我们可以使用这个功能来模拟定位。不过使用这种方式需要打开电脑,开启
xcode,然后再编写 GPX 文件,对于普通用户,这个门槛太高了。国内的一些 iOS
助手类软件,将 Simulate location
功能逆向出来,集成到自己的软件上,比如下面这个 iTools 软件:
闪电口外设
典型产品如位移精灵,不但具备虚拟定位能力,还具备充电宝功能,多种用途,很方便啊,有木有。
那这个东西是啥原理呢?
解释起来很简单,这也是苹果提供的功能,不是啥黑科技。通过苹果 MFi(Made
For iOS) 认证厂商会获得 MFI Accessory Interface
Specification
文档,其中描述了 USB 与外设之间的通讯协议
iAP2,该协议具备许多丰富的功能:
可以看到其中就有 location 定位功能,按照协议格式,发送对应位置数据,就可以更改定位信息。电脑端 xcode 是不是也是使用 iAP2 协议呢?xcode 实现文档没有公开过,所以这个是未知的。
检测方法
知道了,这三种虚拟定位方式,我们只要找到正常定位与虚拟定位之间的差异就可以做到检测了
动态库注入
有几个明显特征: - 越狱环境,安装越狱插件,其动态库会被注入到目标进程 - 非越狱环境下,砸壳目标ipa,注入动态库 - 劫持(HOOK)定位函数
越狱环境可以检查设备是否越狱,非越狱可以检查 app 是否被重打包。如此,检查定位函数是否被劫持比较关键
函数 HOOK 涉及 OC 语言的动态特性,主要利用了
method_exchangeImplementations()
将函数实现替换掉。被 HOOK
的函数,其 IMP 实现会被劫持到注入的动态库中,所以我们检查函数 IMP
实现是否是原始 module 即可判断是否被 HOOK 了。
1 | - (NSString *) getMethodIMPInfo:(NSString *) className, sel:(NSString *)sel { |
电脑端软件
使用电脑端软件虚拟定位时,app 获取定位信息与正常获取定位信息有差异。
正常获取定位的时代理方法会被执行 3 次: 1
2
3
4
5
6
7
8
92020-09-25 14:37:25.587317+0800 iOSApp[990:275020] 纬度为:22.996662, 经度为:113.328448
2020-09-25 14:38:00.158517+0800 iOSApp[990:275020] 高度为:23.031912
2020-09-25 14:38:04.869490+0800 iOSApp[990:275020] 水平精确度:65.000000, 垂直精确度:10.000000
2020-09-25 14:38:22.238887+0800 iOSApp[990:275020] 纬度为:22.996662, 经度为:113.328448
2020-09-25 14:38:23.784470+0800 iOSApp[990:275020] 高度为:23.031912
2020-09-25 14:38:25.844754+0800 iOSApp[990:275020] 水平精确度:65.000000, 垂直精确度:10.000000
2020-09-25 14:38:26.841710+0800 iOSApp[990:275020] 纬度为:22.996667, 经度为:113.328447
2020-09-25 14:38:26.842180+0800 iOSApp[990:275020] 高度为:23.047693
2020-09-25 14:38:26.842767+0800 iOSApp[990:275020] 水平精确度:65.000000, 垂直精确度:10.000000
使用xcode虚拟定位的 location 代理方法仅执行一次: 1
2
32020-09-25 07:41:57.466217+0100 iOSApp[1005:276293] 纬度为:51.509980, 经度为:-0.133700
2020-09-25 07:41:57.466404+0100 iOSApp[1005:276293] 高度为:0.000000
2020-09-25 07:41:57.466511+0100 iOSApp[1005:276293] 水平精确度:5.000000, 垂直精确度:-1.000000
多次实验后,发现以下特征:正常获取定位信息时,locationManager
代理方法会被回调 3 次,而虚拟定位,代理方法仅会被回调 1
次;正常定位可以获取海拔高度,水平精确度,垂直精确度,虚拟定位时,无法获取海拔高度,水平精确度,垂直精确度也是固定的错误值。以上两点可以作为检查依据。
闪电口外设
没有购买位移精灵,没有做测试,不过在 gayhub 上发现一份检查 iap2 外设定位的代码 iap2-location-checker
其主要思路也是检查定位数据的精度。还有一种思路是检查外设类型,获取外设的硬件信息,如 mac,manufacturer,brand 之类的信息,不过在高版本 iOS 中,需要额外申请权限,这里就没有实践了。