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);
}