Java Native Interface API hook 想要打印一些JNI函数调用时候的参数,我常用的有两种方法,一种是通过IDA,另一种是写一个so实现hook。
IDA中打印JNI API参数 _JNIEnv结构:
struct _JNIEnv { const struct JNINativeInterface * functions ;#if defined(__cplusplus) jint GetVersion () { return functions->GetVersion(this ); }
JNINativeInterface结构:
struct JNINativeInterface { void * reserved0; void * reserved1; void * reserved2; void * reserved3; jint (*GetVersion)(JNIEnv *); jclass (*DefineClass)(JNIEnv*, const char *, jobject, const jbyte*, jsize); jclass (*FindClass)(JNIEnv*, const char *); ....
找一个导出的JNI函数,一般函数的前两个参数的类型分别是_JavaVM *,_JNIEnv *。有了env(_JNIEnv)值,就可以获取到函数表的地址。
以NewStringUTF的地址为例。
import idc r1 = idc.get_reg_value('R1' ) addr_func_table = idc.get_wide_dword(r1) addr_NewStringUTF= idc.get_wide_dword(addr_func_table + 0x29c )print (hex (addr_NewStringUTF))
Hook并打印参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from idaapi import *import idc r1 = idc.get_reg_value('R1' ) addr_func_table = idc.get_wide_dword(r1) addr_NewStringUTF= idc.get_wide_dword(addr_func_table + 0x29c ) - 1 idc.add_bpt(libdvm_base + addr_NewStringUTF)class MyDbgHook (DBG_Hooks ): def dbg_bpt (self, tid, ea ): if ea == addr_NewStringUTF: s = idc.get_strlit_contents(idc.get_reg_value('R1' )) if s is not None : print ('NewStringUTF: ' +s.decode()) continue_process() return 0 try : if debughook: print ("MyDbgHook : Removing previous hook" ) debughook.unhook()except : pass debughook = MyDbgHook() debughook.hook()
so模块Hook 使用Android-Inline-Hook 编写so(仅支持32位)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 uint32_t (*old_NewStringUTF)(JNIEnv* env, const char * s) = NULL ;jstring new_NewStringUTF (JNIEnv* env, const char * s) { LOGI("NewStringUTF: %s" , s); return old_NewStringUTF(env, s); }jint JNI_OnLoad (JavaVM* vm, void * reserved) { JNIEnv* env = NULL ; if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { return -1 ; } if (registerInlineHook((uint32_t ) addr_NewStringUTF, (uint32_t ) new_NewStringUTF, (uint32_t **) &old_NewStringUTF) != 0 ) { LOGE("registerInlineHook error" ); return -1 ; } if (inlineHook((uint32_t ) addr_NewStringUTF) != 0 ) { LOGE("inlineHook error" ); return -1 ; } LOGI("JNI_OnLoad SUCCESS" ); return JNI_VERSION_1_4; }
使用Xposed或其他工具注入so文件。
findAndHookMethod("com.stub.StubApp" ,lpparam.classLoader, "attachBaseContext" , Context.class,new XC_MethodHook() { @Override protected void beforeHookedMethod (MethodHookParam param) throws Throwable { super .beforeHookedMethod(param); System.load("/data/data/com.zhighest.xxxx/files/libnative-lib.so" ); } });
参考连接 https://github.com/ele7enxxh/Android-Inline-Hook
https://bbs.pediy.com/thread-200398.htm
https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml
https://github.com/chame1eon/jnitrace