首页
社区
课程
招聘
[分享]记录如何追踪native函数动态注册地址
发表于: 2026-5-8 18:11 9905

[分享]记录如何追踪native函数动态注册地址

2026-5-8 18:11
9905

分析jni动态注册流程并用frida获取函数名与地址。发现只学不练记忆不够深刻,于是记录一下学习过程使自己有更深刻的理解。

开发者在JNI_OnLoad中调用env->RegisterNatives后底层做了什么。

例:




进入RegisterNatives源码:


上图可以看到,获取JNINativeMethod的fnPtr , 然后调用m->RegisterNative。

JNINativeMethod结构体如下。

name为Java 中的方法名, signature为签名,fnPtr为native函数地址。

然后进入到RegisterNative,在

Runtime::Current()->GetRuntimeCallbacks()->RegisterNativeMethod(this, native_method, /*out*/&new_native_method);中做的事情其实就是把native_method赋值给new_native_method


然后再进入到SetEntryPointFromJni,我们知道entrypoint就是函数地址,而kRuntimePointerSize其实是个固定值,见下图,一个常量,它代表了当前正在运行的 ART 虚拟机所在环境的“真实指针大小”(32位系统是 4 字节,64位系统是 8 字节)

进入SetEntryPointFromJniPtrSize

进入SetDataPtrSize

看一下DataOffset

先看

OFFSETOF_MEMBER(PtrSizedFields, data_) / sizeof(void*) * static_cast<size_t>(pointer_size),

sizeof(void*) 是编译安卓源码时所在机器的指针大小,static_cast<size_t>(pointer_size)是运行安卓系统所在手机的指针大小

再看一下OFFSETOF_MEMBER,即计算出一个结构体(或类)中某个特定成员变量,距离该结构体首地址的字节偏移量。

也就是data_在PtrSizedFields的偏移是多少。


综上,

OFFSETOF_MEMBER(PtrSizedFields, data_) / sizeof(void*) * static_cast<size_t>(pointer_size),

sizeof(void*)  ,假设sizeof(void*)和static_cast<size_t>(pointer_size)都是8,我们可以算一下,OFFSETOF_MEMBER(PtrSizedFields, data_)是0,然后 (0/8 )* 8还是0


然后看,PtrSizedFieldsOffset返回的就是hotness_count_变量在ArtMethod类的偏移+hotness_count_大小,再进行内存对齐。


先看一下ArtMethod类的结构


手动计算一下hotness_count_变量在ArtMethod类的偏移。declaring_class_的偏移是4字节(不说为什么了,篇幅太大太乱了),access_flags_,dex_code_item_offset_,dex_method_index_都是四字节,method_index_和union {uint16_t hotness_count_;uint16_t imt_index_; };是两个字节。union共用内存。所以hotness_count_的偏移是20字节,然后再加上sizeof(hotness_count_),总共是22字节。


再看RoundUp,现在已知参数1是22,参数2是8。即RoundUp(22,8),我们看看会返回什么

调用RoundDown(22+8-1,8)=RoundDown(29,8)



代入计算一下,29 & -8 =24



综上,PtrSizedFieldsOffset(pointer_size)=24, 

OFFSETOF_MEMBER(PtrSizedFields, data_) / sizeof(void*) * static_cast<size_t>(pointer_size)   = 0;




最后进入SetNativePointer,即SetNativePointer(24, 函数地址, 8);



ok了老铁们,也就是 RegisterNative在背后做的事就是 把函数地址赋值给ArtMethod类偏移为24的变量(在arm64是24,32位偏移为20,可以自己算一下),也就是data_变量。


接下来分析std::string类,下面有用


再看basic_string


[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 6
打赏
分享
最新回复 (4)
雪    币: 76
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
两种方法,一种用yang神的hookregister脚本;另一种直接在unidbg搭个空架子也能看到入口偏移
2026-5-9 00:09
1
雪    币: 209
活跃值: (100)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
温泉划水鱼 两种方法,一种用yang神的hookregister脚本;另一种直接在unidbg搭个空架子也能看到入口偏移
谢谢指正
2026-5-9 09:30
0
雪    币: 453
活跃值: (275)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
写的蛮好,学习了
2026-5-19 10:46
0
雪    币: 209
活跃值: (100)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
x1a0f3n9 写的蛮好,学习了
谢谢认可
2026-5-19 14:50
0
游客
登录 | 注册 方可回帖
返回