百趣云 百趣云的博客

腾讯乐固脱壳:dump dex 的时机选择决定成败

乐固的特点:懒加载与分片解密

腾讯乐固(legu)的识别特征:入口 com.tencent.StubShell.TxAppEntry,assets 里有 libshell.solibshella-x.so 等。它和 360/梆梆最大的不同是解密策略:乐固不是启动时一次性解密全部 dex,而是按需解密、分片加载——用到哪个类才解密哪部分。

这个差异决定了脱壳策略:启动后立刻 dump,只能拿到不完整的 dex;必须把 App 的主要功能都点一遍,触发所有类的加载,再 dump

正确的脱壳流程

第一步:spawn 启动,绕过反调试

frida -U -f com.target.app -l dump.js --no-pause

乐固的反调试相对温和(主要是 TracerPid 和端口检测),标准绕过脚本即可。

第二步:自动化遍历触发类加载

手动点太慢,写个简单的遍历:启动后通过 monkey 或 UI Automator 随机点击几分钟:

# 另开一个终端跑 monkey,覆盖主要页面
adb shell monkey -p com.target.app --pct-touch 80 --pct-motion 20 -v 500

第三步:dump

// dump.js
Java.perform(function() {
    // 延迟 30 秒,期间配合 monkey 遍历
    setTimeout(dumpAllDex, 30000);
});

function dumpAllDex() {
    var count = 0;
    Process.enumerateRanges('r--').forEach(function(range) {
        if (range.size < 4096 || range.size > 30 * 1024 * 1024) return;
        try {
            Memory.scan(range.base, range.size, '64 65 78 0a 30 33 35 00', {
                onMatch: function(addr) {
                    var size = addr.add(0x20).readU32();
                    if (size > 1024 && size < 50 * 1024 * 1024) {
                        count++;
                        console.log('[' + count + '] dex @ ' + addr + ' size=' + size);
                        send({type: 'dex', index: count}, addr.readByteArray(size));
                    }
                },
                onComplete: function() {}
            });
        } catch(e) {}
    });
    console.log('共 dump ' + count + ' 个 dex');
}

精髓一:判断 dump 是否完整

乐固脱壳最常见的失败是"dump 了但类不全"。验收方法:

# 把所有 dump 出的 dex 合并分析
jadx -d out dump1.dex dump2.dex dump3.dex
# 检查 AndroidManifest 里声明的 Activity 是否都有对应类

对照原 APK 的 AndroidManifest.xml,逐个检查四大组件的类是否存在且有方法体。缺哪个页面的类,就回去多点哪个页面再 dump。

精髓二:乐固的字符串与资源加密

乐固对部分字符串做了加密,dump 出的 dex 里会看到 TxAppEntry 相关的解密调用。处理思路:

  1. 运行时批量调用解密函数建映射表(Frida hook 解密函数,遍历所有密文)
  2. 写 jadx 插件或后处理脚本把 decrypt(0x1234) 替换成明文

精髓三:64 位与 32 位的差异

乐固在 64 位设备上加载 libshella-x.so(64 位壳),部分老脚本只 hook 了 32 位路径。Frida 脚本里注意:

// 确认当前进程位数
console.log(Process.arch);  // arm64 还是 arm
// libart 的符号在两种位数下参数布局不同,dump 脚本的参数索引要适配

与其他壳的对比速查

入口特征解密策略脱壳要点
360 加固StubApp启动全量解密启动后即可 dump
梆梆ApplicationWrapper启动解密+反调试强先过反调试
腾讯乐固TxAppEntry按需分片解密遍历后再 dump

总结

  1. 乐固的特征是按需解密,启动即 dump 必不完整
  2. monkey 遍历主要页面触发全量类加载,再动手 dump
  3. 验收对照 Manifest 的组件清单,缺类补点
  4. 注意 32/64 位壳的符号差异,脚本要做适配

交流微信:run1255

By 百趣云 阅读量:2 On