http://download.csdn.net/detail/lykseek/9478270 源码
1、hook的原理,大家可以自行查找。这里,只给出一个实践的例子。
2、这里所写的hook,是导入表hook。什么叫做导入表 hook呢:对于一个elf可执行文件,或者动态链接库文件(so),调用其他动态链接库中的函数的时候,实际上,就去一个表中去查找一个值,这个值就是该函数在线性地址中的偏移值。我们所做的,就是修改这个值。
举个例子来说,就是你在libjavacore.so中想要hook read这个函数,那么你就要去libjavacore.so中(加载到内存中),去寻找这个导入表,找到read这个函数的地址,然后改成自己的函数。
3、关键代码解析
static void start(const char *soname) {
void *handle = dlopen(soname, RTLD_LAZY);
if (handle == NULL) {
LOGE("load libcrypto.so failed!");
return;
}
SoInfo* info = (SoInfo*) handle;
modify_rel(info->base, info->strtab, info->symtab, info->plt_rel,
info->plt_rel_count);
dlclose(handle);
}
打开so
static void modify_rel(Elf32_Addr base, const char* strtab, Elf32_Sym* symtab,
Elf32_Rel* rel_start, size_t size) {
int i;
unsigned long start = (unsigned long) rel_start;
for (i = 0; i < size; i++) {
Elf32_Rel* rel = (Elf32_Rel*) (start + i * 8);
int ret = modify_rel_one(i, base, strtab, symtab, rel);
if (ret)
break;
}
}
从导入表中,查找到read函数的地址,进行修改
</pre><pre code_snippet_id="1630768" snippet_file_name="blog_20160331_5_8490424" name="code" class="html"><pre name="code" class="html">static int modify_rel_one(int i, Elf32_Addr base, const char* strtab,
Elf32_Sym* symtab, Elf32_Rel* rel) {
unsigned int type = ELF32_R_TYPE(rel->r_info);
unsigned int sym_idx = ELF32_R_SYM(rel->r_info);
unsigned reloc = (unsigned) (rel->r_offset + base);
char *sym_name = (char*) (strtab + symtab[sym_idx].st_name);
if (!strcmp(sym_name, "read")) {
LOGI("modify reloc to:%p", my_read);
//reloc中,是地址,改地址是存放的函数地址值
read_reloc = reloc;
unsigned int * va = (unsigned int*) reloc;
old_read = *va;
LOGI("reloc addr value:%0x", *va);
mmprotect(reloc);
*va = my_read;
LOGI("my read new location:%p", *va);
hooked = 1;
return 1;
}
return 0;
}
查找到,进行修改。由于代码段是可读可执行的,所以要修改为可写可读可执行的。
4、这个种hook,是在同一个进程中进行本地hook。如果,需要进行远程hook,那么需要root和注入技术的支持。可以把这段hook的代码,注入到远程进程中,然后执行。