IOS逆向(二)-绕过某租车app越狱和代理检测

因为日常使用shadowrocket,所以每次打开某租车app都会提示检测到手机开了代理,并且在越狱设备上打开还会直接闪退。如何绕过app的代理和越狱检测呢?
难度
★★☆☆☆
工具环境
- 越狱IOS 14.4
- frida-ios-dump
- frida
- frida-trace
- IDA 7.7
IDA逆向分析
通过砸壳得到app的maco文件,直接扔进ida里面分析。既然app做了越狱检测,那么先直接搜索 jail 相关的函数名。

确实存在越狱检测的函数,通过检查一些特定的文件和目录是否存在来判断设备是否已经越狱。”Cydia.app”是一个在越狱设备上常见的应用商店,而”/bin/bash”和”/usr/sbin/sshd”则表示设备已经获得了全面的文件系统访问权限。

检测的过程是通过NSFileManager的fileExistsAtPath:方法来实现的。如果检测到任何一个文件或目录存在,函数就会返回1,表示设备已经越狱。如果所有的文件和目录都不存在,函数就会返回0,表示设备没有越狱。
frida-trace hook越狱函数
看到这里大家可能会想到,那我直接用frida来hook越狱检测函数 +[_priv_NBSProbe isJailBreak]
不就可以了?
一开始我也是这样想的,所以直接用frida-trace进行hook。
frida-trace -U -f com.szzc.szzc -m "+[_priv_NBSProbe isJailBreak]"
修改hook代码如下,替换函数返回值为0绕过检测。
{ onEnter(log, args, state) { log(`进入 +[_priv_NBSProbe isJailBreak] 检测函数`); log(args[0]); }, onLeave(log, retval, state) { log('退出 +[_priv_NBSProbe isJailBreak] 检测函数'); retval.replace(0); } }

程序在进入该函数之前,已经退出了。说明是app还有其他的检测函数在该函数之前先执行并退出了。
定位程序退出的堆栈
如何定位程序退出时的堆栈?可以通过frida-trace来hook系统的exit或abort函数。
frida-trace -U -i "exit" -i "abort" -f com.szzc.szzc
并添加exit的js代码如下:
{ onEnter(log, args, state) { log(`exit(status=${args[0]})`); log('exit() called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n') + '\n'); }, onLeave(log, retval, state) { } }

frida打印程序退出时的堆栈,可以看到是在0x275d4b8的偏移地址执行退出的。
IDA分析程序退出的堆栈
这里解释一下frida打印的三个地址的含义。
0x1047994b8 WCCApp!0x275d4b8 (0x10275d4b8)
- 0x1047994b8 是程序在内存中实际的内存地址,因为存在地址空间布局随机化(ASLR),运行看到的地址都是相对于程序的基址的偏移,这个基址在每次运行时都会改变。
- 0x275d4b8 是该函数相对于基址的偏移地址
- 0x10275d4b8 是该函数在IDA中的地址,因为IDA的默认基址为0x100000000,0x10275d4b8 = 0x100000000 + 0x275d4b8
在IDA中来到0x10275d4b8的地址。

发现没有并不是判断异常的代码逻辑,来到堆栈的上一层0x100007464。

这里有几十个判断逻辑,可以看到越狱检测的和代理检测都有,应该是所有的检测都放到了一起,依次检测判断。从字符串可以推断是app集成了爱加密的sdk。
frida 踩坑
那么是否直接hook 0x7464 地址就行呢?
frida -U -l wcc.js -f com.szzc.szzc
wcc.js 代码如下:
var baseAddr = Module.findBaseAddress('WCCApp'); var offsetAddr = 0x7464 // 0x100007464 var targetAddr = baseAddr.add(offsetAddr); console.log("WCCApp 基址: " + baseAddr); console.log("目标函数地址: " + targetAddr); Interceptor.attach(targetAddr, { onEnter: function(args) { console.log("函数hook成功!"); console.log(' called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n') + '\n'); this.skip = true; }, onLeave: function(retval) { console.log("Function execution finished."); } });

这里frida执行没有打印出堆栈信息是为什么呢?

frida hook函数需要对函数名的偏移地址然后在基址上添加,而不是函数内部的偏移地址。

为什么用frida给的偏移地址hook不成功?
查看函数的交叉应用。


这里我推测是上层函数中调用里面用了异步方法导致的。
交叉应用定位外层函数调用

再往上查找一层,IDA能识别出这是一个objc的方法。

绕过越狱检测
到这一步思路就很清晰了,直接用frida 来hook这个函数然后把把sub_100007008替换成一个空函数就行。重新写一个frida脚本为wcc_jail.js
var baseAddr = Module.findBaseAddress('WCCApp'); console.log("WCCApp base address: " + baseAddr); //0x7008是sub_100007008越狱检测函数的偏移地址 var targetFunctionAddr = baseAddr.add(0x7008); console.log("Target function address: " + targetFunctionAddr); const targetFunction = new NativeFunction(targetFunctionAddr, 'void', []); // 把sub_100007008替换成一个空函数 Interceptor.replace(targetFunctionAddr, new NativeCallback(function () { console.log("Skip the execution of sub_100007008"); }, 'void', [])); //0x8A24是-[RootViewController viewDidLoad]的偏移地址 const targetFunctionAddrRootVC = baseAddr.add(0x8A24); Interceptor.attach(targetFunctionAddrRootVC, { onEnter: function (args) { console.log('Entering -RootViewController viewDidLoad!'); }, onLeave: function (retval) { console.log('Leaving -RootViewController viewDidLoad!'); } });
执行命令如下:
frida -U -l wcc_jail.js -f com.szzc.szzc

效果演示
微信赞赏
支付宝赞赏
发表评论