高中生

- 金币
- 493
- 好评
- 13
- 信誉
- 100
|
李贺给我发了个样本
这个加固有点意思,用脱壳机可以扫出类,但是dump不出dex文件,李贺说用内存扫描也扫不到dex
于是来了兴趣,然后交给codex去内存扫描,扫了一轮确实扫不到,有点意思,dex肯定在内存,怎么会扫不到呢,于是就进行了更深层次的扫描,具体呢,我做成了skill,打包了分析报告,样本,自行下载学习
免回复下载地址:https://pan.删quark删.cn/s/2c639115fb5c
--------------------------
压缩包内已附带本次AI任务的完整分析报告和样本/脚本等
--------------------------
不想下载压缩包的,我下面就简单的说一下这玩意儿的原理(让AI整理的)
--------------------------
这次分析的目标是已经安装在 root 手机上的 App Cloner 3.6.8,包名为 com.applisto.appcloner。目标不是重复提取 APK 中原本就存在的 classes.dex,而是找出应用启动后由 ART 实际持有、但无法通过普通 DEX 魔数扫描完整发现的隐藏代码。
最终成功恢复出两个主要隐藏 DEX,大小分别为 27,398,624 字节和 25,651,296 字节。第一个 DEX 中真实定义了 com.applisto.appcloner.activity.MainActivity,共包含 546 个 App Cloner 包名下的类定义;第二个 DEX 包含 136 个 App Cloner 包名下的类定义。另外还保留了一个 788 字节的小型合法应用 DEX。三个文件都通过了 DEX 完整性和结构验证。
为什么必须做深层扫描
普通内存扫描通常搜索 dex\n035\0、dex\n039\0 或 cdex 等魔数,再从 header 的 file_size 读取一段连续内存。这种方法只适用于头部完整、布局连续的 DEX。
本次样本中的真实代码并不是这种状态。保护层把 DEX header 中最容易被扫描器识别的字段清除了,包括 magic、checksum、signature、file_size、header_size、endian tag 和多个 section offset。同时,DEX 的 header、字符串表、类型表、方法表和 class_defs 等数据并不一定处于同一段连续映射中,中间还夹有不可读页面和不属于 DEX 的匿名内存。
但是应用仍然能够运行,因为 ART 加载 DEX 后会创建 DexFile C++ 对象。这个对象已经缓存了 begin、size、header、string_ids、type_ids、proto_ids、field_ids、method_ids 和 class_defs 等直接指针。即使原始 header 被破坏,ART 仍可通过这些指针查找和执行类。
所以关键思路不是继续寻找 DEX 文件头,而是寻找 ART 当前正在使用的 DexFile 对象。
第二次扫描的具体步骤
第一步,彻底冷启动目标应用。
先强制停止包,再重新启动入口 Activity,避免沿用旧进程中的残留状态。启动后等待保护层完成真实代码加载,再开始扫描。
第二步,通过应用 UID 定位全部目标进程。
不能只使用 pidof com.applisto.appcloner。本次目标进程属于 App Cloner 的 UID,但它在 ps、cmdline 和内核可见名称中显示成了 com.android.systemui。如果按包名或进程名过滤,就会直接漏掉真实进程。
正确做法是从包管理器取得应用的精确 UID,然后扫描 ps 输出中 UID 完全相等的所有 PID。这样即使主进程改名,或者应用存在同 UID 子进程,也能全部覆盖。
第三步,读取目标系统自己的 libdexfile.so。
从手机上的 libdexfile.so 获取 art::StandardDexFile 和 art::CompactDexFile 的 vtable 符号偏移,再结合该库在目标进程中的实际加载基址,计算运行时 vptr。
ARM64 使用的 C++ ABI 中,对象首字段通常是 vptr。运行时 vptr 一般等于库基址加 vtable 符号地址,再加两个指针宽度,也就是 16 字节的 vtable 前缀。
第四步,按 vptr 枚举真实 DexFile 对象。
短暂向目标进程发送 SIGSTOP,保证读取 header、map 和各 section 时内存不会在中途变化。随后遍历进程的可读映射,在 /proc/PID/mem 中搜索与 StandardDexFile vptr 相同的 8 字节值。
每一个命中位置都可能是一个真实的 ART DexFile 对象。再从对象中解析 begin、size、header 和各 section 指针,并进行范围、对齐、数量、映射归属等检查,排除偶然匹配。
这一步成功找到了两个异常的 StandardDexFile 对象。它们的逻辑大小分别约为 27.4 MB 和 25.6 MB,header 被独立保存且部分清零,各 section 指针仍然有效,逻辑地址范围横跨多个匿名映射和不可读空洞。
第五步,重建稀疏 DEX。
先创建一个长度等于 DexFile.size 的全零文件。然后读取 /proc/PID/maps,把每段可读映射与 begin 到 begin 加 size 的逻辑区间求交,只把交集数据写入对应的文件偏移。不可读空洞继续保持为零,不能用一次连续读取覆盖整个范围,否则读取会在第一个空洞处失败或只得到截断文件。
DEX 中每个固定 section 的逻辑 offset 可以用“ART 缓存的 section 指针减去 begin”计算。这样能够恢复 string_ids、type_ids、proto_ids、field_ids、method_ids 和 class_defs 的真实位置。
这里有一个很容易踩的坑:ART 对象中的字段排列顺序和 DEX header 的字段顺序并不相同。不能凭记忆直接复制,必须使用普通 DexFile 对象和 map list 双重确认,否则 verifier 会报告 section offset 错误。
第六步,修复 DEX header 和完整性字段。
恢复 dex\n035\0 magic、实际 file_size、0x70 的 header_size、0x12345678 endian tag,以及各固定 section 的 size 和 offset。保留下来的 map list 用来确定 data 区、各类变长 section 和合法边界。
初次拼接出的逻辑范围中可能混入与 DEX 无关的堆数据,官方 verifier 会报告 Non-zero padding。此时只能依据 map list 和 verifier 指出的边界清理未声明的 padding,不能随意清零大块区域,否则可能破坏 code_item、class_data、debug_info、annotation 或 encoded_array。
结构修复完成后,重新计算从 0x20 到文件末尾的 SHA-1 signature,再计算从 0x0c 到文件末尾的 Adler-32 checksum。
第七步,执行严格验证。
每个候选文件都要检查 magic、文件长度、header_size、endian tag、section 范围、SHA-1 和 Adler-32,并使用 Android SDK 的 dexdump 完整遍历结构。
业务验收不能只搜索 MainActivity 字符串。字符串可能只是方法签名、父类引用或 MainActivity$xxx 形式的内部类引用。真正的成功条件是 class_defs 中存在精确描述符 Lcom/applisto/appcloner/activity/MainActivity;。
本次第一个重建 DEX 满足这个条件,因此可以确认恢复到的是 ART 实际加载的真实应用代码,而不是 APK 中已有 DEX 的重复副本。
第八步,排除系统 DEX并保存结果。
vtable 扫描会枚举到大量 boot、framework、APEX 和 dalvik-cache 中的系统 DexFile。过滤不能只看路径是否以 /system 开头,因为系统 DEX 也可能显示为匿名映射,或者位于 /data/dalvik-cache 中。
最终同时使用来源路径、映射描述和 class_defs 命名空间过滤。只有至少定义一个目标包名前缀类的候选,才进入应用 DEX 结果集。通过验证的文件按 SHA-256 去重,保存到本地,并复制到手机的 /sdcard/MT2/apks 目录。扫描结束后无论成功或失败都必须发送 SIGCONT,避免目标进程永久停住。
这次成功的核心原因
核心不是把扫描范围扩大,而是改变了扫描对象。
普通方法寻找的是“看起来像完整 DEX 文件的连续字节”。深层方法寻找的是“ART 已经认可并正在使用的 DexFile 对象”。保护层可以擦除文件头、拆散 section、伪装进程名,却不能在代码正常运行的同时让 ART 忘记这些代码的位置。只要 ART 仍要解析类、方法和字段,DexFile 对象或等价运行时数据结构就必须保存可用指针。
因此,vtable 是定位对象的入口,DexFile 中缓存的 section 指针是重建依据,map list 是区分真实 DEX 数据和堆内杂质的边界依据,class_def 则是判断目标类是否真正恢复的最终证据。
方法边界
本次方案只读取 root 权限下的 /proc/PID/maps、/proc/PID/mem 和设备自身的 libdexfile.so,没有使用 Frida、ptrace、调试器、LD_PRELOAD 或进程注入。
vtable 偏移和 DexFile 对象布局不是跨 Android 版本稳定的公开 ABI。Android 版本、ROM、编译器、LTO、厂商补丁或 32/64 位 ABI 变化后,都必须重新提取目标设备的符号并验证字段布局。不能把一台 Android 10 设备上的偏移直接硬编码到其他设备;若 libdexfile.so 指纹不一致,深扫工具应明确停止,而不是在没有找到目标类时仍然宣称扫描完成。
最终判断标准很简单:扫描所有精确 UID 进程,找到真实 DexFile 对象,按 map 和 section 重建,通过完整 verifier,在 class_defs 中精确找到目标类,排除系统 DEX,并保证本地与手机端文件哈希一致。缺少其中任一关键条件,都只能算候选,不能算成功恢复。
--------------------------
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
-
查看全部评分
总评分:金币 +2
|