首页
社区
课程
招聘
[原创]你的游戏签名校验被绕过?罪魁祸首可能是他!SRPatch iohook重定向
发表于: 6天前 339

[原创]你的游戏签名校验被绕过?罪魁祸首可能是他!SRPatch iohook重定向

6天前
339

APK 校验为什么会失效:你读到的可能不是它


很多人第一次做 APK 防护,都会先想到几个词:


AES、HMAC、签名证书、SHA-256。


这些东西当然重要。但有一个更基础的问题经常被忽略:


校验代码读到的文件,真的就是手机上正在运行的那份 APK 吗?


如果答案是否定的,那么算法写得再复杂,也可能是在检查一份假的文件。


先举一个大家更容易遇到的例子,几乎所有游戏都遭到此类工具欺骗过!这些人本质就是利用安逸的乌托邦环境来批量侵扰 实际连怎么过的都不知道

包括目前手游榜排行前3的上亿用户项目"原省"WY某盾!都会被此类欺骗!外挂作者获取到游戏补丁或者关键hook位置和内存特征就会打包游戏直装批量传播 甚至欺骗绕过服务端受信校验!建议所有手游从业者技术及时通过几分钟时间下载np管理器等工具自查!看看校验是否通过,这是手游被2次打包最热门的场景!甚至是千万级用户的软件都会被骗过


很多游戏修改者并不会自己分析 APK,也不会自己写 Hook。拿到游戏以后,直接交给某些管理器类的一键工具处理,点几下就能完成过签名、重打包,集成lgl开源等菜单再安装到手机里,依托健全的外挂生态,前者都帮他们修好了路,本质上就是耍流氓行为


以常见的 NP 管理器类工具为例,它们往往把很多步骤都藏在按钮后面:读取 APK、处理签名、替换或加载组件、再把结果安装起来。使用者不一定知道底层发生了什么,只会看到“原来打不开的修改包,现在能启动了”。


这里真正值得关注的不是工具界面,而是它可能改变了应用读取自身 APK 的方式。应用以为自己在检查修改后的文件,校验代码实际拿到的却可能是另一份原始内容。


下面不讨论怎么使用这类工具,只从防守角度说明:为什么一键工具能做到这一点,以及应用应该检查什么。


从文件管理器里打开处理后的 APK,通常能看到一个很直观的现象:APK 本质上就是一个压缩包,里面有 assets、lib、classes.dex 和 base.apk 等内容。有些工具还会在处理过程中保留一份工作副本,或者把原始 APK 放在另一个位置供后续读取。


对普通使用者来说,表面上只是“点了一键处理”;但从文件层面看,可能已经同时出现了:


- 一份被修改、准备安装的 APK;

- 一份没有修改过、用于对照或读取的原始 APK;

- 工具自己的配置、补丁或临时文件。


截图里看到 APK 内部存在多个目录和文件,只能说明它被作为压缩包展开或浏览过,不能单凭目录名判断具体工具的完整工作流程。真正需要防守的是:应用运行时打开的文件,是否就是当前安装的这一份,而不是旁边被保留的另一份。


一、先看攻击者是怎么做的


假设一个应用启动时要检查自己的 APK。


它可能会这样做:


1. 找到 APK 路径;

2. 打开 APK;

3. 读取签名或某个 SO;

4. 算一个 SHA-256;

5. 和程序里保存的结果比较。


正常情况下,程序读到的是当前安装的 APK。


但如果手机里有一个过签名工具,它可以在程序调用文件接口的时候插一脚。


程序想读取修改后的 APK,工具就把这个请求转到另一份没有修改过的 APK 上。


于是程序看到的是:


    程序:我要打开当前 APK。

    工具:可以,给你。

    程序:我要读取这段内容。

    工具:可以,给你原始内容。


最后的结果就变成了:


- APK 实际上已经被改过;

- 校验代码没有被改;

- 但校验代码拿到的是另一份内容;

- 所以校验仍然显示正常。


这时候,攻击者甚至不需要破解 AES,也不需要研究 HMAC 是怎么计算的。


他只需要让校验代码“看错文件”。


二、为什么只用普通文件接口容易被绕


Android Native 程序经常通过 libc 提供的 open、read、pread 等接口读文件。


这样写代码很方便,兼容性也好。


但这些接口在用户态,比较容易被 Hook。


