- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章谈谈 iOS 识别虚拟定位调研由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
最近业务开发中,有遇到我们的项目 app 定位被篡改的情况,在 android 端表现的尤为明显。为了防止这种黑产使用虚拟定位薅羊毛,iOS 也不得不进行虚拟定位的规避.
在做技术调研后,发现在苹果手机上,单凭一部手机,真正要实现虚拟定位,是比较难实现的,但还是有存在的可能性,公司的一个项目 app 的 bugly 记录反馈用户存在使用越狱苹果手机,这就着实让人这种行为实在有大嫌.
本人和公司伙伴的共同努力下,大致调研了以下使用虚拟定位的情况(使用 Xcode 虚拟定位的方式本文忽略):
第一种:使用越狱手机 。
一般 app 用户存在使用越狱苹果手机的情况,一般可以推断用户的行为存在薅羊毛的嫌疑(也有 app 被竞品公司做逆向分析的可能),因为买一部越狱的手机比买一部正常的手机有难度,且在系统升级和 appstore 的使用上,均不如正常手机,本人曾经浅浅的接触皮毛知识通过越狱 iPhone5s 进行的 app 逆向.
识别方式 。
建议一刀切的方式进行,通过识别手机是否安装了 Cydia.app,如果安装了直接判定为越狱手机,并向后台上报“设备异常”的信息。如果不使用这种方式的方式,请继续看,后面会有其他方式解决.
专业的逆向人员是绝对可以避免 app 开发者对 Cydia 的安装检测的,当然这种情况是 app 在市场上有很大的份量,被竞争对手拿来进行逆向分析,对这种情况,虚拟的识别基本毫无意义。个人建议,直接锁死停掉此手机 app 的接口服务。这里推荐一篇开发者如何识别苹果手机已经越狱[1]的文章.
代码实现 。
第二种:使用爱思助手 。
对于使用虚拟定位的场景,大多应该是司机或对接人员打卡了。而在这种场景下,就可能催生了一批专门以使用虚拟定位进行打卡薅羊毛的黑产。对于苹果手机,目前而言,能够很可以的实现的,当数爱思助手的虚拟定位功能了.
使用步骤: 下载爱思助手 mac 客户端,连接苹果手机,工具箱中点击虚拟定位,即可在地图上选定位,然后点击修改虚拟定位即可实现修改地图的定位信息.
原理: 在未越狱的设备上通过电脑和手机进行 USB 连接,电脑通过特殊协议向手机上的 DTSimulateLocation 服务发送模拟的坐标数据来实现虚假定位,目前 Xcode 上内置位置模拟就是借助这个技术来实现的。(文章来源[2]) 。
识别方式 。
1、通过多次记录爱思助手的虚拟定位的数据发现,其虚拟的定位信息的经纬度的高度是为 0 且经纬度的数据位数也是值得考究的。真实定位和虚拟定位数据如下图:
真实定位 。
虚拟定位 。
仔细观察数据,不难发现,如果我们比对获取定位信息的高度,以及对经纬度的 double 位数也进行校验,虚拟定位的黑帽子就会轻易被破了.
那么如果我们比对虚拟定位的高度为 0 时,就认定为虚拟定位,那么就会产生一个疑问,真实海拔就是零的地点,如何解决?这里科普下中国的海拔零度位置,中国水准零点位于青岛市东海中路银海大世界内的“中华人民共和国水准零点”,是国内唯一的水准零点。唯一的水准零点.
同时,因为比对经纬度的 double 位数,发现虚拟定位的位数很明显不对,核对 swift 的 float 和 double 的位数精度发现,虚拟定位的经纬度数据只是敷衍的满足 double 精度位数,swift 的 float 有效位数是 7,double 的有效位数是 15.
当然这个比较的权重是相对高度比较低的,笔者刚刚更新爱思助手版本发现新版本经纬度有更详细,但是还是达不到 double 的有效位数级别。相对于目前的爱思助手的高度比较识别为虚拟定位,已经完全可以做到.
代码实现 。
2、把定位后的数据的经纬度上传给后台,后台再根据收到的经纬度获取详细的经纬度信息,对司机的除经纬度以外的地理信息进行深度比较,优先比较 altitude、horizontalAccuracy、verticalAccuracy 值,根据值是否相等进行权衡后,确定.
3、 。
(一)通过获取公网 ip,大概再通过接口根据 ip 地址可获取大概的位置,但误差范围有点大.
(二)通过 Wi-Fi 热点来读取 app 位置[3] 。
(三)利用 CLCircularRegion 设定区域中心的指定经纬度和可设定半径范围,进行监听.
代码简略实现:
(四)通过 IBeacon 技术,使用 CoreBluetooth 框架下的 CBPeripheralManager 建立一个蓝牙基站。这种定位直接是端对端的直接定位,省去了 GPS 的卫星和蜂窝数据的基站通信.
代码简略实现:
四(待完善)、 iOS防黑产虚假定位检测技术 文章的末尾附的解法本人有尝试过,一层一层通过 kvc 读取 CLLocation 的 _internal 的 fLocation,只能读取到到此。再通过 kvc 读取会报以下错误:
深入研究,在苹果的官方开发文档上发现了这个解释[4],也有说设置 debug+ 优化策略的,但 iOS 默认 bug 环境就是 -Onone 级别的。其实主要原因貌似因为 JIT 的设置是在开发 mac 客户端的时候,才能在 Signing&Capabilities 的 Hardened Runtime 中找到。关于 Allow Execution of JIT-compiled Code 的设置(官方文章[5])。最终只能卡到这里,若有大神能通过其他方式读取 CLLocation 的真实定位(这是极其完美的解决方案),还请不吝赐教.
附:
CLLocation 对象私有变量 _internal 实例对象的官方定义[6]:
参考资料 。
[1]用代码判断 iOS 系统是否越狱的方法: https://www.huaweicloud.com/articles/7c6b8027253c4a97196d359840f638d9.html 。
[2]iOS 防黑产虚假定位检测技术: https://cloud.tencent.com/developer/article/1800531 。
[3]Wifi 定位原理及 iOS Wifi 列表获取: http://www.caojiarun.com/2017/01/iOS_Wifilist/ 。
[4]Allow Execution of JIT-compiled Code Entitlement: https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit 。
[5]Hardened Runtime: https://developer.apple.com/documentation/security/hardened_runtime 。
[6]_internal 实例对象的官方定义: https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/CoreLocation.framework/CLLocationInternal.h 。
原文地址:https://mp.weixin.qq.com/s/ZbZ4pFzzyfrQifmLewrxsw 。
最后此篇关于谈谈 iOS 识别虚拟定位调研的文章就讲到这里了,如果你想了解更多关于谈谈 iOS 识别虚拟定位调研的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有WHERE 1=1有什么作用如果您在脚本(伪代码)中编写此请求: sql = "SELECT f1,f2,f3 FROM t WHERE 1=1" ++ restOfTheClause
这个问题已经有答案了: R: Convert delimited string into variables (3 个回答) 已关闭 5 年前。 我有一个包含电影数据的表,在最后一列中,它包含电影所属
假设我有一个基类: struct A{ virtual void foo() = 0; }; 然后假设我有一个这样的派生类: struct B : public virtual A{ voi
我有一个小问题,我的 << 运算符没有被正确调用。 这是我的: class SomeInterface { friend std::ostream& operator<<(std::ostrea
首先,我来自 Java 社区,并且仍然是 C++ 的学习者。 请看下面的类 第二张图片显示了类“GameObject”的子类。它还有一个 Display() 方法。 GameObject类有5个子类,
我这里遇到了一些问题。我试图让我的代码像 java 中的接口(interface)一样工作。这个类被其他 2 个继承,因为它们导致了一些问题。而且我还想知道我是否做对了,以及改进我的代码的方法。我是新
在 C++ 中,我有一个基类 A,一个子类 B。两者都有虚方法 Visit。我想在 B 中重新定义“访问”,但 B 需要访问每个 A(以及所有子类)的“访问”功能。 我有类似的东西,但它告诉我 B 无
我有一个抽象类,它是类层次结构的根。该根类有一个带有一些简单实现的方法,似乎没有必要随时随地更改该实现。 使该方法成为非虚方法很好,但是某些子类可能会意外地重新实现它。在这种情况下,虚拟 final方
在 MSDN 上,我发现在抽象方法声明中使用“virtual”修饰符是错误的。我的一位同事应该是非常有经验的开发人员,但他在他的代码中使用了这个: public abstract class Busi
C++ 虚函数表是仅用于确定调用虚函数时应该执行哪一段代码,还是在运行时有其他用途? 在维基百科上,它列出了“动态调度”作为一个原因,但没有深入了解 C++ 的更多细节...... 最佳答案 一些实现
页面大小是否恒定?更具体地说,getconf PAGE_SIZE 给出 4096,这很公平。但这可以通过程序的运行时间改变吗?或者它在整个操作系统进程生成过程中是否保持不变。 IE。 , 进程是否可能
析构函数(当然还有构造函数)和其他成员函数之间的区别在于,如果常规成员函数在派生类中具有主体,则仅执行派生类中的版本。而在析构函数的情况下,派生版本和基类版本都会被执行? 很高兴知道在析构函数(可能是
如果一个函数被定义为虚函数并且与纯虚函数相同,这究竟意味着什么? 最佳答案 来自 Wikipedia's Virtual function... In object-oriented programm
我有一个在 Jetty 下运行的应用程序,我希望该应用程序返回自引用绝对 URL(生成 RSS 提要时,因此客户端必须能够在没有“当前 URL”上下文的情况下工作)。 问题是我事先不知道应用程序将部署
如何在两个virtualtreeview之间复制以复制所有列,而不仅仅是第一列? 复制前: 复制后: 最佳答案 树控件不保存任何数据。它不包含要显示的列数据,因此无法复制它。而是,当树控件想要显示任何
我已将 ShowHint 设置为 true 并将 HintMode 设置为 hmToolTip,但是当我将光标悬停在控件上时,我的 OnGetHint() 事件处理程序甚至没有断点。 知道我做错了什么
我的 friend 正在 Delphi 中使用 VirtualTreeView 工作,并且遇到了下一个问题:他有两列,第一列的每一行都有数据和子项。是否可以不更改第一列宽度来设置最大子列宽度? 图例:
我在我的 Virtual TreeView Component 中使用 TVirtualStringTree ( Delphi project 的一部分)我想创建一个 View ,其中 2 列可以有可
我想遍历 VirtualTreeView 的所有根并将其删除。 我不想清除它。 我收到此代码的访问冲突: var Node : PVirtualNode; begin if VirtualStri
我有一个可以输出表单的 PHP 文件。我想在服务器端调用这个 PHP 文件(当前使用“include”),填写并提交。 这样更好,因此我不必干预实际的 PHP 表单,只需处理表示层,以便数据可以被它自
我是一名优秀的程序员,十分优秀!