ArturoYi
安卓代码加固
so 与加密实现约定整数版本 12。对不上就拒绝加载,避免新旧 AAR 错位。

libhiddendecrypt.so 按方法名和 JNI 签名调用加密 dex。如果改了 HiddenLandingPage 的方法表,却仍使用旧 so(或反过来),GetMethodID 会静默失败,表现为 init 成功,但所有 invoke 都没有实际效果。因此,加载末尾加了一道 整数版本 检查。

这里的 ABI 不是 CPU 的 armeabi / arm64,而是 SDK 与 landing-page 的协议版本。两边必须成对升级。

两边固定同一数字

so:

hidden-sdk/src/main/cpp/hidden_bridge.cpp
#define ABI_VERSION 12

实现类:

hidden-landing-page/src/main/java/com/example/minidex/hidden/HiddenLandingPage.kt
class HiddenLandingPage {
    val abiVersion: Int = 12
}

未初始化时,Java fallback 的 op 16 也返回 12,避免调试接口在加载前报出一个还没核对过的版本。

加载后立刻核对

构造实例之后,用 XOR 方法名取 getAbiVersion:

hidden-sdk/src/main/cpp/hidden_bridge.cpp
static const uint8_t abi_enc[] = {
        0x3d, 0x3f, 0x2e, 0x1b, 0x38, 0x33, 0x0c, 0x3f, 0x28, 0x29, 0x33, 0x35, 0x34
};
jmethodID abi_mid = mid_by_xor(env, impl, abi_enc, sizeof(abi_enc), "()I");
const jint abi = env->CallIntMethod(instance, abi_mid);
if (pending(env) || abi != ABI_VERSION) {
    pthread_mutex_unlock(&g_lock);
    return jerr(env, "ABI 不匹配");
}

对不上时 不会 设置 g_instance。Java 看到 LOAD_FAILED,文案类似「SDK 未初始化:加载失败(ABI 不匹配)」。之后所有 invoke 走 fallback。

最常见的错位,是旧 AAR 里的 so 搭配从新仓库拷出的 enc(或反过来)。更换 AAR 后应先 Clean,不要解压后再自行放入一份过期的 hidden.dex.enc。

什么时候加版本

改了以下内容就应将版本从 12 调整为 13,并同时修改 so 与 Kotlin:

  • HiddenLandingPage 方法增删、改名、改签名
  • nativeDispatch 的 case 与 XOR 数组
  • 密文布局(HDX1 头、nonce、算法)
  • ClassLoader 协议(例如不再无参构造)

只改来电 UI 文案、不改方法表,可以不动 ABI。

接入文档把当前版本写在显眼位置:当前 ABI:12。工具包升级时应成对更换,不要只换 so 或只换 enc。

和指令 16 的关系

invoke(16) 在已加载时走 getAbiVersion,未加载时返回常量 12。它用于调试当前协议号,不能代替 init 的失败码。真正拦截错位的,是 nativeInit 里的那一次比较。

下一步

  • XOR混淆:getAbiVersion 的字节从哪来
  • 总览:十种方式如何串起来
Copyright © 2026