在前面关于Substrate的介绍中我们已经讲了用Substrate hook java代码,现在我们讲下怎么用它hook native代码。hook native代码我们需要编写Substrate extensions,它跟native库一样被视作标准的android包的一部分, 将作为一个共享库被编译 (使用复合扩展名.cy.so)。
一、相关API
(1)
MSConfig
名称 | 描述 |
Filter:Executable | 开发者试图hook的可执行文件的完整路径。一般为zygote, "/system/bin/app_process"。 |
Filter:Library | 开发者试图hook的lib库的名称,比如hook __android_log, 则指定 "liblog.so". |
如:
MSConfig(MSFilterExecutable, "/system/bin/app_process") MSConfig(MSFilterLibrary, "liblog.so")
(2)void MSHookFunction(void *symbol, void *hook, void **old);
参数 | 描述 |
---|---|
symbol | 被替换代码的地址,一般是一个函数 |
hook | The address of an ABI-compatible replacement for the code at the address referenced by symbol . |
old | 指向函数指针的指针,用来调用原函数的实现。如果不需要对原函数进行处理则为NULL |
示例:
1 void *(*oldConnect)(int, const sockaddr *, socklen_t); 2 3 void *newConnect( 4 int socket, const sockaddr *address, socklen_t length 5 ) { 6 if (address->sa_family == AF_INET) { 7 sockaddr_in *address_in = address; 8 if (address_in->sin_port == htons(6667)) { 9 sockaddr_in copy = *address_in; 10 address_in->sin_port = htons(7001); 11 return oldConnect(socket, ©, length); 12 } 13 } 14 15 return oldConnect(socket, address, length); 16 } 17 18 MSHookFunction(&connect, &newConnect, &oldConnect);
(3)void *MSFindSymbol(MSImageRef image, const char *name);
参数 | 描述 |
---|---|
image | 指定一个有效的image引用(通过调用MSGetImageByName返回的结果)。如果为NULL,则会搜索所有image |
name | 待查找的原始镜像符号的名称。这并非如dlopen所加载的高级符号,它可能需要以下划线为前缀或其他特定平台的编码。 |
return | 符号的地址(调整为ARM/Thumb类型),如果不能定位符号则返回NULL |
示例:
1 MSImageRef image; 2 image = MSGetImageByName("/usr/lib/libSystem.B.dylib"); 3 4 void *(*palloc)(size_t); 5 palloc = (void *(*)(size_t)) MSFindSymbol(image, "_malloc"); 6 7 void *data = (*palloc)(1024); 8 free(data);
(4)MSImageRef MSGetImageByName(const char *file);
参数 | 描述 |
---|---|
file | 根据so或者动态库的完整路径加载image |
return | 可以被其它API使用的image引用,如果image没有加载则为NULL |
示例:
1 MSImageRef image; 2 image = MSGetImageByName("/system/lib/libc.so"); 3 if (image != NULL) 4 /* image is loaded */;
二、使用示例
下面以前一篇过签名验证的hook代码为例讲解native hook的代码编写过程:
1.创建android native工程HookVerify,so层hook并不需要界面(作为Cydia Substrate的扩展模块),所以在新建工程时无需建activity。接下来在工程目录下新建jni文件夹,并将libsubstrate.so,libsubstrate-dvm.so,substrate.h三个文件拷贝至jni文件夹下。
在jni目录下创建HookVerify.cy.cpp文件。
2.配置Manifest文件
需要添加权限:<uses-permission android:name="cydia.permission.SUBSTRATE"/>
由于我们只使用native code,将android:hasCode设为false。
3.Android.mk文件编写:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE := substrate LOCAL_SRC_FILES := libsubstrate.so include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := substrate-dvm LOCAL_SRC_FILES := libsubstrate-dvm.so include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := HookVerify #一定要有.cy作后缀 LOCAL_SRC_FILES := HookVerify.cy.cpp LOCAL_LDLIBS := -llog LOCAL_ARM_MODE := arm LOCAL_LDLIBS += -L$(LOCAL_PATH) -lsubstrate-dvm -lsubstrate include $(BUILD_SHARED_LIBRARY)
4.HookVerify.cy.cpp代码:
1 #include <jni.h> 2 #include "substrate.h" 3 #include <android/log.h> 4 #include <unistd.h> 5 #include <stdio.h> 6 #include <fcntl.h> 7 #include <sys/types.h> 8 #include <string.h> 9 #include <sys/stat.h> 10 #define TAG "HOOKDEMO" 11 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 12 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) 13 char* AppName = NULL; 14 //指定要hook的lib 库: 15 MSConfig(MSFilterLibrary, "/system/lib/libdvm.so"); 16 //保留原来的地址: 17 void *(*oldUnzOpen64)(const char* filepath); 18 //替换的函数 19 void *newUnzOpen64(const char* filepath){ 20 return oldUnzOpen64("/sdcard/myapk.apk"); 21 } 22 //Hook dvmLoadNativeCode 23 bool (*_dvmLoadNativeCode)(char* pathName, void* classLoader, char** detail); 24 bool My_dvmLoadNativeCode(char* pathName, void* classLoader, char** detail){ 25 bool b_Result = _dvmLoadNativeCode(pathName,classLoader,detail); //进行原来的调用,不影响程序运行 26 //LOGD("dvmLoadNativeCode AppName:%s", AppName); 27 if(strstr(pathName,"AppVerify") != NULL){ 28 LOGD("dvmLoadNativeCode Find Hook"); 29 MSImageRef image = MSGetImageByName(pathName); 30 if(image != NULL){ 31 void* mFun = MSFindSymbol(image, "unzOpen64"); 32 //开始Hook fork 33 if(mFun != NULL){ 34 LOGD("dvmLoadNativeCode Hook"); 35 //MSHookFunction(mFun,(void*)&My_fork,(void**)&_fork); 36 MSHookFunction(mFun, (void*)&newUnzOpen64, (void**)&oldUnzOpen64); 37 } 38 } 39 } 40 return b_Result; 41 } 42 //在初始化的时候进行hook,具体如下: 43 //Substrate entry point 44 MSInitialize{ 45 __android_log_print(ANDROID_LOG_ERROR, TAG, "Substrate initialized."); 46 MSImageRef image; 47 image = MSGetImageByName("/system/lib/libdvm.so"); //载入lib 48 if (image != NULL) 49 { 50 //注意这个是个c++函数,可以通过objdump来获取 51 void * dvmload = MSFindSymbol(image, "_Z17dvmLoadNativeCodePKcP6ObjectPPc"); 52 if(dvmload == NULL) 53 { 54 LOGD("error find dvmLoadNativeCode "); 55 } 56 else{ 57 MSHookFunction(dvmload,(void*)&My_dvmLoadNativeCode,(void **)&_dvmLoadNativeCode); 58 } 59 } 60 else{ 61 LOGD("ERROR FIND LIBDVM"); 62 } 63 }
这样就完成了hook代码的编写。安装运行就行了。