android 逆向分析过程有时候需要hook dlopen和dlsym函数,打印调用的库或者函数名。
利用cydia substrate的动态库,或者thomasking大大的elf-arm-hook-library 两个都行,但是cydia 支持x86的hook,模拟器hook 比较方便(个人见解)。
我用的是cydia 实现的hook。具体如下,
//substrate.cpp
void *(*msfindsymbol)(msimageref image, const char *name);
msimageref(*msgetimagebyname)(const char *file);
void(*msjavahookmethod)(jnienv *jni, jclass _class, jmethodid methodid, void *function, void **result);
void(*mshookfunction)(void *symbol, void *replace, void **result);
void(*msjavahookclassload)(jnienv *jni, const char *name, void(*callback)(jnienv *, jclass, void *), void *data);
__attribute__((__constructor__)) static void _msinitialize()
{
void* handlesubdsub = dlopen("/system/lib/libsubstrate.so", rtld_now);
void* handlesubdvm = dlopen("/system/lib/libsubstrate-dvm.so", rtld_now);
if (handlesubdsub != null)
{
logd("***start dlsym methond***");
msgetimagebyname = (msimageref(*)(const char *file))dlsym(handlesubdsub, "msgetimagebyname");
msfindsymbol = (void*(*)(msimageref image, const char *name))dlsym(handlesubdsub, "msfindsymbol");
mshookfunction = (void(*)(void *symbol, void *replace, void **result))dlsym(handlesubdsub, "mshookfunction");
msjavahookclassload = (void(*)(jnienv *jni, const char *name, void(*callback)(jnienv *, jclass, void *), void *data))dlsym(handlesubdvm, "msjavahookclassload");
msjavahookmethod = (void(*)(jnienv *jni, jclass _class, jmethodid methodid, void *function, void **result)) dlsym(handlesubdvm, "msjavahookmethod");
logd("***end dlsym methond***");
}
else
{
loge("***open so file fail or can't find file!***");
}
}
以上代码:可以不用安装cydia的apk,把libsubstrate.so、 libsubstrate-dvm.so 两个动态库复制到 /system/lib/目录下。 直接调用 相关函数,elf-arm-hook-library 也有同样的方法自己实现。
hook dlopen 函数 就要获取 函数的地址:
//这个方法来自 android inject 用于获取地址
void* get_module_base(int pid, const char* module_name)
{
file *fp;
long addr = 0;
char *pch;
char filename[32];
char line[1024];
if (pid < 0) {
/* self process */
snprintf(filename, sizeof(filename), "/proc/self/maps", pid);
}
else {
snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
}
fp = fopen(filename, "r");
if (fp != null) {
while (fgets(line, sizeof(line), fp)) {
if (strstr(line, module_name)) {
pch = strtok(line, "-");
addr = strtoul(pch, null, 16);
if (addr == 0x8000)
addr = 0;
break;
}
}
fclose(fp);
}
return (void *)addr;
}
//这个方法来自 android inject 用于获取地址
void* get_remote_addr(int target_pid, const char* module_name, void* local_addr)
{
void* local_handle, *remote_handle;
local_handle = get_module_base(-1, module_name);
remote_handle = get_module_base(target_pid, module_name);
logi("[ ] get_remote_addr: local[%x], remote[%x]\n", local_handle, remote_handle);
void * ret_addr = (void *)((uint32_t)local_addr (uint32_t)remote_handle - (uint32_t)local_handle);
#if defined(__i386__)
if (!strcmp(module_name, "/system/lib/libc.so")) {
ret_addr = 2;
}
#endif
return ret_addr;
}
hook方法
//声明各个变量存放地址
void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;
//获取dlopen地址
dlopen_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlopen);
logi("[ ] dlopen_addr: [%x]", dlopen_addr);
//hook dlopen方法 下面方法类似
mshookfunction((void*)dlopen_addr, (void*)newdlopen, (void**)&olddlopen);
dlsym_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlsym);
logi("[ ] dlsym_addr: [%x]", dlsym_addr);
mshookfunction(dlsym_addr, (void*)newdlsym, (void**)&olddlsym);
dlclose_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlclose);
dlerror_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlerror);
//hook方法
void* (*olddlsym)(void* handle, const char* symbol);
void* newdlsym(void* handle, const char* symbol) {
logd("the handle [0x%x] symbol name:%s",handle,symbol);
return olddlsym(handle, symbol);
}
void* (*olddlopen)(const char* filename, int myflags);
void* newdlopen(const char* filename, int myflags) {
logd("the dlopen name :%s",filename);
return olddlopen(filename, myflags);
}