这是3W班7月份的练习题第一题。题目要求是分析总结动态注册jni函数时的流程,并编写frida脚本,达到能够跟踪测试apk中动态注册的jni函数的绑定流程的目标。
通过查看源码,使用Frida验证了部分绑定流程。加深了对之前使用的hook RegisterNative脚本原理的理解。
按照hanbing老师的讲解,native函数有2次绑定。这里分别查看绑定
自己写Demo方便测试
从ClassLinker::DefineClass->ClassLinker::LoadClass->ClassLinker::LoadClassMembers进入到ArtMethod的初始化。
这里就是主要看LinkCode方法中的method->IsNative()条件
静态和动态注册的方法都会先进行UnregisterNative();第一次绑定art_jni_dlsym_lookup_stub,最后还是通过RegisterNative注册。
这里就可以先HOOK artFindNativeMethod查看返回值
这里可以看到2个静态注册的stringFromJNI调用了绑定,但是stringFromJNI2没有绑定,因为程序中并没有调用stringFromJNI2,这里可以打印一下2个ArtMethod的差别
这里可以看出几点
和上方静态注册一样,也就是0x20处地址发生变化。从art模块的art_jni_dlsym_lookup_stub换成了自己so文件的地址,下面分析就是修改的流程。
这里和静态注册一样也是走到了SetEntryPointFromJni,查看具体流程
涉及的方法还是比较多,大多数是ALWAYS_INLINE修饰,IDA查不到符号SetEntryPointFromJni,直接查看ArtMethod::RegisterNative末尾
查看libart反编译源码发现这里其实就2步,0x20也和上面对应上了。
SetEntryPointFromJni(new_native_method),其实已经被优化成几句汇编了,主要就是STR X0, [X19,#0x20]
这里也就验证了之前ArtMethod+0x20是EntryPoint,也可以通过源码计算内存偏移
这样修改后的确可以调用,没有报错。
正常打印,第二个参数是注册地址
public native String stringFromJNI();
public native String stringFromJNI2();
public native void RegisterFunc();
public native void Func();
public native String stringFromJNI();
public native String stringFromJNI2();
public native void RegisterFunc();
public native void Func();
extern
"C"
JNIEXPORT jstring JNICALL
Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI(
JNIEnv
*
env,
jobject
/
*
this
*
/
) {
std::string hello
=
"Hello from C++"
;
return
env
-
>NewStringUTF(hello.c_str());
}
extern
"C"
JNIEXPORT jstring JNICALL
Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI2(
JNIEnv
*
env,
jobject
/
*
this
*
/
) {
std::string hello
=
"Hello from C++2"
;
return
env
-
>NewStringUTF(hello.c_str());
}
void F(JNIEnv
*
env, jobject thiz) {
__android_log_print(
4
,
"nativedemo"
,
"Call Func"
);
}
__attribute__ ((visibility (
"hidden"
))) void RF(JNIEnv
*
env, jobject thiz) {
/
/
注册另外一个函数
__android_log_print(
4
,
"nativedemo"
,
"Call RegisterFunc New"
);
JNINativeMethod jniNativeMethod[]
=
{{
"Func"
,
"()V"
, (void
*
) F}};
jclass MainActivityjclass
=
env
-
>FindClass(
"com/cwuzao/nativedemo/MainActivity"
);
env
-
>RegisterNatives(MainActivityjclass, jniNativeMethod,
sizeof(jniNativeMethod)
/
sizeof(JNINativeMethod));
}
JNIEXPORT jint JNI_OnLoad(JavaVM
*
vm, void
*
reserved) {
JNIEnv
*
env
=
nullptr;
if
(vm
-
>GetEnv((void
*
*
) &env, JNI_VERSION_1_6)
=
=
JNI_OK) {
__android_log_print(
4
,
"nativedemo"
,
"jni->%s"
,
"vm->GetEnv((void**)&env,JNI_VERSION_1_6) success"
);
}
JNINativeMethod jniNativeMethod[]
=
{{
"RegisterFunc"
,
"()V"
, (void
*
) RF}};
jclass MainActivityjclass
=
env
-
>FindClass(
"com/cwuzao/nativedemo/MainActivity"
);
env
-
>RegisterNatives(MainActivityjclass, jniNativeMethod,sizeof(jniNativeMethod)
/
sizeof(JNINativeMethod));
return
JNI_VERSION_1_6;
}
extern
"C"
JNIEXPORT jstring JNICALL
Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI(
JNIEnv
*
env,
jobject
/
*
this
*
/
) {
std::string hello
=
"Hello from C++"
;
return
env
-
>NewStringUTF(hello.c_str());
}
extern
"C"
JNIEXPORT jstring JNICALL
Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI2(
JNIEnv
*
env,
jobject
/
*
this
*
/
) {
std::string hello
=
"Hello from C++2"
;
return
env
-
>NewStringUTF(hello.c_str());
}
void F(JNIEnv
*
env, jobject thiz) {
__android_log_print(
4
,
"nativedemo"
,
"Call Func"
);
}
__attribute__ ((visibility (
"hidden"
))) void RF(JNIEnv
*
env, jobject thiz) {
/
/
注册另外一个函数
__android_log_print(
4
,
"nativedemo"
,
"Call RegisterFunc New"
);
JNINativeMethod jniNativeMethod[]
=
{{
"Func"
,
"()V"
, (void
*
) F}};
jclass MainActivityjclass
=
env
-
>FindClass(
"com/cwuzao/nativedemo/MainActivity"
);
env
-
>RegisterNatives(MainActivityjclass, jniNativeMethod,
sizeof(jniNativeMethod)
/
sizeof(JNINativeMethod));
}
JNIEXPORT jint JNI_OnLoad(JavaVM
*
vm, void
*
reserved) {
JNIEnv
*
env
=
nullptr;
if
(vm
-
>GetEnv((void
*
*
) &env, JNI_VERSION_1_6)
=
=
JNI_OK) {
__android_log_print(
4
,
"nativedemo"
,
"jni->%s"
,
"vm->GetEnv((void**)&env,JNI_VERSION_1_6) success"
);
}
JNINativeMethod jniNativeMethod[]
=
{{
"RegisterFunc"
,
"()V"
, (void
*
) RF}};
jclass MainActivityjclass
=
env
-
>FindClass(
"com/cwuzao/nativedemo/MainActivity"
);
env
-
>RegisterNatives(MainActivityjclass, jniNativeMethod,sizeof(jniNativeMethod)
/
sizeof(JNINativeMethod));
return
JNI_VERSION_1_6;
}
void ClassLinker::LoadClassMembers() {
for
(size_t i
=
0
; it.HasNextDirectMethod(); i
+
+
, it.
Next
()) {
ArtMethod
*
method
=
klass
-
>GetDirectMethodUnchecked(i, image_pointer_size_);
LoadMethod(dex_file, it, klass, method);
LinkCode(this, method, oat_class_ptr, class_def_method_index);
}
void ClassLinker::LoadClassMembers() {
for
(size_t i
=
0
; it.HasNextDirectMethod(); i
+
+
, it.
Next
()) {
ArtMethod
*
method
=
klass
-
>GetDirectMethodUnchecked(i, image_pointer_size_);
LoadMethod(dex_file, it, klass, method);
LinkCode(this, method, oat_class_ptr, class_def_method_index);
}
if
(method
-
>IsNative()) {
/
/
Unregistering restores the dlsym lookup stub.
method
-
>UnregisterNative();
}
void ArtMethod::UnregisterNative() {
CHECK(IsNative() && !IsFastNative()) << PrettyMethod();
/
/
restore stub to lookup native pointer via dlsym
SetEntryPointFromJni(GetJniDlsymLookupStub());
}
extern
"C"
void
*
art_jni_dlsym_lookup_stub(JNIEnv
*
, jobject);
static inline const void
*
GetJniDlsymLookupStub() {
return
reinterpret_cast<const void
*
>(art_jni_dlsym_lookup_stub);
}
ENTRY art_jni_dlsym_lookup_stub
/
/
spill regs.
...
bl artFindNativeMethod
...
END art_jni_dlsym_lookup_stub
extern
"C"
const void
*
artFindNativeMethod() {
ArtMethod
*
method
=
self
-
>GetCurrentMethod(nullptr);
void
*
native_code
=
soa.Vm()
-
>FindCodeForNativeMethod(method);
return
method
-
>RegisterNative(native_code, false);
}
}
/
/
namespace art
if
(method
-
>IsNative()) {
/
/
Unregistering restores the dlsym lookup stub.
method
-
>UnregisterNative();
}
void ArtMethod::UnregisterNative() {
CHECK(IsNative() && !IsFastNative()) << PrettyMethod();
/
/
restore stub to lookup native pointer via dlsym
SetEntryPointFromJni(GetJniDlsymLookupStub());
}
extern
"C"
void
*
art_jni_dlsym_lookup_stub(JNIEnv
*
, jobject);
static inline const void
*
GetJniDlsymLookupStub() {
return
reinterpret_cast<const void
*
>(art_jni_dlsym_lookup_stub);
}
ENTRY art_jni_dlsym_lookup_stub
/
/
spill regs.
...
bl artFindNativeMethod
...
END art_jni_dlsym_lookup_stub
extern
"C"
const void
*
artFindNativeMethod() {
ArtMethod
*
method
=
self
-
>GetCurrentMethod(nullptr);
void
*
native_code
=
soa.Vm()
-
>FindCodeForNativeMethod(method);
return
method
-
>RegisterNative(native_code, false);
}
}
/
/
namespace art
var addr_ArtMethod_UnRegisterNative
=
libart.findExportByName(
"_ZN3art9ArtMethod16UnregisterNativeEv"
);
Interceptor.attach(addr_ArtMethod_UnRegisterNative, {
onEnter: function(args){
allocPrettyMethod.writeByteArray(allocPrettyMethodInit);
PrettyMethod(addr_ArtMethod_PrettyMethod, args[
0
], allocPrettyMethod,
0x100
);
console.log(
"addr_ArtMethod_UnRegisterNative onEnter:"
,allocPrettyMethod.readCString());
},
onLeave: function(retval){
}
});
var addr_artFindNativeMethod
=
libart.findExportByName(
"artFindNativeMethod"
);
Interceptor.attach(addr_artFindNativeMethod, {
onEnter: function(args){
},
onLeave: function(retval){
console.log(
"addr_artFindNativeMethod onLeave:"
, retval);
}
});
var addr_FindCodeForNativeMethod
=
libart.findExportByName(
"_ZN3art9JavaVMExt23FindCodeForNativeMethodEPNS_9ArtMethodE"
);
Interceptor.attach(addr_FindCodeForNativeMethod, {
onEnter: function(args){
allocPrettyMethod.writeByteArray(allocPrettyMethodInit);
PrettyMethod(addr_ArtMethod_PrettyMethod, args[
1
], allocPrettyMethod,
0x100
);
console.log(
"addr_FindCodeForNativeMethod onEnter:"
,allocPrettyMethod.readCString() );
},
onLeave: function(retval){
}
});
var addr_ArtMethod_UnRegisterNative
=
libart.findExportByName(
"_ZN3art9ArtMethod16UnregisterNativeEv"
);
Interceptor.attach(addr_ArtMethod_UnRegisterNative, {
onEnter: function(args){
allocPrettyMethod.writeByteArray(allocPrettyMethodInit);
PrettyMethod(addr_ArtMethod_PrettyMethod, args[
0
], allocPrettyMethod,
0x100
);
console.log(
"addr_ArtMethod_UnRegisterNative onEnter:"
,allocPrettyMethod.readCString());
},
onLeave: function(retval){
}
});
var addr_artFindNativeMethod
=
libart.findExportByName(
"artFindNativeMethod"
);
Interceptor.attach(addr_artFindNativeMethod, {
onEnter: function(args){
},
onLeave: function(retval){
console.log(
"addr_artFindNativeMethod onLeave:"
, retval);
}
});
var addr_FindCodeForNativeMethod
=
libart.findExportByName(
"_ZN3art9JavaVMExt23FindCodeForNativeMethodEPNS_9ArtMethodE"
);
Interceptor.attach(addr_FindCodeForNativeMethod, {
onEnter: function(args){
allocPrettyMethod.writeByteArray(allocPrettyMethodInit);
PrettyMethod(addr_ArtMethod_PrettyMethod, args[
1
], allocPrettyMethod,
0x100
);
console.log(
"addr_FindCodeForNativeMethod onEnter:"
,allocPrettyMethod.readCString() );
},
onLeave: function(retval){
}
});
dlopen: libart.so
libart
-
> [
object
Object
]
addr_FindCodeForNativeMethod onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI()
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI
addr_artFindNativeMethod onLeave:
0x7593752c0c
dlopen: libart.so
libart
-
> [
object
Object
]
addr_FindCodeForNativeMethod onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI()
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI
addr_artFindNativeMethod onLeave:
0x7593752c0c
addr_ArtMethod_UnRegisterNative onEnter: void com.cwuzao.nativedemo.MainActivity.Func()
addr_ArtMethod_UnRegisterNative onEnter: void com.cwuzao.nativedemo.MainActivity.RegisterFunc()
addr_ArtMethod_UnRegisterNative onEnter: void com.cwuzao.nativedemo.MainActivity.onCreate(android.os.Bundle)
addr_ArtMethod_UnRegisterNative onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI()
addr_ArtMethod_UnRegisterNative onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
methodName
-
> public native java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI()
Func.getArtMethod
-
>
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75ae4c56c0
20
25
c8
12
01
01
00
08
00
00
00
00
b1
3b
00
00
%
...........;..
75ae4c56d0
10
02
00
00
00
00
00
00
00
80
22
94
75
00
00
00
..........".u...
75ae4c56e0
0c
2c
75
93
75
00
00
00
70
96
f1 ac
75
00
00
00
.,u.u...p...u...
methodName
-
> public native java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
Func.getArtMethod
-
>
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75ae4c56f0
20
25
c8
12
01
01
00
08
00
00
00
00
b2
3b
00
00
%
...........;..
75ae4c5700
11
02
00
00
00
00
00
00
00
80
22
94
75
00
00
00
..........".u...
75ae4c5710
00
f5 f0 ac
75
00
00
00
70
96
f1 ac
75
00
00
00
....u...p...u...
/
/
调用一次stringFromJNI2
addr_FindCodeForNativeMethod onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI2
addr_artFindNativeMethod onLeave:
0x7593752d5c
methodName
-
> public native java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
Func.getArtMethod
-
>
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75ae4c56f0
20
25
c8
12
01
01
00
08
00
00
00
00
b2
3b
00
00
%
...........;..
75ae4c5700
11
02
00
00
00
00
00
00
00
80
22
94
75
00
00
00
..........".u...
75ae4c5710
5c
2d
75
93
75
00
00
00
70
96
f1 ac
75
00
00
00
\
-
u.u...p...u...
/
/
这ArtMethod在
0x20
处发生变化,打印调用前后stringFromJNI2
0x20
的地址所在模块
[AOSP on msm8996::com.cwuzao.nativedemo]
-
> Process.findModuleByAddress(
0x75acf0f500
)
{
"base"
:
"0x75aca2d000"
,
"name"
:
"libart.so"
,
"path"
:
"/system/lib64/libart.so"
,
"size"
:
6041600
}
[AOSP on msm8996::com.cwuzao.nativedemo]
-
> Process.findModuleByAddress(
0x7593752d5c
)
{
"base"
:
"0x7593744000"
,
"name"
:
"libnative-lib.so"
,
"path"
:
"/data/app/com.cwuzao.nativedemo-UgxLVJ25_JE-ydv0Rl_x2A==/lib/arm64/libnative-lib.so"
,
"size"
:
212992
}
[AOSP on msm8996::com.cwuzao.nativedemo]
-
> console.log(hexdump(ptr(
0x75acf0f500
)))
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75acf0f500
fd
7b
bf a9 fd
03
00
91
e6
1f
bf
6d
e4
17
bf
6d
.{.........m...m
75acf0f510
e2
0f
bf
6d
e0
07
bf
6d
e6
1f
bf a9 e4
17
bf a9 ...m...m........
75acf0f520
e2
0f
bf a9 e0
07
bf a9 d7
01
ff
97
f1
03
00
aa ................
75acf0f530
e0
07
c1 a8 e2
0f
c1 a8 e4
17
c1 a8 e6
1f
c1 a8 ................
75acf0f540
e0
07
c1
6c
e2
0f
c1
6c
e4
17
c1
6c
e6
1f
c1
6c
...l...l...l...l
75acf0f550
fd
7b
c1 a8
51
00
00
b4
20
02
1f
d6 c0
03
5f
d6 .{..Q... ....._.
/
/
0x75acf0f500
这段
hex
可以转成arm汇编就是art_jni_dlsym_lookup_stub
/
/
0x7593752d5c
-
0x7593744000
就是stringFromJNI2的代码位置
addr_FindCodeForNativeMethod onEnter: void com.cwuzao.nativedemo.MainActivity.Func()
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_Func
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_Func__
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_Func
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_Func__
addr_artFindNativeMethod onLeave:
0x0
/
/
运行到这里程序崩溃了
addr_ArtMethod_UnRegisterNative onEnter: void com.cwuzao.nativedemo.MainActivity.Func()
addr_ArtMethod_UnRegisterNative onEnter: void com.cwuzao.nativedemo.MainActivity.RegisterFunc()
addr_ArtMethod_UnRegisterNative onEnter: void com.cwuzao.nativedemo.MainActivity.onCreate(android.os.Bundle)
addr_ArtMethod_UnRegisterNative onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI()
addr_ArtMethod_UnRegisterNative onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
methodName
-
> public native java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI()
Func.getArtMethod
-
>
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75ae4c56c0
20
25
c8
12
01
01
00
08
00
00
00
00
b1
3b
00
00
%
...........;..
75ae4c56d0
10
02
00
00
00
00
00
00
00
80
22
94
75
00
00
00
..........".u...
75ae4c56e0
0c
2c
75
93
75
00
00
00
70
96
f1 ac
75
00
00
00
.,u.u...p...u...
methodName
-
> public native java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
Func.getArtMethod
-
>
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75ae4c56f0
20
25
c8
12
01
01
00
08
00
00
00
00
b2
3b
00
00
%
...........;..
75ae4c5700
11
02
00
00
00
00
00
00
00
80
22
94
75
00
00
00
..........".u...
75ae4c5710
00
f5 f0 ac
75
00
00
00
70
96
f1 ac
75
00
00
00
....u...p...u...
/
/
调用一次stringFromJNI2
addr_FindCodeForNativeMethod onEnter: java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
addr_FindSymbol: Java_com_cwuzao_nativedemo_MainActivity_stringFromJNI2
addr_artFindNativeMethod onLeave:
0x7593752d5c
methodName
-
> public native java.lang.String com.cwuzao.nativedemo.MainActivity.stringFromJNI2()
Func.getArtMethod
-
>
0
1
2
3
4
5
6
7
8
9
A B C D E F
0123456789ABCDEF
75ae4c56f0
20
25
c8
12
01
01
00
08
00
00
00
00
b2
3b
00
00
%
...........;..
75ae4c5700
11
02
00
00
00
00
00
00
00
80
22
94
75
00
00
00
..........".u...
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课