Loading... 本文的方法适用于已越狱的iPhone手机 打开Cydia,[软件源](https://so.csdn.net/so/search?q=%E8%BD%AF%E4%BB%B6%E6%BA%90&spm=1001.2101.3001.7020),编辑(右上角),添加(左上角):https://build.frida.re ![image.png](http://type.zimopy.com/usr/uploads/2024/07/2998839671.png) ![image.png](http://type.zimopy.com/usr/uploads/2024/07/717459922.png) ![image.png](http://type.zimopy.com/usr/uploads/2024/07/2287304276.png) 然后搜索[Frida](https://so.csdn.net/so/search?q=Frida&spm=1001.2101.3001.7020),点击安装 ![image.png](http://type.zimopy.com/usr/uploads/2024/07/4017649359.png) ### 安装指定版本Frida iOS上的Frida版本需要和PC上的Frida版本保持一致,所以有时候需要安装指定版本Frida 下载指定版本deb包: https://github.com/frida/frida/releases ![image.png](http://type.zimopy.com/usr/uploads/2024/07/167165925.png) 通过finalshell将deb拷贝至手机`/private/var/tmp`目录(也就是`/tmp`目录) cd进入 `/tmp`目录,执行安装: ```shell dpkg -i xx.deb ``` ### 使用Frida 在iPhone上启动Frida-server后,将iPhone通过USB连接至PC PC上安装Frida,通过命令行输入命令 或 运行脚本 #### frida-ls-devices 查看电脑连接的iOS设备信息 ![image.png](http://type.zimopy.com/usr/uploads/2024/07/29812900.png) #### frida-ps 查看正在运行的应用 ##### USB连接 frida-ps -Ua ![image.png](http://type.zimopy.com/usr/uploads/2024/07/3932958838.png) ##### Wi-Fi连接 frida-ps -H 10.168.1.34:6666 -a ![image.png](http://type.zimopy.com/usr/uploads/2024/07/2209134807.png) #### frida hook 类函数 * 函数名以”+”开头的,如:“+ URLWithString:”,可以直接通过类名调用方法,相当于java中的static函数 ```javascript #coding=utf-8 import frida, sys jscode = """ if(ObjC.available){ console.log('\\n[*] Starting Hooking'); var _className = "JDJR_HackersInfo"; var _methodName = "+ judgementJailbreak"; var hooking = ObjC.classes[_className][_methodName]; console.log('className is: ' + _className + ' and methodName is: ' + _methodName); Interceptor.attach(hooking.implementation,{ onEnter: function(args) { //args[0]:self //args[1]:The selector //args[2]:第一个参数 console.log(' hook success ') this._className = ObjC.Object(args[0]).toString(); this._methodName = ObjC.selectorAsString(args[1]); // console.log('Detected call to: '); // console.log('[-] Detected call to: ' + this._className + ' --> ' + this._methodName); // console.log('\\n----------------' + this._methodName + '----------------'); // console.log('arg2:\\n' + ObjC.Object(args[2]).toString()); //console.log('called from:\\n' + Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n'); //print_arguments(args); }, //onLeave.function(returnValue)被拦截函数调用之后回调 其中returnValue表示原始函数的返回值 onLeave:function(returnValue){ // console.log('Return value of: '); // console.log(' ' + this._className + ' --> ' + this._methodName); // var typeValue = Object.prototype.toString.call(returnValue); // console.log("\\t Type of return value: " + typeValue); // console.log("\\t Return Value: " + returnValue); console.log("old Return Value: " + ObjC.Object(returnValue)); var newRet = ObjC.classes.NSString.stringWithString_("1"); returnValue.replace(newRet); console.log("new Return Value: " + ObjC.Object(returnValue)); } }); } """ bundle = 'xxx.xxx.xxx' device = frida.get_usb_device() #连接usb设备 参数:超时时长 pid = device.spawn([bundle]) #启动指定bundleId的app session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` frida hook 实例函数 函数名以“-”开头的需要找到一个实例化的对象,然后再调用方法 如果内存中没有这样的对象 这种情况需要手动生成一个实例,用法为ObjC.classes.类名.alloc() 如果内存中存在实例化后的对象 这种情况需要先找出一个类的实例,使用var tmp=ObjC.chooseSync(ObjC.classes.类名),例如: ObjC.chooseSync(ObjC.classes.PARSHealthPedometer10thHomeViewController)[0] 其中[0]表示取找到的实例中的第一个实例,可根据实际情况换成其他的实例。 ```javascript #coding=utf-8 import frida, sys jscode = """ if(ObjC.available){ console.log('\\n[*] Starting Hooking'); // setToken: 有内容 var _className = "WLRequestInfo"; var _methodName = "- setToken:"; // var hookingclass = ObjC.chooseSync(ObjC.classes[_className])[0]; //如果内存中存在实例化后的对象,需要先找出一个类的实例 var hookingclass = ObjC.classes[_className].alloc(); //如果内存中没有实例化后的对象,手动实例化 var hooking = hookingclass[_methodName]; console.log('className is: ' + _className + ' and methodName is: ' + _methodName); Interceptor.attach(hooking.implementation,{ onEnter: function(args) { //args[0]:self //args[1]:The selector //args[2]:第一个参数 // console.log(' hook success ') this._className = ObjC.Object(args[0]).toString(); this._methodName = ObjC.selectorAsString(args[1]); // console.log('Detected call to: '); // console.log('[-] Detected call to: ' + this._className + ' --> ' + this._methodName); // console.log('\\n[-]' + this._className + ' --> ' + this._methodName + ' : '); console.log('\\n----------------' + this._methodName + '----------------'); console.log('arg2:\\n' + ObjC.Object(args[2])); console.log('called from:\\n' + Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n'); //print_arguments(args); }, //onLeave.function(returnValue)被拦截函数调用之后回调 其中returnValue表示原始函数的返回值 onLeave:function(returnValue){ // console.log('Return value of: '); // console.log(' ' + this._className + ' --> ' + this._methodName); // var typeValue = Object.prototype.toString.call(returnValue); // console.log("Type of return value: " + typeValue); // console.log("Return Value: " + returnValue); console.log("Return Value: \\n" + ObjC.Object(returnValue)); } }); } """ bundle = 'cn.gov.pbc.dcep' device = frida.get_usb_device() #连接usb设备 参数:超时时长 pid = device.spawn([bundle]) #启动指定bundleId的app session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` frida Wi-Fi连接 先使用ssh在iPhone上执行 /usr/sbin/frida-server -l 0.0.0.0:6666,开启6666端口 iPhone和PC连接至同一局域网 假设iPhone的IP为10.168.1.34,开启端口为6666,则wifi连接代码如下: ```javascript # frida-ps -H 10.168.1.34:6666 -a bundle = 'com.unionpay.chsp' # wifi连接 # ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666 str_host = '10.168.1.34:6666' manager = frida.get_device_manager() device = manager.add_remote_device(str_host) pid = device.spawn([bundle]) #启动指定bundleId的app session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` #### frida USB连接 对比之下,USB连接部分代码如下: ```javascript # frida-ps -Ua bundle = 'com.unionpay.chsp' # usb连接 device = frida.get_usb_device() #连接usb设备 参数:超时时长 pid = device.spawn([bundle]) #启动指定bundleId的app session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` 完整代码如下: ```javascript #coding=utf-8 import frida, sys jscode = """ if(ObjC.available){ console.log('\\n[*] Starting Hooking'); var _className = "CDVWKWebViewEngine"; var _methodName = "- userContentController:didReceiveScriptMessage:"; var hooking = ObjC.classes[_className][_methodName]; console.log('className is: ' + _className + ' and methodName is: ' + _methodName); Interceptor.attach(hooking.implementation,{ onEnter: function(args) { //args[0]:self //args[1]:The selector //args[2]:第一个参数 // console.log(' hook success ') // this._className = ObjC.Object(args[0]).toString(); // this._methodName = ObjC.selectorAsString(args[1]); // console.log('Detected call to: '); // console.log('[-] Detected call to: ' + this._className + ' --> ' + this._methodName); console.log('arg2: ' + ObjC.Object(args[2]).toString()); console.log('arg3: ' + ObjC.Object(args[3]).toString()); console.log('called from:\\n' + Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n'); } }); } """ # frida-ps -Ua bundle = 'com.unionpay.chsp' # usb连接 # device = frida.get_usb_device() #连接usb设备 参数:超时时长 # pid = device.spawn([bundle]) #启动指定bundleId的app # session = device.attach(pid) #附加到app # script = session.create_script(jscode) #创建frida javaScript脚本 # script.load() #load脚本到app进程中 这样即注入成功 # device.resume(pid) #恢复app运行 # sys.stdin.read()#读取打印日志 # wifi连接 # ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666 str_host = '10.168.1.34:6666' manager = frida.get_device_manager() device = manager.add_remote_device(str_host) pid = device.spawn([bundle]) #启动指定bundleId的app session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` #### frida-trace ##### 模糊匹配 hook 所有类的- userContentController:didReceiveScriptMessage:函数,可以用*进行模糊匹配 ```javascript // wifi连接 frida-trace -m "-[* userContentController:didReceiveScriptMessage:]" -H 10.168.1.34:6666 腾讯视频 // USB连接 frida-trace -m "-[* userContentController:didReceiveScriptMessage:]" -U 腾讯视频 ``` 其中"腾讯视频"是进程名,可以通过frida-ps -H 10.168.1.34:6666 -a获得 参考:https://www.jianshu.com/p/7a3ba7ae3c29 自定义处理逻辑 在执行frida-trace的文件夹下,会产生__handlers__文件夹 直接修改文件夹中的JS代码,即可生效 Spawn模式 和 Attach模式 Spawn模式直接启动app 关键代码: pid = device.spawn([‘com.tencent.live4iphone’]) ```javascript # frida-ps -H 10.168.1.34:6666 -a bundle = 'com.tencent.live4iphone' # ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666 str_host = '10.168.1.34:6666' manager = frida.get_device_manager() device = manager.add_remote_device(str_host) pid = device.spawn([bundle]) session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` Attach模式在已启动app情况下注入 关键代码: pid = device.get_process(“腾讯视频”).pid ```javascript # frida-ps -H 10.168.1.34:6666 -a processName = "腾讯视频" # wifi连接 # ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666 str_host = '10.168.1.34:6666' manager = frida.get_device_manager() device = manager.add_remote_device(str_host) pid = device.get_process(processName).pid session = device.attach(pid) #附加到app script = session.create_script(jscode) #创建frida javaScript脚本 script.load() #load脚本到app进程中 这样即注入成功 device.resume(pid) #恢复app运行 sys.stdin.read()#读取打印日志 ``` #### 具体类的处理 ##### 打印WKScriptMessage的内容 ```javascript // console.log('arg3: ' + ObjC.Object(args[3]).toString()); // <WKScriptMessage: 0x28eda47e0> var scriptMessage = ObjC.Object(args[3]); var scriptMessageBody = scriptMessage.body(); var bodyString = scriptMessageBody.toString(); if (bodyString.includes("handlername = getTreasureBoxReportTime;") || bodyString.includes("handlername = sendRadarLog;") || bodyString.includes("handlername = setClientLog;")) { return; } console.log("scriptMessageBody: " + scriptMessageBody); ``` 例如: ```javascript var _className = "KMYWKWebViewBridge"; var _methodName = "- userContentController:didReceiveScriptMessage:"; var hooking = ObjC.classes[_className][_methodName]; console.log('className is: ' + _className + ' and methodName is: ' + _methodName); Interceptor.attach(hooking.implementation, { onEnter: function (args) { //args[0]:self //args[1]:The selector //args[2]:第一个参数 // console.log(' hook success ') // this._className = ObjC.Object(args[0]).toString(); // this._methodName = ObjC.selectorAsString(args[1]); // console.log('Detected call to: '); // console.log('[-] Detected call to: ' + this._className + ' --> ' + this._methodName); // console.log('arg2: ' + ObjC.Object(args[2]).toString()); // <WKUserContentController: 0x285aa7ba0> // console.log('arg3: ' + ObjC.Object(args[3]).toString()); // <WKScriptMessage: 0x28eda47e0> var scriptMessage = ObjC.Object(args[3]); var scriptMessageBody = scriptMessage.body(); var bodyString = scriptMessageBody.toString(); if (bodyString.includes("handlername = getTreasureBoxReportTime;") || bodyString.includes("handlername = sendRadarLog;") || bodyString.includes("handlername = setClientLog;")) { return; } console.log("scriptMessageBody: " + scriptMessageBody); // console.log('called from:\\n' + Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n'); } }); ``` ##### 替换字符串参数的值 ```javascript onEnter(log, args, state) { // log(`-[NSMutableURLRequest setValue:${args[2]} forHTTPHeaderField:${args[3]}]`); // console.log('arg2: ' + ObjC.Object(args[2]).toString()); // console.log('arg3: ' + ObjC.Object(args[3]).toString()); // console.log("\n"); arg3 = ObjC.Object(args[3]); if (arg3.isEqualToString_('Cookie')) { args[2] = ObjC.classes.NSString.stringWithString_("xxx"); console.log('[*] New cookie value:'+ ObjC.Object(args[2]).toString() ); } } ``` 最后修改:2024 年 07 月 01 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