5

【iOS逆向与安全】frida-trace入门 - 移动端小陈

 1 year ago
source link: https://www.cnblogs.com/witchan/p/16904169.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

frida-trace是一个用于动态跟踪函数调用的工具。支持android和ios。安装教程请参考官网。工欲善其事必先利其器。本文将以某App为示范,演示frida-trace的各种方法在iOS中的应用。


让看文章的你在使用frida-trace时更得心应手。

  • mac系统
  • frida:动态调试工具
  • 已越狱iOS设备:脱壳及frida调试

1.命令格式

frida-trace [options] target

iOS常用的可选参数:

// 设备相关
-D	连接到指定的设备,多个设备时使用。示例:frida-trace -D 555315d66cac2d5849408f53da9eea514a90547e -F 
-U	连接到USB设备,只有一个设备时使用。示例fria-trace -U -F

// 应用程序相关
-f	目标应用包名。spawn模式。示例:frida-trace -U -f com.apple.www
-F	当前正在运行的程序。attach模式示例。示例:frida-trace -U -F或frida-trae -UF
-n	正在运行的程序的名字。attach模式。示例:frida-trace -U -n QQ
-N	正在运行的程序的包名。attach模式。示例:frida-trace -U -N com.apple.www
-p	正在运行的程序的pid。attach模式。示例:frida-trace -U -p 2302
  
// 方法相关,以下参数在一条跟踪命令中可重复使用
-I	包含模块。示例:frida-trace -UF -I "libcommonCrypto*"
-X	不包含模块。示例:frida-trace -UF -X "libcommonCrypto*"
-i 	包含c函数。示例:frida-trace -UF -i "CC_MD5"
-x 	不包名c函数。示例:frida-trace -UF -i "*MD5" -x "CC_MD5"
-a 	包含模块+偏移跟踪。示例:frida-trace -UF -a 模块名\!0x7B7D48
-m 	包含某个oc方法。示例:frida-trace -UF -m "+[NSURL URLWithString:]"
-M 	不包含某个oc方法。示例:frida-trace -UF -M "+[NSURL URLWithString:]"
  
// 日志相关
-o	日志输出到文件。示例:frida-trace -UF -m "*[* URL*]" -o run.log

2.常用命令

frida-trace中的方法匹配命令支持模糊匹配,星号匹配0个或多个字符,问号匹配1个字符:

-m "-[NSURL *]"	// 匹配NSURL类的所有实例方法
-m "+[NSURL *]"	// 匹配NSURL类的所有类方法
-m "*[NSURL *]" // 匹配NSURL类的所有方法
-m "*[*URL *]"	// 匹配以URL结尾类的所有方法
-m "*[URL* *]" 	// 匹配以URL开头类的所有方法
-m "*[*URL* *]"	// 匹配包含URL的类的所有方法
-m "*[*URL* *login*]"	// 匹配包含URL的类的带login的所有方法
-m "*[????? *]"	// 匹配类名只有五个字符的类的所有方法

简而言之:

当你不确定你要跟踪的方法是类方法还是实例方法时,用星号代替

当你只知道部分类名时,不确定的地方用星号代替

当你只知道部分方法名时,不确定的地方用星号代替

当你不知道方法名时,直接用星号代替

当你不知道某个字母是大小写时,用问号代替

frida-trace命令会在当前目录生成./__handlers__/文件夹内生成对应函数的js代码。当你需要打印入参,返回值。或修改入参,返回值时,可编辑对应的js文件。

  • 打印或修改OC方法的入参

$ frida-trace -UF -m "-[DetailViewController setObj:]"
Instrumenting...
-[DetailViewController setObj:]: Auto-generated handler at "/Users/witchan/__handlers__/DetailViewController/setObj_.js"
Started tracing 1 function. Press Ctrl+C to stop.

js源码如下:

{
  onEnter(log, args, state) {
    var self = new ObjC.Object(args[0]);  // 当前对象
    var method = args[1].readUtf8String();  // 当前方法名
    log(`[${self.$className} ${method}]`);

    var isData = false;

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

    // array
    // var 

    // 数组
    // 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; // 修改入参
    isData = true;

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

    var before = args[2];

    // 注意,日志输出请直接使用log函数。不要使用console.log()
    if (isData) {
    	// 打印byte对象
      var after = new ObjC.Object(args[2]); // 打印NSData
      var outValue = after.bytes().readUtf8String(after.length()) // 将data转换为string
      log(`before:=${before}=`);
      log(`after:=${outValue}=`);
    } else {
    	// 打印字符串、数组、字段
      var after = new ObjC.Object(args[2]); // 打印出来是个指针时,请用该方式转换后再打印
      log(`before:=${before}=`);
      log(`after:=${after}=`);
    }

    // 如果是自定义对象时,使用以上方法无法打印时,请使用以下方法:
    // var customObj = new ObjC.Object(args[0]); // 自定义对象
    // // 打印该对象所有属性
    // 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[i]}=`);
    // }
  },
  onLeave(log, retval, state) {

  }
}

  • 修改OC方法的返回值

$ frida-trace -UF -m "-[DetailViewController obj]"
Instrumenting...
-[DetailViewController obj]: Loaded handler at "/Users/witchan/__handlers__/DetailViewController/obj.js"
Started tracing 1 function. Press Ctrl+C to stop.

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}=`);

    // 其他数据类型,请往上看
  }
}
  • 打印C函数的入参和返回值

$ frida-trace -UF -i "CC_MD5"
Instrumenting...
CC_MD5: Loaded handler at "/Users/witchan/__handlers__/libcommonCrypto.dylib/CC_MD5.js"
Started tracing 1 function. Press Ctrl+C to stop.

js源码如下:

{
  onEnter(log, args, state) {
    // 注意。c方法里的参数直接从下标0开始
    this.args0 = args[0];	
    this.args2 = args[2];
    this.backtrace = 'CC_MD5 called from:\n' +
        Thread.backtrace(this.context, Backtracer.ACCURATE)
        .map(DebugSymbol.fromAddress).join('\n') + '\n';
  },
  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[i].toString(16))
        if(hextemp.length == 1){
            hextemp = "0" + hextemp
        }
        str += hextemp;
    }
    log(`CC_MD5(${this.args0.readUtf8String()})`);   
    log(`CC_MD5()=${str}=`);
    log(this.backtrace);	// 打印函数调用栈
  }
}
  • 常用frida-trace命令

跟踪单个方法:frida-trace -UF -m "-[DetailViewController obj]"

跟踪多个方法:frida-trace -UF -m "-[DetailViewController obj]" -m "+[NSURL URLWithString:]"

跟踪某个类的所有方法:frida-trace -UF -m "*[DetailViewController *]"

跟踪某个类的所有方法并排除viewDidLoad方法:frida-trace -UF -m "*[DetailViewController *]" -M "-[DetailViewController viewDidLoad]"

跟踪整个App中包含sendMsg关键词的所有方法:frida-trace -UF -m "*[* *sendMsg*]"

需要忽略某个字母的大小写,请使用?代替sendMsg中的M:frida-trace -UF -m "*[* *send?sg*]"

日志过多时,可保存到文件:frida-trace -UF -m "*[* *sendMsg*]" -o run.log

跟踪某个动态库:frida-trace -UF -I "libcommonCrypto*"

跟踪某个c函数:frida-trace -UF -i "CC_MD5"

跟踪sub_1007B7D48函数:frida-trace -UF -a xxxxx\!0x7B7D48

以上就是关于frida-trace的基本使用,希望能帮助到大家。同时也建议大家阅读官方文档:https://frida.re/docs/frida-trace/

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

IMG_4048

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK