/*
* =====================================================================================
*
* 反编译的 C 源码 (Decompiled C Source Code)
*
* 以下代码是根据给定的汇编逻辑推断出的等效 C/C++ 源码。
* 它展示了 JNI_OnLoad 函数的典型实现,用于动态注册本地方法。
*
* =====================================================================================
*/
#include <jni.h>
// 假设在别处定义了本地方法的信息。
// 汇编代码通过 cs:nativeMethod_ptr 来引用它。
extern const JNINativeMethod* nativeMethod_ptr;
/**
* @brief 当本地库被加载时,Java 虚拟机会调用此函数。
*
* @param vm JavaVM 指针,代表整个 Java 虚拟机。
* @param reserved 保留参数,未使用。
* @return jint 返回库所需的 JNI 版本号。如果出错,则返回 JNI_ERR (-1)。
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
// 1. 获取当前线程的 JNIEnv 指针。
// 对应汇编: 0x64a - 0x65a
// vm->GetEnv(vm, &env, JNI_VERSION_1_4);
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) {
return -1; // 获取失败,返回错误码 JNI_ERR
}
// 2. 查找需要注册本地方法的 Java 类。
// 对应汇编: 0x65c - 0x66a
jclass clazz = (*env)->FindClass(env, "github/jp1017/hellojni/MainActivity");
// 注意:原始汇编代码没有检查 FindClass 是否返回 NULL,
// 在实际产品代码中,这里应该有错误检查。
if (clazz == NULL) {
// 在严谨的实现中,如果找不到类,也应该返回错误。
return -1;
}
// 3. 注册本地方法。
// 对应汇编: 0x66d - 0x683
// 汇编中使用 `mov ecx, 1`,表示只注册一个方法。
if ((*env)->RegisterNatives(env, clazz, nativeMethod_ptr, 1) < 0) {
// 在严谨的实现中,如果注册失败,也应该返回错误。
return -1;
}
// 4. 所有操作成功,返回库所支持的 JNI 版本。
// 对应汇编: 0x68a
return JNI_VERSION_1_4;
}
/*
* =====================================================================================
*
* 带中文注释的汇编代码 (Assembly with Chinese Comments)
*
* =====================================================================================
*/
// JNI_OnLoad 函数的汇编实现
JNI_OnLoad:
0x630 lea rsp, [rsp-18h] // 在栈上分配 0x18 (24) 字节的临时空间。
0x635 mov edx, 10004h // 将 JNI 版本号 JNI_VERSION_1_4 (0x10004) 放入 edx,作为 GetEnv 的参数和最终返回值。
0x63a mov rax, fs:28h // 从 fs:28h 加载栈保护金丝雀值到 rax。这是一种防止栈溢出的安全机制。
0x643 mov [rsp+18h+var_10], rax // 将金丝雀值存入栈中,用于函数返回前的完整性检查。
0x648 xor eax, eax // 清零 eax 寄存器。
0x64a mov rax, [rdi] // 第一个参数 rdi 包含 JavaVM* vm 指针,解引用以获取其函数指针表。
0x64d mov rsi, rsp // 将 rsp (当前栈指针) 放入 rsi。这里将用于存放 GetEnv 函数返回的 JNIEnv* 指针。
0x650 call qword ptr [rax+30h] // 调用 vm->GetEnv(vm, &env, version)。虚函数表中偏移量 0x30 对应 GetEnv。
0x653 mov edx, 0FFFFFFFFh // 预设默认的错误返回值 -1 (JNI_ERR) 到 edx。
0x658 test eax, eax // 测试 GetEnv 的返回值 (eax)。如果成功,eax 为 JNI_OK (0)。
0x65a jnz short loc_68F // 如果 GetEnv 失败 (返回值不为0),则直接跳转到函数末尾进行清理和返回。
0x65c mov rdi, [rsp+18h+var_18] // 从栈上加载 GetEnv 成功后得到的 JNIEnv* 指针到 rdi。
0x660 lea rsi, aGithubJp1017He // 将目标类名字符串 "github/jp1017/hellojni/MainActivity" 的地址加载到 rsi。
0x667 mov rax, [rdi] // rdi 此时包含 JNIEnv* env 指针,解引用以获取其函数指针表。
0x66a call qword ptr [rax+30h] // 调用 env->FindClass(env, "...")。JNIEnv 函数表中偏移量 0x30 对应 FindClass。
0x66d mov rdi, [rsp+18h+var_18] // 再次从栈上加载 JNIEnv* 指针到 rdi,准备作为 RegisterNatives 的第一个参数。
0x671 mov ecx, 1 // 将要注册的本地方法数量 (1) 放入 ecx。
0x676 mov rdx, cs:nativeMethod_ptr // 将包含本地方法信息的 JNINativeMethod 结构数组指针加载到 rdx。
0x67d mov rsi, rax // 将 FindClass 返回的 jclass (在rax中) 移动到 rsi,作为 RegisterNatives 的第二个参数。
0x680 mov r8, [rdi] // 再次解引用 JNIEnv* 指针获取函数表,存入 r8。
0x683 call qword ptr [r8+6B8h] // 调用 env->RegisterNatives(env, clazz, methods, count)。偏移量 0x6B8 对应 RegisterNatives。
0x68a mov edx, 10004h // 注册成功后,将函数的最终返回值设置为 JNI_VERSION_1_4。
loc_68F: // 函数清理和返回部分
0x68f mov rcx, [rsp+18h+var_10] // 从栈中加载之前保存的金丝雀值到 rcx。
0x694 xor rcx, fs:28h // 与当前fs:28h处的金丝雀值进行异或运算。如果栈未被破坏,结果应为0。
0x69d mov eax, edx // 将最终的返回值(成功时的版本号或失败时的-1)移到 eax。
0x69f jnz short loc_6A7 // 如果金丝雀值不匹配 (异或结果不为0),说明栈可能已被破坏,跳转到错误处理。
0x6a1 lea rsp, [rsp+18h] // 释放栈帧,恢复栈指针。
0x6a6 retn // 从函数返回。
loc_6A7: // 栈检查失败处理
0x6a7 call ___stack_chk_fail // 调用栈破坏错误处理函数,通常这会导致程序立即终止。