如果程序所有读取都走这一条路,攻击者只需要盯住这一条路:


    校验代码

        |

        v

    普通文件接口

        |

        v

    被替换的内容


所以,签名算法没有错,不代表结果一定可信。


因为程序可能从一开始就没有读到真正的 APK。


三、一个简单的防法:再读一次


既然第一条读取路径可能被改,那就不要只相信它。


可以在 Native 里再准备一条不同的读取路径。


第一条路径继续使用普通 libc 接口,保证正常手机上的兼容性。


第二条路径不依赖 libc 的普通封装,而是尝试从更底层请求内核读取文件。


这里要特别说明:绕开 libc 不代表一定绕过所有 Hook。


如果工具只处理 libc,第二条路径可能拿到不同的数据,从而暴露重定向。


但如果工具已经进入更底层的 SVC 或系统调用拦截阶段,第二条路径同样可能被观察、修改或重定向。因此,不能把“底层调用成功”直接当成“读到的就是真实文件”。


然后让两条路径读取同一个文件的同一个位置:


    普通路径  ─────┐

                   ├── 比较读取结果

    底层路径  ─────┘


如果两边拿到的内容一样,只能说明这一次抽查没有发现差异,并不能证明读取路径绝对没有被处理。


如果一边拿到的是修改后的内容,另一边拿到的是原始内容,就说明中间很可能有人动过读取过程。


面对更高等级的系统调用拦截,防守方还需要增加其它独立检查,例如文件描述符实际指向、APK 映射关系、证书和原生库摘要。核心不是寻找一条永远不会被 Hook 的接口,而是让攻击者必须同时伪造多类结果。


实际中没必要把整个 APK 读两遍,可以只抽查几个位置,例如:


- APK 目录附近;

- 签名附近;

- 完整性数据附近;

- 随机挑选的一小段位置。


这样速度不会太慢,也不容易被简单规则直接猜中。


四、为什么“读不到”不能马上退出


这里很容易做错。


底层读取并不是每台手机都一定成功。可能有这些情况:


- 系统限制了底层调用;

- ROM 的行为不一样;

- 双开或容器改了 APK 路径;

- 进程看不到某些 /proc 信息;

- 32 位和 64 位的参数规则不同。


如果底层读取失败就直接结束应用,正常用户也可能打不开软件;而且在更高等级的系统调用拦截环境中,失败本身也不能直接说明发生了攻击。


所以要区分两件事:


第一种:没有读到。


这只能说明当前环境不方便检查,不能证明用户在攻击。一般应该记录一下,然后继续普通签名和文件校验。


第二种:两条路径都读成功了,但结果不一样。


这就不是“环境不支持”了,而是比较明确的读取被替换迹象,可以进入拦截流程。


简单说:


    读不到,不一定有问题;

    同一个位置读出两份不同内容,问题就比较大。


五、文件描述符也可能骗人


还有一种情况:程序调用 open 看起来成功了,但拿到的文件描述符其实指向另一份文件。


所以还可以检查一下:


- 这个文件描述符实际指向哪里;

- 它是不是当前 APK;

- 进程里映射的 APK 和它是不是同一个文件;

- 文件的基本属性有没有明显异常。


不过这类检查不能太死。


双开、沙箱、插件化环境本来就可能让路径和文件属性看起来不一样。


如果只是“信息没拿到”,不要直接退出。


只有在明确发现“程序要打开 A,实际打开的是 B”时,才应该把它当作强证据。


六、为什么要随机抽查


如果每次都检查固定位置,攻击者很容易写规则:


“程序读到这里时,就返回准备好的内容。”


所以每次构建时可以生成一些随机材料,用它们算出本次 APK 的检查位置。


这样不同 APK 的检查位置不完全一样,简单的通用脚本就不容易直接套用。


但随机抽查不是无敌的。


如果攻击者能够动态调试程序,还是可能慢慢找到读取位置。


它的作用只是让批量绕过更麻烦,不是保证永远绕不过。对于已经具备 SVC 或系统调用级处理能力的工具,随机点只能增加工作量,不能单独成为安全结论。


七、还可以看看程序周围有没有异常


除了比较读取结果,还可以看看一些旁证:


- APK 里有没有过签名工具留下的异常配置;

- 进程里有没有可疑的注入模块;

- 文件描述符、APK 映射和真实文件是否对应;

- 当前进程和应用身份是否一致。


