飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2036|回复: 5

[iOS] 【iOS逆向与安全】frida-trace命令大全

[复制链接]
  • TA的每日心情
    无聊
    2021-11-11 13:50
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2022-11-22 12:49:08 | 显示全部楼层 |阅读模式
    Frida-trace常用命令
    1、spawn - 冷启动$ frida-trace -U -f com.apple.ExampleCode -m "+[NSURL URLWithString:]"
    2、attach - 热启动$ frida-trace -UF -m "+[NSURL URLWithString:]"
    3、Hook类方法$ frida-trace -UF -m "+[NSURL URLWithString:]"
    4、Hook实例方法$ frida-trace -UF -m "-[NSURL host]"
    5、Hook类的所有方法$ frida-trace -UF -m "*[NSURL *]"
    6、模糊Hook类的所有方法$ frida-trace -UF -m "*[*service* *]"
    7、模糊Hook所有类的特定方法$ frida-trace -UF -m "*[* *sign*]"
    8、模糊Hook所有类的特定方法并忽略大小写
    假设我们要hook所有类中包含getSign或getsign关键词的方法
    $ frida-trace -UF -m "*[* get?ign]"
    9、模糊Hook所有类的特定方法并排除viewDidLoad方法$ frida-trace -UF -m "*[DetailViewController *]" -M "-[DetailViewController viewDidLoad]"
    10、Hook某个动态库$ frida-trace -UF -I "libcommonCrypto*"
    11、Hook get或post的接口地址$ frida-trace -UF -m "+[NSURL URLWithString:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        var args2 = new ObjC.Object(args[2]);
        log(`-[NSURL URLWithString:${args2}]`);
      },
      onLeave(log, retval, state) {
      }
    }
    12、Hook post的body$ frida-trace -UF -m "-[NSMutableURLRequest setHTTPBody:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        var args2 = new ObjC.Object(args[2]);
        log(`-[NSMutableURLRequest setHTTPBody:${args2.bytes().readUtf8String(args2.length())}]`);
      },
      onLeave(log, retval, state) {
      }
    }
    13、Hook即将显示页面$ frida-trace -UF -m "-[UINavigationController pushViewController:animated:]" -m "-[UIViewController presentViewController:animated:completion:]"
    pushViewController:animated:方法的js代码如下:
    {
      onEnter(log, args, state) {
        var args2 = new ObjC.Object(args[2]);
        log(`-[UINavigationController pushViewController:${args2.$className} animated:${args[3]}]`);
      },
      onLeave(log, retval, state) {
      }
    }
    presentViewController:animated:completion:方法对应的js代码如下:
    {
      onEnter(log, args, state) {
        var args2 = new ObjC.Object(args[2]);
        log(`-[UIViewController presentViewController:${args2.$className} animated:${args[3]} completion:${args[4]}]`);
      },
      onLeave(log, retval, state) {
      }
    }
    14、Hook MD5函数$ frida-trace -UF -i "CC_MD5"
    js代码如下:
    {
      onEnter(log, args, state) {
        this.args0 = args[0];        // 入参
        this.args2 = args[2];        // 返回值指针
      },
      onLeave(log, retval, state) {
        var ByteArray = Memory.readByteArray(this.args2, 16);
        var uint8Array = new Uint8Array(ByteArray);

        var str = "";
        for(var i = 0; i < uint8Array.length; i++) {
            var hextemp = (uint8Array.toString(16))
            if(hextemp.length == 1){
                hextemp = "0" + hextemp
            }
            str += hextemp;
        }
        log(`CC_MD5(${this.args0.readUtf8String()})`);           // 入参
        log(`CC_MD5()=${str}=`);                                                                                                        // 返回值
      }
    }
    15、Hook Base64编码方法$ frida-trace -UF -m "-[NSData base64EncodedStringWithOptions:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        this.self = args[0];
      },
      onLeave(log, retval, state) {
        var before = ObjC.classes.NSString.alloc().initWithData_encoding_(this.self, 4);
        var after = new ObjC.Object(retval);
        log(`-[NSData base64EncodedStringWithOptions:]before=${before}=`);
        log(`-[NSData base64EncodedStringWithOptions:]after=${after}=`);
      }
    }
    16、Hook Base64解码方法$ frida-trace -UF -m "-[NSData initWithBase64EncodedData:options:]" -m "-[NSData initWithBase64EncodedString:options:]"
    initWithBase64EncodedData:options:方法对应的js代码如下:
    {
      onEnter(log, args, state) {
        this.arg2 = args[2];
      },
      onLeave(log, retval, state) {
        var before = ObjC.classes.NSString.alloc().initWithData_encoding_(this.arg2, 4);
        var after = ObjC.classes.NSString.alloc().initWithData_encoding_(retval, 4);
        log(`-[NSData initWithBase64EncodedData:]before=${before}=`);
        log(`-[NSData initWithBase64EncodedData:]after=${after}=`);
      }
    }
    initWithBase64EncodedString:options:方法对应的js代码如下:
    {
      onEnter(log, args, state) {
        this.arg2 = args[2];
      },
      onLeave(log, retval, state) {
        var before = new ObjC.Object(this.arg2);
        var after = ObjC.classes.NSString.alloc().initWithData_encoding_(retval, 4);
        log(`-[NSData initWithBase64EncodedString:]before=${before}=`);
        log(`-[NSData initWithBase64EncodedString:]after=${after}=`);
      }
    }

    17、Hook加密函数AES、DES、3DESfrida-trace -UF -i CCCrypt
    js代码如下:
    {
            onEnter: function(log, args, state) {
                    this.op = args[0]
                    this.alg = args[1]
                    this.options = args[2]
                    this.key = args[3]
                    this.keyLength = args[4]
                    this.iv = args[5]
                    this.dataIn = args[6]
                    this.dataInLength = args[7]
                    this.dataOut = args[8]
                    this.dataOutAvailable = args[9]
                    this.dataOutMoved = args[10]

                    log('CCCrypt(' +
                            'op: ' + this.op + '[0:加密,1:解密]' + ', ' +
                            'alg: ' + this.alg + '[0:AES128,1:DES,2:3DES]' + ', ' +
                            'options: ' + this.options + '[1:ECB,2:CBC,3:CFB]' + ', ' +
                            'key: ' + this.key + ', ' +
                            'keyLength: ' + this.keyLength + ', ' +
                            'iv: ' + this.iv + ', ' +
                            'dataIn: ' + this.dataIn + ', ' +
                            'inLength: ' + this.inLength + ', ' +
                            'dataOut: ' + this.dataOut + ', ' +
                            'dataOutAvailable: ' + this.dataOutAvailable + ', ' +
                            'dataOutMoved: ' + this.dataOutMoved + ')')

                    if (this.op == 0) {
                            log("dataIn:")
                            log(hexdump(ptr(this.dataIn), {
                                    length: this.dataInLength.toInt32(),
                                    header: true,
                                    ansi: true
                            }))
                            log("key: ")
                            log(hexdump(ptr(this.key), {
                                    length: this.keyLength.toInt32(),
                                    header: true,
                                    ansi: true
                            }))
                            log("iv: ")
                            log(hexdump(ptr(this.iv), {
                                    length: this.keyLength.toInt32(),
                                    header: true,
                                    ansi: true
                            }))
                    }
            },
            onLeave: function(log, retval, state) {
                    if (this.op == 1) {
                            log("dataOut:")
                            log(hexdump(ptr(this.dataOut), {
                                    length: Memory.readUInt(this.dataOutMoved),
                                    header: true,
                                    ansi: true
                            }))
                            log("key: ")
                            log(hexdump(ptr(this.key), {
                                    length: this.keyLength.toInt32(),
                                    header: true,
                                    ansi: true
                            }))
                            log("iv: ")
                            log(hexdump(ptr(this.iv), {
                                    length: this.keyLength.toInt32(),
                                    header: true,
                                    ansi: true
                            }))
                    } else {
                            log("dataOut:")
                            log(hexdump(ptr(this.dataOut), {
                                    length: Memory.readUInt(this.dataOutMoved),
                                    header: true,
                                    ansi: true
                            }))
                    }
                    log("CCCrypt did finish")
            }
    }
    18、Hook加密函数RSA
    rsa加密有公钥加密和私钥加密两种方式
    $ frida-trace -UF -i "SecKeyEncrypt" -i "SecKeyRawSign"
    SecKeyEncrypt公钥加密函数对应的js代码如下:
    {
      onEnter(log, args, state) {
        // 由于同一条加密信息可能会多次调用该函数,故在这输出该函数的调用栈。可根据栈信息去分析上层函数
        log(`SecKeyEncrypt()=${args[2].readCString()}=`);
        log('SecKeyEncrypt called from:\n' +
            Thread.backtrace(this.context, Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n') + '\n');
      },
      onLeave(log, retval, state) {
      }
    }
    SecKeyRawSign私钥加密函数对应的js代码如下:
    {
      onEnter(log, args, state) {
        log(`SecKeyRawSign()=${args[2].readCString()}=`);
        log('SecKeyRawSign called from:\n' +
            Thread.backtrace(this.context, Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n') + '\n');
      },
      onLeave(log, retval, state) {
      }
    }
    19、修改方法的入参$ frida-trace -UF -m "-[DetailViewController setObj:]"
    js代码如下:
    /*
    * Auto-generated by Frida. Please modify to match the signature of -[DetailViewController setObj:].
    * This stub is currently auto-generated from manpages when available.
    *
    * For full API reference, see: https://frida.re/docs/javascript-api/
    */

    {
      /**
       * Called synchronously when about to call -[DetailViewController setObj:].
       *
       * @this {object} - Object allowing you to store state for use in onLeave.
       * @param {function} log - Call this function with a string to be presented to the user.
       * @param {array} args - Function arguments represented as an array of NativePointer objects.
       * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
       * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
       * @param {object} state - Object allowing you to keep state across function calls.
       * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
       * However, do not use this to store function arguments across onEnter/onLeave, but instead
       * use "this" which is an object for keeping state local to an invocation.
       */
      onEnter(log, args, state) {
        var self = new ObjC.Object(args[0]);  // 当前对象
        var method = args[1].readUtf8String();  // 当前方法名
        log(`[${self.$className} ${method}]`);

        // 字符串
        // var str = ObjC.classes.NSString.stringWithString_("hi wit!")  // 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
        // args[2] = str  // 修改入参为字符串

        // 数组
        // var array = ObjC.classes.NSMutableArray.array();  // 对应的oc语法:NSMutableArray array = [NSMutablearray array];
        // array.addObject_("item1");  // 对应的oc语法:[array addObject:@"item1"];
        // array.addObject_("item2");  // 对应的oc语法:[array addObject:@"item2"];
        // args[2] = array; // 修改入参为数组

        // 字典
        // var dictionary = ObjC.classes.NSMutableDictionary.dictionary(); // 对应的oc语法:NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
        // dictionary.setObject_forKey_("value1", "key1"); // 对应的oc语法:[dictionary setObject:@"value1" forKey:@"key1"]
        // dictionary.setObject_forKey_("value2", "key2"); // 对应的oc语法:[dictionary setObject:@"value2" forKey:@"key2"]
        // args[2] = dictionary; // 修改入参为字典

        // 字节
        var data = ObjC.classes.NSMutableData.data(); // 对应的oc语法:NSMutableData *data = [NSMutableData data];
        var str = ObjC.classes.NSString.stringWithString_("hi wit!")  // 获取一个字符串。 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
        var subData = str.dataUsingEncoding_(4);  // 将str转换为data,编码为utf-8。对应的oc语法:NSData *subData = [str dataUsingEncoding:NSUTF8StringEncoding];
        data.appendData_(subData);  // 将subData添加到data。对应的oc语法:[data appendData:subData];
        args[2] = data; // 修改入参字段

        // 更多数据类型:https://developer.apple.com/documentation/foundation
      },

      onLeave(log, retval, state) {

      }
    }
    20、修改方法的返回值$ frida-trace -UF -m "-[DetailViewController Obj]"
    js代码如下:
    {
      onEnter(log, args, state) {

      },
      onLeave(log, retval, state) {
        // 字符串
        var str = ObjC.classes.NSString.stringWithString_("hi wit!")  // 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
        retval.replace(str)  // 修改返回值
        var after = new ObjC.Object(retval); // 打印出来是个指针时,请用该方式转换后再打印
        log(`before:=${retval}=`);
        log(`after:=${after}=`);
      }
    }
    21、打印字符串、数组、字典$ frida-trace -UF -m "-[DetailViewController setObj:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        var self = new ObjC.Object(args[0]);  // 当前对象
        var method = args[1].readUtf8String();  // 当前方法名
        log(`[${self.$className} ${method}]`);

        var before = args[2];
        // 注意,日志输出请直接使用log函数。不要使用console.log()
        var after = new ObjC.Object(args[2]); // 打印出来是个指针时,请用该方式转换后再打印
        log(`before:=${before}=`);
        log(`after:=${after}=`);
      },
      onLeave(log, retval, state) {

      }
    }
    22、打印NSData$ frida-trace -UF -m "-[DetailViewController setObj:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        var self = new ObjC.Object(args[0]);  // 当前对象
        var method = args[1].readUtf8String();  // 当前方法名
        log(`[${self.$className} ${method}]`);

        var before = args[2];

        // 注意,日志输出请直接使用log函数。不要使用console.log()
       
        var after = new ObjC.Object(args[2]); // 打印NSData
        var outValue = after.bytes().readUtf8String(after.length()) // 将data转换为string
        log(`before:=${before}=`);
        log(`after:=${outValue}=`);
      },
      onLeave(log, retval, state) {

      }
    }
    23、打印对象的所有属性和方法$ frida-trace -UF -m "-[DetailViewController setObj:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        var self = new ObjC.Object(args[0]);  // 当前对象
        var method = args[1].readUtf8String();  // 当前方法名
        log(`[${self.$className} ${method}]`);

        var customObj = new ObjC.Object(args[2]); // 自定义对象
        // 打印该对象所有属性
        var ivarList = customObj.$ivars;
        for (key in ivarList) {
           log(`key${key}=${ivarList[key]}=`);
        }

        // 打印该对象所有方法
        var methodList = customObj.$methods;
        for (var i=0; i<methodList.length; i++) {
           log(`method=${methodList}=`);
        }
      },
      onLeave(log, retval, state) {

      }
    }
    24、打印调用栈$ frida-trace -UF -m "+[NSURL URLWithString:]"
    js代码如下:
    {
      onEnter(log, args, state) {
        var url = new ObjC.Object(args[2]);
        log(`+[NSURL URLWithString:${url}]`);
        log('NSURL URLWithString: called from:\n' +
            Thread.backtrace(this.context, Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n') + '\n');
      },
      onLeave(log, retval, state) {
      }
    }
    25、日志输出到文件$ frida-trace -UF -m "+[NSURL URLWithString:]" -o run.log
    26、更多数据类型/**
    * Converts to a signed 32-bit integer.
    */
      toInt32(): number;

      /**
      * Converts to an unsigned 32-bit integer.
      */
      toUInt32(): number;

      /**
      * Converts to a “0x”-prefixed hexadecimal string, unless a `radix`
      * is specified.
      */
      toString(radix?: number): string;

      /**
      * Converts to a JSON-serializable value. Same as `toString()`.
      */
      toJSON(): string;

      /**
      * Returns a string containing a `Memory#scan()`-compatible match pattern for this pointer’s raw value.
      */
      toMatchPattern(): string;

      readPointer(): NativePointer;
      readS8(): number;
      readU8(): number;
      readS16(): number;
      readU16(): number;
      readS32(): number;
      readU32(): number;
      readS64(): Int64;
      readU64(): UInt64;
      readShort(): number;
      readUShort(): number;
      readInt(): number;
      readUInt(): number;
      readLong(): number | Int64;
      readULong(): number | UInt64;
      readFloat(): number;
      readDouble(): number;
      readByteArray(length: number): ArrayBuffer | null;
      readCString(size?: number): string | null;
      readUtf8String(size?: number): string | null;
      readUtf16String(length?: number): string | null;
    以上就是关于frida-trace在iOS端的常用命令,希望能帮助到大家。同时也建议大家阅读官方文档:https://frida.re/docs/frida-trace/

    提示:阅读此文档的过程中遇到任何问题,请关注公众号【移动端Android和iOS开发技术分享】或加QQ群【812546729



    评分

    参与人数 2威望 +3 飘云币 +3 收起 理由
    LuckyClover + 1 + 1 PYG有你更精彩!
    不破不立 + 2 + 2 PYG有你更精彩!

    查看全部评分

    PYG19周年生日快乐!
  • TA的每日心情
    开心
    昨天 09:32
  • 签到天数: 2178 天

    [LV.Master]伴坛终老

    发表于 2022-11-22 14:17:41 | 显示全部楼层
    楼主整理不易,收藏备用
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2024-2-14 23:29
  • 签到天数: 49 天

    [LV.5]常住居民I

    发表于 2022-11-22 18:05:14 | 显示全部楼层
    非常好,总结的很到位的
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 10:36
  • 签到天数: 522 天

    [LV.9]以坛为家II

    发表于 2022-11-23 08:42:58 | 显示全部楼层
    感谢科普,收藏备用
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    昨天 21:31
  • 签到天数: 424 天

    [LV.9]以坛为家II

    发表于 2022-11-23 20:21:25 | 显示全部楼层

    感谢科普,收藏备用
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    难过
    前天 09:03
  • 签到天数: 510 天

    [LV.9]以坛为家II

    发表于 2022-11-24 15:42:08 | 显示全部楼层
    过来学习,多谢!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表