小工具知识网

当前位置: 首页 > 行业知识 > 【iOS安全】越狱iOS安装Frida | 安装指定版本Frida | Frida使用

行业知识

【iOS安全】越狱iOS安装Frida | 安装指定版本Frida | Frida使用

2026-11-04 18:23:09 来源:互联网转载

越狱iPhone安装Frida

本文的方法适用于已越狱的iPhone手机

打开Cydia,软件源,编辑(右上角),添加(左上角):https://build.frida.re

然后搜索Frida,点击安装

参考:https://blog.csdn.net/boildoctor/article/details/122769942

安装指定版本Frida

iOS上的Frida版本需要和PC上的Frida版本保持一致,所以有时候需要安装指定版本Frida

下载指定版本deb包:

https://github.com/frida/frida/releases

例如:frida_15.2.2_iphoneos-arm.deb

通过XFTP将deb拷贝至手机/private/var/tmp目录(也就是/tmp目录)

ssh进入手机 /tmp目录,执行安装:

dpkg -i xx.deb

参考:https://cloud.tencent.com/developer/article/2160543

使用Frida

在iPhone上启动Frida-server后,将iPhone通过USB连接至PC

PC上安装Frida,通过命令行输入命令 或 运行脚本

frida-ls-devices 查看电脑连接的iOS设备信息

frida-ps 查看正在运行的应用

USB连接

frida-ps -Ua

Wi-Fi连接

frida-ps -H 10.168.1.34:6666 -a

frida hook 类函数

  • 函数名以”+”开头的,如:“+ URLWithString:”,可以直接通过类名调用方法,相当于java中的static函数
    #coding=utf-8import 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的appsession = device.attach(pid) #附加到appscript = 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]表示取找到的实例中的第一个实例,可根据实际情况换成其他的实例。

        #coding=utf-8import 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的appsession = device.attach(pid) #附加到appscript = session.create_script(jscode) #创建frida javaScript脚本script.load() #load脚本到app进程中 这样即注入成功device.resume(pid) #恢复app运行sys.stdin.read()#读取打印日志

        参考:https://mabin004.github.io/2018/08/24/%E5%9C%A8iOS%E4%B8%8A%E4%BD%BF%E7%94%A8Frida/

        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连接代码如下:

        # frida-ps -H 10.168.1.34:6666 -abundle = 'com.unionpay.chsp'# wifi连接# ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666str_host = '10.168.1.34:6666'manager = frida.get_device_manager()device = manager.add_remote_device(str_host)pid = device.spawn([bundle]) #启动指定bundleId的appsession = device.attach(pid) #附加到appscript = session.create_script(jscode) #创建frida javaScript脚本script.load() #load脚本到app进程中 这样即注入成功device.resume(pid) #恢复app运行sys.stdin.read()#读取打印日志

        frida USB连接

        对比之下,USB连接部分代码如下:

        # frida-ps -Uabundle = 'com.unionpay.chsp'# usb连接device = frida.get_usb_device() #连接usb设备 参数:超时时长pid = device.spawn([bundle]) #启动指定bundleId的appsession = device.attach(pid) #附加到appscript = session.create_script(jscode) #创建frida javaScript脚本script.load() #load脚本到app进程中 这样即注入成功device.resume(pid) #恢复app运行sys.stdin.read()#读取打印日志

        完整代码如下:

        #coding=utf-8import 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 -Uabundle = '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:6666str_host = '10.168.1.34:6666'manager = frida.get_device_manager()device = manager.add_remote_device(str_host)pid = device.spawn([bundle]) #启动指定bundleId的appsession = device.attach(pid) #附加到appscript = session.create_script(jscode) #创建frida javaScript脚本script.load() #load脚本到app进程中 这样即注入成功device.resume(pid) #恢复app运行sys.stdin.read()#读取打印日志

        frida-trace

        模糊匹配

        hook 所有类的- userContentController:didReceiveScriptMessage:函数,可以用*进行模糊匹配

        // 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’])

        # frida-ps -H 10.168.1.34:6666 -abundle = 'com.tencent.live4iphone'# ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666str_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) #附加到appscript = session.create_script(jscode) #创建frida javaScript脚本script.load() #load脚本到app进程中 这样即注入成功device.resume(pid) #恢复app运行sys.stdin.read()#读取打印日志

        Attach模式在已启动app情况下注入

        关键代码:

        pid = device.get_process(“腾讯视频”).pid

        # frida-ps -H 10.168.1.34:6666 -aprocessName = "腾讯视频"# wifi连接# ssh执行 /usr/sbin/frida-server -l 0.0.0.0:6666str_host = '10.168.1.34:6666'manager = frida.get_device_manager()device = manager.add_remote_device(str_host)pid = device.get_process(processName).pidsession = device.attach(pid) #附加到appscript = session.create_script(jscode) #创建frida javaScript脚本script.load() #load脚本到app进程中 这样即注入成功device.resume(pid) #恢复app运行sys.stdin.read()#读取打印日志

        具体类的处理

        打印WKScriptMessage的内容
        // console.log('arg3: ' + ObjC.Object(args[3]).toString());// 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);

        例如:

            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()); //             // console.log('arg3: ' + ObjC.Object(args[3]).toString()); //             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');        }    });
        替换字符串参数的值
          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() );    }  }

上一篇:上游服务器错误怎么解决?

下一篇:淘宝客网站源码全解析,轻松搭建,开启你的电商事业大门!