android native 中的函数动态注册方式总结

一、最标准 & 官方的动态注册方式(JNI_RegisterNatives)

1️⃣ JNI_OnLoad + RegisterNatives(最常见

复制代码
static JNINativeMethod gMethods[] = {
    {"nativeAdd", "(II)I", (void *)native_add},
    {"nativeInit", "()V", (void *)native_init},
};

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    vm->GetEnv((void **)&env, JNI_VERSION_1_6);

    jclass clazz = env->FindClass("com/example/Test");
    env->RegisterNatives(clazz, gMethods,
                         sizeof(gMethods)/sizeof(gMethods[0]));
    return JNI_VERSION_1_6;
}

✅ 特点

  • 方法名、签名、函数指针三元组

  • 字符串 + 函数指针同时存在

  • 非常适合静态分析 & Frida/Unidbg

🔍 逆向切入点

  • JNI_OnLoad

  • RegisterNatives

  • JNINativeMethod[]

2️⃣ 多 Class / 分模块注册

复制代码
registerClass(env, "com/a/A", methodsA);
registerClass(env, "com/b/B", methodsB);

✅ 特点

  • 一个 so 注册几十上百个类

  • 常见于大型 SDK(腾讯、阿里)

🔍 逆向技巧

  • FindClass

  • 跟字符串池里的 Java 类路径

二、半隐藏型:JNI 函数指针二次封装

3️⃣ 封装 RegisterNatives(初级混淆

复制代码

int my_register(JNIEnv *env, const char *cls, JNINativeMethod *m, int n) { jclass c = env->FindClass(cls); return env->RegisterNatives(c, m, n); }

甚至:

复制代码

(*(env->functions + 215))(env, clazz, methods, n);

✅ 特点

  • IDA 看不到 RegisterNatives 符号

  • 靠 JNI function table 调用

🔍 逆向

  • 识别 JNIEnv->functions

  • Frida hook RegisterNatives真实地址

三、反编译最烦的:字符串 / 表结构混淆

4️⃣ JNINativeMethod 表动态生成

复制代码
JNINativeMethod *m = malloc(sizeof(JNINativeMethod) * n);
m[i].name = decrypt("xxx");
m[i].signature = decrypt("xxx");
m[i].fnPtr = calc_func(i);

特点

  • 没有静态表

  • name/signature 运行时解密

🔍 逆向

  • 解密函数

  • Hook RegisterNatives 直接 dump

5️⃣ 函数指针运行时计算(offset / hash)

复制代码
m[i].fnPtr = base + offset[i];

或者:

fn = (void *)((char *)so_base + hash_table[name]);

✅ 特点

  • 函数地址无法静态交叉引用

  • 常见于加固 SDK

🔍

  • 先拿 so base

  • 动态调试时下断点

四、进阶:完全不走 RegisterNatives 的骚操作

6️⃣ 利用 JNI 函数表劫持(少见但狠

复制代码
env->functions->CallVoidMethod = my_call;

或者修改 ART 内部结构

⚠️ 极少见

  • 强依赖 Android 版本

  • 高风险但极难分析

7️⃣ 利用 dlsym + 手动调用 Java 方法

复制代码
void *handle = dlopen("libart.so", RTLD_NOW);
void *sym = dlsym(handle, "_ZN3art...");

直接调用 ART 内部接口

⚠️

  • 非 JNI 官方

  • 加固厂常用(某些 Dex2C / VMProtect)

五、结合 Java 层的"假动态注册"

8️⃣ Java 层 native 方法名动态生成

复制代码
static {
    String m = decrypt("native_" + x);
    System.loadLibrary("xxx");
    register(m);
}

Java 层看不到真实 native 名

🔍

  • 反 Java 混淆

  • 或直接 Hook JNI 层

六、现代加固常见组合拳(真实项目)

实战中经常是 多种方式叠加

技术 是否常见
JNI_OnLoad + RegisterNatives ⭐⭐⭐⭐⭐
字符串加密 ⭐⭐⭐⭐
函数指针偏移 ⭐⭐⭐
多 so 分散注册 ⭐⭐⭐
Dex2C + Native 调度 ⭐⭐⭐⭐
ART 私有 API ⭐⭐

七、逆向/Hook 统一破局思路(很重要)

下一篇分析

相关推荐
海兰12 分钟前
使用 Spring AI 打造企业级 RAG 知识库第二部分:AI 实战
java·人工智能·spring
历程里程碑29 分钟前
二叉树---二叉树的中序遍历
java·大数据·开发语言·elasticsearch·链表·搜索引擎·lua
小信丶43 分钟前
Spring Cloud Stream EnableBinding注解详解:定义、应用场景与示例代码
java·spring boot·后端·spring
无限进步_1 小时前
【C++】验证回文字符串:高效算法详解与优化
java·开发语言·c++·git·算法·github·visual studio
亚历克斯神1 小时前
Spring Cloud 2026 架构演进
java·spring·微服务
七夜zippoe1 小时前
Spring Cloud与Dubbo架构哲学对决
java·spring cloud·架构·dubbo·配置中心
海派程序猿1 小时前
Spring Cloud Config拉取配置过慢导致服务启动延迟的优化技巧
java
call me by ur name1 小时前
ERNIE 5.0 Technical Report论文解读
android·开发语言·人工智能·机器学习·ai·kotlin
w6100104661 小时前
CKA-2026-Service
linux·服务器·网络·service·cka
阿维的博客日记1 小时前
为什么不逃逸代表不需要锁,JIT会直接删掉锁
java