高中生

- 金币
- 620
- 好评
- 0
- 信誉
- 98
|
发表于
2026-8-10 00:02:49
|
显示全部楼层
来自 天津
### 2. 脱壳 (frida dump dex)
- art::DexFile 结构 (x86\_64): vtable\@0, begin\_(数据指针)@8, size\_@16
- 从 Java 层反射 dalvik.system.DexFile.mCookie (long\[]), 每个非零 cookie 就是 DexFile\*; begin=p+8 读指针, size=p+16 读 u64
- 不能依赖 magic 校验(magic 被抹) —— 直接 dump begin 处 0x200000(2MB+) 原始内存
- dump 脚本验证: 先在 PC 端把 dump 的 bin 校验是否为合法 dex (修正 header 后再看)
- 关键: 脱壳前先运行一次原始 APK 让壳解出真实库到 files/templib/ (见 §5), 否则拿不到真实 .so
- 环境: frida 16.7.19 (x86\_64), frida-server 放 /data/local/tmp/frida-server (114MB, 需 root); 脚本在 d:\yy\Claude (dump\_dex\_attach\*.js / dump\_dex\_spawn\*.js)
- 反调试概览: 易盾检测 frida (frida-helper dex 注入 /data/local/tmp), 检测 ptrace, 检测 /proc/self/maps 中 frida-gadget; 快速读 /proc/pid/mem 或注入可能致 App 自杀; attach 失败时换 spawn (详见下方反调试详细清单)
### 2.1 易盾(NESEC)反调试详细清单
核心思想: 不是"检测到就拒绝运行", 而是"检测到就自杀" (exit/kill/raise signal), 伪装成闪退, 掩盖真实原因增加定位成本。
层级架构:
- Java 层 (壳 dex 30 类): 最弱, 易绕过
- Native 层 (libnesec.so / libnesec-x86.so): 主力, 反调试核心
- 内存/文件特征: 辅助
① Frida 检测 (本次亲历):
- /data/local/tmp 目录扫描: frida-server/frida-helper 文件痕迹 → 检测到即自杀
- frida-helper dex: Frida Java 注入会写 helper dex → 检测到即自杀
- /proc/self/maps 扫描模块名: frida-gadget / gum-js-loop → 自杀
- /proc/self/task 遍历线程名
- 端口探测: frida 默认 27042 → 尝试 connect 检测
- 应对: 改名 frida-server、spawn 模式早期 hook、Java 层反射脱壳避免 native hook
② ptrace 检测 (最经典):
- ptrace(PTRACE\_TRACEME) 自跟踪, 防止被调试器附加
- 轮询 /proc/self/status 的 TracerPid: 非 0 即被跟踪 → 自杀
- 检查 /proc/<pid>/stat、/proc/<pid>/wchan 判断调试状态
- 多线程同时 ptrace 增加对抗难度
- 应对: hook ptrace 返回 0 (注意 syscall 层面, 需 hook syscall 或 <ptrace@libc.so>); hook kill/raise 阻止自杀信号
③ 定时轮询 + 信号自杀 (易盾特色):
- 独立 native 守护线程, 每几百 ms 执行一轮完整检测
- 检测异常后不返回错误, 直接 raise(SIGSEGV) / kill(getpid(), SIGKILL)
- 部分版本延迟自杀 (检测后等几秒再杀), 让你误以为 hook 没生效
- 实战表现: 启动即崩且无 Java 异常栈, 即 native 静默自杀
④ 内存访问特征:
- /proc/self/maps 检查可执行页异常映射 (hook 注入的新 so 映射)
- 检查 libc 函数头字节是否被改成跳转指令 (Inline Hook 特征, 如 ldr pc 开头)
- /proc/self/environ、/proc/self/fd 调试器痕迹
- 影响: 常规 GOT hook / inline hook libc 会被识别 → 脱壳优先走 Java 层 (mCookie 反射)
⑤ 文件/目录完整性校验:
- 校验 assets/.nesec\_patch 存在性与大小
- 校验 APK 内 dex 签名/结构 (防篡改)
- dex magic 被抹除: 既是保护也是反静态分析
⑥ 环境检测 (辅助):
- 模拟器特征: qemu / goldfish / Build.FINGERPRINT
- root 检测: su 文件存在性
- 本次 Magisk+模拟器 环境未因 root 直接自杀, 但组合检测会计权重
实战应对策略:
1. Magisk 隐藏 root 或选无 root 环境先跑通脱壳
2. 清理 frida 痕迹: 改名 frida-server 文件名, 或用 --realm/换目录
3. attach 失败 → spawn 模式 (-f 包名 + %resume)
4. 优先 Java 层反射脱壳, 避免 native inline hook (触发 ④)
5. 自杀排查: 临时 hook kill/raise/ptrace 观察, 判断是哪种检测
### 3. 修复 dex (PC 端)
- dump 出的 bin 按 header 中 file\_size 截取 → 修正 header magic + checksum + signature → 得到合法 dex
- 26 个修复 dex 在 D:\yy\Claude\dump\_dex3\_fixed/; raw\_13 是业务主 dex (10.3MB)
- 业务 dex 共 80451 类, 合并后 11 个 dex
### 4. 重建 APK (PC 端 Python)
- 用 base.apk (原包) 作骨架: 保留 res/assets/Manifest, 替换 classes\*.dex 为修复后的 dex
- 中间产物: D:\yy\Claude\unpacked\_new\.apk (11 dex, 80451 类); 构建脚本 build\_apk.py
- 必须改 Manifest: android:name="com.netease.nis.wrapper.MyApplication" → 真实 Application 类 (com.ydtx.camera.App), 否则走壳逻辑
- 删除 .nesec\_patch / 壳相关类
- **必须清除壳特征 assets 才能让 MT 查壳不再显示易盾**: 易盾壳特征文件是 assets/nedig.properties + assets/nedata.db (脱壳后业务代码不引用, 可安全删除); 验证残留用 python zipfile 搜索 nedig|nedata|nesec|nshelper
- 注意: PC 端用 zipfile 重建会破坏 V2/V3 签名块 (签名降级为仅 V1), 必须再走 MT mt\_apk\_build(sign=true) 恢复 V1/V2/V3
### 5. 真实 .so 提取 (脱壳后 native 功能恢复的关键)
- 特征: 原始 APK 中所有 .so 全部是裁剪 stub (最大 736 字节, 仅 ELF 头+程序头, 无真实代码/符号), 真实库由壳从 .nesec\_patch 解密后运行时写入 /data/data/<pkg>/files/templib/
- 提取方法: 先安装运行原始 APK (壳会解出全部真实库), 再 root 拉取:
`adb shell "su -c 'mkdir -p /sdcard/templib_copy && cp /data/data/com.ydtx.camera/files/templib/*.so /sdcard/templib_copy/ && chmod 644 /sdcard/templib_copy/*'"`
`adb pull /sdcard/templib_copy/ D:\yy\Claude\templib_real\` (63 个真实 arm64 .so, 105MB)
- 替换: 用 zipfile 重建 APK, 把 lib/arm64-v8a/ 下同名 stub 替换为真实库 (脚本 D:\yy\Claude\rebuild\_lib.py); 63 real vs 58 stub, 多出的 5 个是壳库(libnesec\*/libInno\*/libnshelper)不放
- 验证真实性: 检查 ELF machine (183=arm64) + 文件大小 (真实库 MB 级, stub 仅几百字节)
### 6. MT 管理器编辑重建 (壳抽取方法)
- MT MCP: HTTP 服务 <http://127.0.0.1:8787/mcp> (adb reverse), APK 目录 /storage/emulated/0/MT2/mcp/
- 壳保护特征: 业务关键方法 (App.onCreate + 各 Activity.onCreate) 被标记 ACC\_NATIVE(0x100) code\_off=0, 方法体在壳 native 层 —— 去壳后必须重建 smali 实现否则 UnsatisfiedLinkError
- mt\_apk\_edit\_text 用 write\_target 模式整方法替换; 改前必须先 read 拿 targetVersion (同内容方法共享 hash)
- 重建模板:
- Application.onCreate: invoke-super + 关键初始化 (sput g, registerActivityLifecycleCallbacks, m2.e(ctx,"config"), v7/a.b().c(), XUI.init(p0))
- Activity.onCreate: invoke-super(实际父类) + return-void (保留注解); .registers 需 ≥2 (1 会 v0/p0 重叠 VerifyError) |
|