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

2024-06-04 3740阅读

越狱iPhone安装Frida

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

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

【iOS安全】越狱iOS安装Frida | 安装指定版本Frida Frida使用 第1张【iOS安全】越狱iOS安装Frida | 安装指定版本Frida Frida使用 第2张【iOS安全】越狱iOS安装Frida | 安装指定版本Frida Frida使用 第3张

然后搜索Frida,点击安装

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

参考: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

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

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

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

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设备信息

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

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

USB连接

frida-ps -Ua

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

Wi-Fi连接

frida-ps -H 10.168.1.34:6666 -a

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

frida hook 类函数

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

        #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()#读取打印日志
        

        参考: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 -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连接部分代码如下:

        # 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()#读取打印日志
        

        完整代码如下:

        #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:函数,可以用*进行模糊匹配

        // 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 -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

        # 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的内容
        // 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() );
            }
          }
        

    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]