iOS 识别虚拟定位调研

最近业务开发中,有遇到我们的项目app定位被篡改的情况,在android端表现的尤为明显。为了防止这种黑产使用虚拟定位薅羊毛,iOS也不得不进行虚拟定位的规避。
在做技术调研后,发现在苹果手机上,单凭一部手机,真正要实现虚拟定位,是比较难实现的,但还是有存在的可能性,公司的一个项目app的bugly记录反馈用户存在使用越狱苹果手机,这就着实让人这种行为实在有大嫌。
本人和公司伙伴的共同努力下,大致调研了以下使用虚拟定位的情况:

第一种:使用越狱手机。

一般app用户存在使用越狱苹果手机的情况,一般可以推断用户的行为存在薅羊毛的嫌疑(也有app被竞品公司做逆向分析的可能),因为买一部越狱的手机比买一部正常的手机有难度,且在系统升级和appstore的使用上,均不如正常手机,本人曾经浅浅的接触皮毛知识通过越狱iPhone5s进行的app逆向。

识别方式:

建议一刀切的方式进行,通过识别手机是否安装了Cydia.app,如果安装了直接判定为越狱手机,并向后台上报“设备异常”的信息。如果不使用这种方式的方式,请继续看,后面会有其他方式解决。专业的逆向人员是绝对可以避免app开发者对Cydia的安装检测的,当然这种情况是app在市场上有很大的份量,被竞争对手拿来进行逆向分析,对这种情况,虚拟的识别基本毫无意义。个人建议,直接锁死停掉此手机app的接口服务。这里推荐一篇开发者如何识别苹果手机已经越狱的文章

第二种:使用爱思助手。

对于使用虚拟定位的场景,大多应该是司机或对接人员打卡了。而在这种场景下,就可能催生了一批专门以使用虚拟定位进行打卡薅羊毛的黑产。对于苹果手机,目前而言,能够很可以的实现的,当数爱思助手的虚拟定位功能了。

使用步骤:下载爱思助手mac客户端,连接苹果手机,工具箱中点击虚拟定位,即可在地图上选定位,然后点击修改虚拟定位即可实现修改地图的定位信息。

原理:在未越狱的设备上通过电脑和手机进行USB连接,电脑通过特殊协议向手机上的DTSimulateLocation服务发送模拟的坐标数据来实现虚假定位,目前Xcode上内置位置模拟就是借助这个技术来实现的。( 文章来源

识别方式:

第一种:通过多次记录爱思助手的虚拟定位的数据发现,其虚拟的定位信息的经纬度的高度是为0且经纬度的数据位数也是值得考究的。真实定位和虚拟定位数据如下图:

真实定位.png

虚拟定位.png

仔细观察数据,不难发现,如果我们比对获取定位信息的高度,以及对经纬度的double位数也进行校验,虚拟定位的黑帽子就会轻易被破了。那么如果我们比对虚拟定位的高度为0时,就认定为虚拟定位,那么就会产生一个疑问,真实海拔就是零的地点,如何解决?这里科普下中国的海拔零度位置,中国水准零点位于青岛市东海中路银海大世界内的“中华人民共和国水准零点”,是国内唯一的水准零点。唯一的水准零点。同时,因为比对经纬度的double位数,发现虚拟定位的位数很明显不对,核对swift的float和double的位数精度发现,虚拟定位的经纬度数据只是敷衍的满足double精度位数,swift的float有效位数是7,double的有效位数是15。当然这个比较的权重是相对高度比较低的,笔者刚刚更新爱思助手版本发现新版本经纬度有更详细,但是还是达不到double的有效位数级别。相对于目前的爱思助手的高度比较识别为虚拟定位,已经完全可以做到

精度.png

代码实现:

       if location.altitude == 0.0 {
            print("虚拟定位")
        }

        //位数作为判定的权重比,如果位数小于12(假定值,目前爱思助手的虚拟定位的此数据的位数是9),判断为虚拟定位,
        //危险慎用,但是作为小权重的异常数据记录还是可以的
        let longitude = location.coordinate.longitude
        let longitudeStr = "\(longitude)".components(separatedBy: ".").last ?? ""

        print("经度的有效位数:\(longitudeStr.count)")
        if longitudeStr.count < 12 {

            print("虚拟定位")
        }
                
复制代码

第二种: 把定位后的数据的经纬度上传给后台,后台再根据收到的经纬度获取详细的经纬度信息,对司机的除经纬度以外的地理信息进行深度比较,优先比较altitude、horizontalAccuracy、verticalAccuracy值,根据值是否相等进行权衡后,确定。

第三种:

(一)通过获取公网ip,大概再通过接口根据ip地址可获取大概的位置,但误差范围有点大。

    //获取公网ip地址
    var ipAddress: String? {
        
        let ipUrl = URL(string: "https://ipof.in/txt")!
        let ip = try? String.init(contentsOf: ipUrl, encoding: .utf8)

        return ip
    }
复制代码

(二)通过Wi-Fi热点来读取app位置

(三)利用CLCircularRegion设定区域中心的指定经纬度和可设定半径范围,进行监听。

(四)通过IBeacon技术,使用 CoreBluetooth 框架下的CBPeripheralManager建立一个蓝牙基站。这种定位直接是端对端的直接定位,省去了GPS的卫星和蜂窝数据的基站通信。

第四种(待完善):
此文章的末尾附的解法本人有尝试过,一层一层通过kvc读取CLLocation的_internal的fLocation,只能读取到到此。再通过kvc读取会报以下错误:

Expression can't be run, because there is no JIT compiled function
复制代码

深入研究,再苹果的官方开发文档上发现了这个解释,也有说设置debug+优化策略的,但iOS默认bug环境就是-Onone级别的。其实主要原因貌似因为JIT的设置是在开发mac客户端的时候,才能在Signing&Capabilities的Hardened Runtime中找到关于Allow Execution of JIT-compiled Code的设置(官方文章)。最终只能卡到这里,若有大神能通过读取私有变量的方式,还请不吝赐教。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享