轉載:https://blog.csdn.net/tslx1020/article/details/128250777 1、spawn - 冷啟動 frida-trace -U -f com.apple.ExampleCode -m “+[NSURL URLWithString:]" 2、attac ...
轉載:https://blog.csdn.net/tslx1020/article/details/128250777
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:
{
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[i].toString(16))
if(hextemp.length == 1){
hextemp = "0" + hextemp
}
str += hextemp;
}
log(`CC_MD5(${this.args0.readUtf8String()})`); // 入參
log(`CC_MD5()=${str}=`); // 返回值
}
}
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}=`);
}
}
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}=`);
}
}
加密函數AES、DES、3DES
frida-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")
}
}
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) {
}
}
15.修改方法的入參
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) {
}
}
16、修改方法的返回值
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}=`);
}
}
17、列印字元串、數組、字典
frida-trace -UF -m “-[DetailViewController setObj:]”
{
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) {
}
}
18、列印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) {
}
}
19、列印對象的所有屬性和方法
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[i]}=`);
}
},
onLeave(log, retval, state) {
}
}
20、列印調用棧
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) {
}
}
21、日誌輸出到文件
frida-trace -UF -m “+[NSURL URLWithString:]” -o run.log
22、更多數據類型
/**
* 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;