但不要只依赖一个字符串。


因为字符串可以改名,也可能误报。


比较稳妥的方式是:多个证据分别检查,只有拿到比较明确的证据时才拦截。


八、双通道不能代替签名校验


两条读取路径解决的是一个问题:


“我读到的内容是不是真的?”


签名、HMAC 和 SHA-256 解决的是另一个问题:


“这份内容有没有被改?”


这两件事不能互相替代。


只做签名校验,读取被重定向时可能检查错文件。


只做双通道读取,文件内容本身仍然可能被修改。


比较完整的做法应该是:


1. 读取完整性数据;

2. 验证完整性数据没有被换;

3. 检查发布证书;

4. 检查关键 SO 或资源的摘要;

5. 对关键位置做两条路径的读取比较;

6. 根据证据决定是否继续运行。


九、它能防什么


这种方法主要针对的是比较简单的过签名方式:


- 只 Hook 普通文件接口;

- 把读取请求转到原始 APK;

- 只处理固定的几个读取位置;

- 直接替换校验文件或校验库。


它不能保证挡住所有高手。


如果攻击者可以修改 Native 分支、动态改返回值、转储解密后的代码,或者控制更底层的系统环境,用户态保护仍然可能被绕过。


所以不要把它说成“绝对防破解”。


更准确的说法是:


它让攻击者不能只改一个接口、换一份文件就轻松通过,同时也让批量工具更难直接套用。


十、最后说一句


APK 防护里最容易犯的错误,是只盯着算法,不看数据从哪里来。


你算 SHA-256 之前,应该先问一句:


“我算的,真的是当前这份文件吗?”


如果普通读取可能被替换,那就增加一条不同实现的读取路径,并把它当作交叉证据,而不是绝对可信的路径。


如果底层检查失败,不要马上误杀正常用户。


如果两条路径读到不同内容,再把它当成重点问题。


最后,再配合签名证书、HMAC、SO 摘要和多点校验,才能形成比较实际的防护。


这类方案的价值,不是让攻击者永远没有办法,而是让“改一个接口、换一份文件、批量套规则”不再那么简单。

最好的办法还是配合检测游戏必须的文件属性 如classes.dex等assets 修改者要破坏必须要面临万里挑一的筛选和多重绕过的成本


依托多年底层对抗经验,我们的安全团队在针对手游安卓鸿蒙进行定制化调优,,以及其严格的检测方式多步校验配合内核直连通道复合apk读取 识别此类以及io hook 过签名行为 发现异常通道自动降级。实现零误判设计多重致信点 强java层绑定 引擎内链接入 保证极强的全渠道发版情况下 反复校验包体是否被篡改,一旦篡改立刻崩溃,游戏型和软件接入后,拥有极强的兼容性,符合目前安卓以及谷歌鸿蒙的适配方案 开发者通过自有证书密钥可自新重签测试 支持v1 v2 v3 方案 反降证书绕过 so通过高级加密 媲美业内顶尖运行时自解密方案 防止被绕过 开发者可以通过web同时接入 Matrix V3 运行时模块 反制多重外挂注入作弊 替换 dump 内存膨胀反修改器超过28种云控游戏型调优方案 将流氓行为彻底阻拦


另外 我想向您继续表述

通过金丝雀团队 攻击侧小组多年对抗经验

我们集所有集合检测矛盾点

倾力研发

全引擎通用反运行时模块数据段篡改策略 

该策略开启后

无需对引擎进行额外修改参数

游戏热更新场景 将不会出现误报拦截行为

当游戏运行时 

修改者通过dump.cs

获取偏移地址后 跳转对应运行时模块 

 修改偏移基地址打补丁篡改行为  立刻触发静默破坏 游戏退出 

 这无疑是给dump存储游戏元数据后修改对应方法补丁的外挂制作者 进行毁灭性打击 


在我们的最新调研当中 

目前国内所有的手游安全模块组件

 都无法反制 运行时模块被打补丁行为

 外挂可肆意修改运行时游戏cocojs.so lib2cpp.so等模块来达到无敌,秒杀,作弊,加速,穿墙等功能 

 而金丝雀团队已经把此策略上架至企业安全控制台当中

开启此策略您的游戏运行时将会被加上双重保险

重签启动后0.1秒崩溃





传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

最后于 1天前 被霸服w编辑 ,原因:
收藏
免费 1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回