安卓代码加固
安卓代码加固(10):ABI门禁
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 里的那一次比较。