一种inlineHook检测方案
定义
inlinehook是修改内存中的机器码来实现hook的方式
我们用frida查看一个函数hook之前和hook之后的机器码,这里以open函数为例:
let bytes_count = 32
let address = Module.getExportByName("libc.so","open")
let before = ptr(address)
console.log("")
console.log("[*] before hook: ")
console.log(hexdump(before, {
offset: 0,
length: bytes_count,
header: true,
ansi: true
}));
let isOutput = false
Interceptor.attach(address, {
onEnter:function(args){
if(isOutput) return;
let after = ptr(address)
console.log("")
console.log("[*] after hook: ")
console.log(hexdump(after, {
offset: 0,
length: bytes_count,
header: true,
ansi: true
}))
isOutput = true
},
onLeave:function(retv){
}
});
hook之前:
hook之后:
可见,hook之后,函数开头的字节被修改了
思考
inlinehook只修改了内存中的机器码,而内存中的机器码是从文件加载而来的,所以我们可以将函数在内存中字节和本地对应的字节进行比较,如果不一致,那么可以认为内存中的字节被修改了,即被inlinehook了。
实现
#ifdef __LP64__
const char *lib_path = "/system/lib64/libc.so";
#else
const char *lib_path = "/system/lib/libc.so";
#endif
#define CMP_COUNT 8
const char *sym_name = "open";
struct local_dlfcn_handle *handle = static_cast<local_dlfcn_handle *>(local_dlopen(lib_path));
off_t offset = local_dlsym(handle,sym_name);
FILE *fp = fopen(lib_path,"rb");
char file_bytes[CMP_COUNT] = {0};
if(fp != NULL){
fseek(fp,offset,SEEK_SET);
fread(file_bytes,1,CMP_COUNT,fp);
fclose(fp);
}
void *dl_handle = dlopen(lib_path,RTLD_NOW);
void *sym = dlsym(dl_handle,sym_name);
int is_hook = memcmp(file_bytes,sym,CMP_COUNT) != 0;
local_dlclose(handle);
dlclose(dl_handle);
char text[128] = {0};
snprintf(text,128,"Function \"%s\" is Hook: %s",sym_name,is_hook ? "true" : "false");
这里local_
开头的函数是读取本地符号偏移库,库代码:https://github.com/luoyesiqiu/local_dlfcn
用frida hook测试demo:frida-trace -U -i "open" -f com.luoye.localdlfcn