ArturoYi
安卓代码加固
so 里的资源路径、实现类名、方法名按 0x5A 异或存放,用完立即清零。

对 libhiddendecrypt.so 执行 strings,不应直接得到 payload/hidden.dex.enc 或 HiddenLandingPage。这些字面量在源码里写成 uint8_t 数组,运行时再异或还原。

hidden-sdk/src/main/cpp/hidden_bridge.cpp
#define XOR_KEY 0x5Au

static void xor_decode(char *dst, const uint8_t *src, size_t n) {
    for (size_t i = 0; i < n; ++i) {
        dst[i] = static_cast<char>(src[i] ^ XOR_KEY);
    }
    dst[n] = '\0';
}
这只是提高扫描字符串的成本,不是密码学保护。密钥是单字节 0x5A,知道算法就能还原。它要阻止的是:打开 so 就能搜到类名和路径。

隐藏资源路径

read_asset 不写 "payload/hidden.dex.enc"。22 个字节解开后才是这条路径:

hidden-sdk/src/main/cpp/hidden_bridge.cpp
static const uint8_t path_enc[] = {
        0x2a, 0x3b, 0x23, 0x36, 0x35, 0x3b, 0x3e, 0x75, 0x32, 0x33, 0x3e,
        0x3e, 0x3f, 0x34, 0x74, 0x3e, 0x3f, 0x22, 0x74, 0x3f, 0x34, 0x39
};
char path[32];
xor_decode(path, path_enc, sizeof(path_enc));
AAsset *asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER);
hidden_secure_zero(path, sizeof(path));

打开后立刻清除栈上的明文路径。Java 的 HiddenCrypto.ASSET_PATH 仍是明文字符串,但主流程不再用它读取文件。

隐藏实现类名

加载时的 FQCN 同样编码。解开后是 com.example.minidex.hidden.HiddenLandingPage:

hidden-sdk/src/main/cpp/hidden_bridge.cpp
static const uint8_t cls_enc[] = {
        0x39, 0x35, 0x37, 0x74, 0x3f, 0x22, 0x3b, 0x37, 0x2a, 0x36, 0x3f,
        0x74, 0x37, 0x33, 0x34, 0x33, 0x3e, 0x3f, 0x22, 0x74, 0x32, 0x33,
        0x3e, 0x3e, 0x3f, 0x34, 0x74, 0x12, 0x33, 0x3e, 0x3e, 0x3f, 0x34,
        0x16, 0x3b, 0x34, 0x3e, 0x33, 0x34, 0x3d, 0x0a, 0x3b, 0x3d, 0x3f
};
char cls_name[64];
xor_decode(cls_name, cls_enc, sizeof(cls_enc));
jstring jname = env->NewStringUTF(cls_name);
hidden_secure_zero(cls_name, sizeof(cls_name));

改包名时必须同步修改这组字节,并重新编译 so。

按名查找方法

mid_by_xor 把方法名解到栈上 64 字节缓冲,GetMethodID 之后立刻 hidden_secure_zero:

hidden-sdk/src/main/cpp/hidden_bridge.cpp
static jmethodID mid_by_xor(
        JNIEnv *env, jclass cls,
        const uint8_t *name_enc, size_t name_len,
        const char *sig
) {
    char name[64];
    xor_decode(name, name_enc, name_len);
    jmethodID mid = env->GetMethodID(cls, name, sig);
    hidden_secure_zero(name, sizeof(name));
    return mid;
}

JNI 签名(例如 (Landroid/content/Context;)Z)目前仍是明文字符串。隐藏的是 业务方法名。

编码数组解开后
path_encpayload/hidden.dex.enc
cls_enccom.example.minidex.hidden.HiddenLandingPage
abi_encgetAbiVersion

完整方法名对照见 指令分发 的表。例如 op 7 的字节解开是 performAnswer,op 13 是 applyScreenProtection。

改名时如何同步

改 Kotlin 方法名

只改 HiddenLandingPage 不够。so 会 GetMethodID 失败,表现为加载成功,但 invoke 没有实际效果。

重算 XOR 字节

每个字符异或 0x5A。例如 's' ^ 0x5A == 0x29,其余字符同理。

成对升级 ABI

方法表变化后,应提高 ABI门禁 的版本号,避免旧 so 调用新 dex。

Kotlin val abiVersion 在 JNI 里是 getAbiVersion。属性改名后,XOR 数组也要改成新的 getter 名。

下一步

Copyright © 2026