前言 frida-trace是一個用於動態跟蹤函數調用的工具。支持android和ios。安裝教程請參考官網。工欲善其事必先利其器。本文將以某App為示範,演示frida-trace的各種方法在iOS中的應用。 一、目標 讓看文章的你在使用frida-trace時更得心應手。 二、工具 mac系統 ...
前言
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
】