android trace
Art trace :hook artmethod
JNI trace : jnitrace
libc trace:frida-trace
syscall trace:strace https://mp.weixin.qq.com/s/PIiGZKW6oQnOAwlCqvcU0g
Wallbreaker: https://github.com/hluwa/Wallbreaker
批量hook
如何使用objection去批量hook和trace?比如一次性hook几千个类?
- 把~/.objection/objection.log删掉;
- 到objection界面中运行android hooking list classes,列出所有的类;
- 对新生成的~/.objection/objection.log文件进行过滤,比如只关心http相关的。cat objection.log|grep -i http
- 将输出结果保存到一个excel列中,前面补全android hooking watch class xxxxx,另存为文本文件。如附件所示
- 加载这个文件:objection -g com.android.settings explore -c "2.txt" ,这样一下子就hook上了几千个相关类的所有方法及其所有重载。
- 如果trace感兴趣的方法也是同理,android hooking search methods * ,会打印出所有的方法。
frida Script
延时注入(Latency injection)
固定时间之后注入
使用setTimeout() 方法,例如:3 秒(3000 毫秒)后弹出 "Hello" :
setTimeout(function(){ alert("Hello"); }, 3000);
// frida's javascript
setImmediate(function () {
setTimeout(native_hook, 5000)
})
在特定so库加载之后注入
有的库在程序启动时,并不会立刻加载。我们直接hook会提示无法找到此库,这时我们可以借助dlopen函数,在so库加载完成之后再去hook。hook框架如下:
Interceptor.attach(Module.findExportByName(null, "dlopen"), {
onEnter: function (args) {
this.path = Memory.readUtf8String(args[0]);
console.log("[*] import :" + this.path);
},
onLeave: function (retval) {
// libwukong_ua.so改为要hook的so库
if(!this.path.isNull() && !retval.isNull() && this.path.includes('libwukong_ua.so')) {
// 匿名函数hook,libwukong_ua.so改为要hook的so库,'0x426DE0'为函数在ida中查看的偏移地址
var fstatat = resolveAddress('libwukong_ua.so', '0x0', '0x426DE0');
Interceptor.attach(fstatat, {
onEnter: function (args) {
console.log("======= used! ======")
},
onLeave: function (retval) {
}
});
// 根据函数名Hook,'libwukong_ua.so'为库名, 'ssl3_send_client_certificate'为函数名
var fstatat = Module.findExportByName('libwukong_ua.so', 'ssl3_send_client_certificate');
Interceptor.attach(fstatat, {
onEnter: function (args) {
console.log("======= used! ======")
},
onLeave: function (retval) {
}
});
}
}
});
function resolveAddress(name, idaBase, idaAddr) {
var baseAddr = Module.findBaseAddress(name);
console.log('[+] BaseAddr of ' + name + ': ' + baseAddr);
// Calculate offset in memory from base address in IDA database
var offset = ptr(idaAddr).sub(idaBase);
// Add current memory base address to offset of function to monitor
var result = baseAddr.add(offset);
// Write location of function in memory to console
console.log('[+] Address in memory: ' + result);
return result;
}
格式化输出(Formatted printing)
Hook动态注册方法frida hook libart(RegisterNatives)
脚本详情见:https://github.com/lasting-yang/frida_hook_libart
function hook_RegisterNatives() {
var symbols = Module.enumerateSymbolsSync("libart.so");
var addrRegisterNatives = null;
for (var i = 0; i < symbols.length; i++) {
var symbol = symbols[i];
//_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
if (symbol.name.indexOf("art") >= 0 &&
symbol.name.indexOf("JNI") >= 0 &&
symbol.name.indexOf("RegisterNatives") >= 0 &&
symbol.name.indexOf("CheckJNI") < 0) {
addrRegisterNatives = symbol.address;
console.log("RegisterNatives is at ", symbol.address, symbol.name);
}
}
if (addrRegisterNatives != null) {
Interceptor.attach(addrRegisterNatives, {
onEnter: function (args) {
console.log("[RegisterNatives] method_count:", args[3]);
var env = args[0];
var java_class = args[1];
var class_name = Java.vm.tryGetEnv().getClassName(java_class);
//console.log(class_name);
var methods_ptr = ptr(args[2]);
var method_count = parseInt(args[3]);
for (var i = 0; i < method_count; i++) {
var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
var name = Memory.readCString(name_ptr);
var sig = Memory.readCString(sig_ptr);
var find_module = Process.findModuleByAddress(fnPtr_ptr);
console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));
}
}
});
}
}
setImmediate(hook_RegisterNatives);