Java Native Interface API hook

Java Native Interface API hook

想要打印一些JNI函数调用时候的参数,我常用的有两种方法,一种是通过IDA,另一种是写一个so实现hook。

IDA中打印JNI API参数

_JNIEnv结构:

1
2
3
4
5
6
7
8
struct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
#if defined(__cplusplus)

jint GetVersion()
{ return functions->GetVersion(this); }

JNINativeInterface结构:

1
2
3
4
5
6
7
8
9
10
11
12
13

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的地址为例。

1
2
3
4
5
6
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))

image-20210325113015092

image-20210325113039877

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:
# NewStringUTF
s = idc.get_strlit_contents(idc.get_reg_value('R1'))
if s is not None:
print('NewStringUTF: '+s.decode())
continue_process()
return 0

# Remove an existing debug hook
try:
if debughook:
print("MyDbgHook : Removing previous hook")
debughook.unhook()
except:
pass
# Install the debug hook
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文件。

1
2
3
4
5
6
7
8
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");
}

});

image-20210325131408269

参考连接

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