mohamad-aljeiawi/android-memdump-elf

GitHub: mohamad-aljeiawi/android-memdump-elf

单文件Python工具,通过ADB从Android进程内存dump原生库并重建ELF节头,使加壳保护的.so文件能在IDA/Ghidra中正常分析。

Stars: 0 | Forks: 0

android-memdump-elf banner

直接从进程内存中 Dump 并重建 Android 原生库—— 单个 Python 脚本,零编译。

快速开始工作原理用法ELF 修复器环境要求致谢

## 这是什么? 一个单文件 Python 工具,具备以下功能: 1. 通过 ADB 从运行中的 Android 进程内存中 **Dump** 已加载的 `.so` 库 2. 通过从头重建所有 16 个节头**修复** Dump 下来的 ELF 修复后的输出文件可以在 IDA Pro、Ghidra 或任何 ELF 分析工具中正常加载 —— 包含完整的符号解析、`.plt`/`.got` 恢复以及正确的节映射。 **专为以下场景构建:** 安全研究人员、逆向工程师,以及调试加壳/保护原生库(如 UPX、Bangcle、360 加固、腾讯等)的开发者。 ## 功能特性 | 功能 | 描述 | |---|---| | **区域感知 Dump** | 单独读取每个映射区域 —— 绝不触碰未映射的间隙 | | **分块传输** | 将大区域拆分为 2 MB 的块,并显示实时进度 | | **ELF 节重建器** | 仅凭 `PT_DYNAMIC` 即可重建 16 个节头 | | **ELF32 + ELF64** | 完整支持 ARM (armeabi-v7a) 和 AArch64 (arm64-v8a) | | **单文件** | 仅需一个 `memdump.py` —— 无需编译,除 Python 3.7+ 外无其他依赖 | | **仅修复模式** | 无需 ADB 即可修复任何现有的内存 Dump | | **反反 Dump** | 可选的 `SIGSTOP` 以在提取期间冻结进程 | ## 快速开始 ``` # 克隆 git clone https://github.com/mohamad-aljeiawi/android-memdump-elf.git cd android-memdump-elf # 使用单条命令 Dump + 修复 python memdump.py com.example.app libtarget.so --fix # 输出: # libtarget_dump.bin ← 原始内存 dump # libtarget_dump_fixed.so ← 可用于 IDA/Ghidra ``` ## 工作原理 ``` flowchart TD A[Start memdump.py] --> B[Connect via ADB] B --> C[Find PID by package name] C --> D["Read /proc/PID/maps"] D --> E[Filter regions matching library name] E --> F[Split each region into 2 MB chunks] F --> G["Dump each chunk via dd from /proc/PID/mem"] G --> H[Pull chunks to PC + merge with zero-filled gaps] H --> I{--fix flag?} I -->|No| J[Output: raw dump] I -->|Yes| K[Parse ELF header + Program Headers] K --> L["Walk PT_DYNAMIC to find all section addresses"] L --> M[Rebuild 16 section headers] M --> N[Fix relocation bias + symbol values] N --> O["Append .shstrtab + section header table"] O --> P[Output: fixed .so ready for IDA] style A fill:#1a1a2e,color:#fff style P fill:#16213e,color:#fff style K fill:#0f3460,color:#fff style M fill:#0f3460,color:#fff ``` ### Dump 阶段 该工具读取 `/proc/PID/maps` 以查找属于目标库的所有内存区域。它不是读取一个巨大的连续范围(这会在未映射的间隙处停滞),而是以 2 MB 的块为单位单独 Dump 每个映射区域: ``` Region 0: 0x7400000000 - 0x7405700000 [87 MB] r--p → 44 chunks Region 1: 0x7405700000 - 0x7405713000 [76 KB] r-xp → 1 chunk Region 2: 0x7405713000 - 0x7405715000 [8 KB] rwxp → 1 chunk ... ``` 每个块都是一个直接的 `adb shell su -c 'dd ...'` 调用,并立即拉取和清理。区域之间的未映射间隙用零字节填充,以保留正确的偏移量。 ### 修复阶段 修复器完全根据 `PT_DYNAMIC` 中可用的信息重建 ELF 节头: ``` flowchart LR DYN["PT_DYNAMIC"] --> SYMTAB["DT_SYMTAB → .dynsym"] DYN --> STRTAB["DT_STRTAB → .dynstr"] DYN --> HASH["DT_HASH → .hash\n(+ symbol count)"] DYN --> REL["DT_REL/RELA → .rel.dyn"] DYN --> JMPREL["DT_JMPREL → .rel.plt"] DYN --> PLTGOT["DT_PLTGOT → .got"] DYN --> INIT["DT_INIT_ARRAY → .init_array"] DYN --> FINI["DT_FINI_ARRAY → .fini_array"] style DYN fill:#e63946,color:#fff ``` **重建的节(共 16 个):** `NULL` · `.dynsym` · `.dynstr` · `.hash` · `.rel.dyn` · `.rel.plt` · `.plt` · `.text` · `.ARM.exidx` · `.fini_array` · `.init_array` · `.dynamic` · `.got` · `.data` · `.bss` · `.shstrtab` **应用的额外修复:** - 从程序头中的所有 `p_vaddr` / `p_offset` 中减去加载偏移 - 设置 `p_offset = p_vaddr` 和 `p_filesz = p_memsz`(内存布局 = 文件布局) - 修复 `R_ARM_RELATIVE` / `R_AARCH64_RELATIVE` 重定位偏移 - 修复 `R_ARM_JUMP_SLOT` / `R_AARCH64_JUMP_SLOT` 条目 - 从 `.dynsym` 中的所有 `st_value` 减去偏移 - 纠正无效的符号类型(为了 IDA 兼容性) - 从 `R_*_RELATIVE` 指向的值中减去镜像基地址 ## 用法 ### Dump + 修复(最常用) ``` python memdump.py com.example.app libtarget.so --fix ``` 生成: - `libtarget_dump.bin` — 原始内存 Dump - `libtarget_dump_fixed.so` — 带有节头、可直接用于 IDA 的文件 ### 自定义输出名称 ``` python memdump.py com.example.app libtarget.so -o my_dump.bin --fix ``` ### 修复现有 Dump(无需 ADB) ``` python memdump.py --fix-only dumped.bin 0x740004D000 fixed.so ``` ### Dump 期间冻结进程(反反 Dump) ``` python memdump.py com.example.app libtarget.so --fix --stop ``` 在 Dump 前发送 `SIGSTOP`,在之后发送 `SIGCONT`。当应用检测到内存读取时很有用。 ### 将每个区域保存为单独的文件 ``` python memdump.py com.example.app libtarget.so --segments ``` ### 更大的块大小(在良好的 USB 连接上速度更快) ``` python memdump.py com.example.app libtarget.so --fix --chunk-mb 4 ``` ### 所有选项 ``` python memdump.py [-h] [--fix] [--stop] [--segments] [--chunk-mb N] [-o OUTPUT] [--fix-only DUMP BASE_HEX OUTPUT] package library ``` | 标志 | 描述 | |---|---| | `--fix` | Dump 后重建 ELF 节头 | | `--stop` | 在 Dump 期间向进程发送 `SIGSTOP` | | `--segments` | 将每个内存区域保存为单独的文件 | | `--chunk-mb N` | 块大小,单位 MB(默认值:2.0) | | `-o OUTPUT` | 自定义输出文件路径 | | `--fix-only` | 仅修复模式 —— 不使用 ADB,参数为 ` <基地址_hex> <输出文件>` | ## 示例输出 ``` ============================================================ memdump — ADB Memory Dumper + ELF Fixer ============================================================ Package : com.tencent.ig Library : libUE4.so Output : dumped.bin Fix ELF : yes ============================================================ [*] Checking ADB... [+] Device connected. [+] PID: 21110 [*] Reading /proc/21110/maps [+] 61 regions for 'libUE4.so': Mapped : 239,751,168 bytes (228.6 MB) Gaps : 6,721,536 bytes (6.4 MB) [*] Dumping 167 chunks (228.6 MB)... [ 167/167] 100.0% 229/229 MB (2.2 MB/s) [+] Dump complete: 102s [*] Fixing ELF headers (base=0x740004D000)... [*] ELF class: ELF64 [+] Fixed ELF: dumped_fixed.so (246,473,870 bytes) ============================================================ Done in 108s (2.1 MB/s) ============================================================ ```

IDA Pro comparison — before and after fix

## 环境要求 | 要求 | 详情 | |---|---| | **Python** | 3.7 或更高版本 | | **ADB** | 已安装并在 PATH 中 | | **Android 设备** | Root 权限(`su` 可用) | | **USB** | 已启用调试,设备已授权 | 不需要外部 Python 包 —— 仅使用 `struct`、`subprocess`、`re`、`os`、`sys`、`argparse`、`time`、`pathlib`。 ### 设备设置检查清单 ``` # 验证 ADB 连接 adb devices # 验证 root 权限 adb shell su -c "whoami" # should print "root" # 验证目标 app 正在运行 adb shell pidof com.example.app ``` ## ELF 修复器如何工作(技术细节) 当 Android linker 将 `.so` 加载到内存中时,**节头表会被丢弃** —— 它在运行时不需要。加壳器利用这一点,通过剥离或破坏节头来阻止静态分析。 本工具使用内存中**必须保留**的唯一结构来重建它们:**dynamic segment**(`PT_DYNAMIC`)。 ### 重建算法 ``` 1. Parse ELF header → get program header table offset + count 2. Walk program headers: - Find first PT_LOAD → compute load bias - Find PT_DYNAMIC → get dynamic section location - Find PT_LOPROC → get .ARM.exidx location 3. Fix all program headers: subtract bias, set offset = vaddr 4. Walk dynamic entries (DT_SYMTAB, DT_STRTAB, DT_HASH, ...): - Each tag gives the address + size of a section - Subtract bias from all pointers 5. Compute derived sections: - .plt starts after .rel.plt (aligned) - .text starts after .plt, ends at .ARM.exidx - .got starts after .dynamic - .data starts after .got (page-aligned) 6. Fix relocations: subtract bias from R_*_RELATIVE offsets 7. Fix symbols: subtract bias from st_value 8. Write: original body + .shstrtab + 16 section headers ``` ## 致谢 **ELF 节头修复器**是 [**elf-dump-fix**](https://github.com/maiyao1988/elf-dump-fix)(作者:**maiyao1988**,后续由 [**strazzere**](https://github.com/strazzere/elf-dump-fix) 维护)中 C++ 逻辑的纯 Python 移植。从 `PT_DYNAMIC` 重建节头的原始算法由 maiyao1988 设计。 **与原版的主要区别:** - 纯 Python —— 无需编译,可在 Windows/macOS/Linux 上运行 - 集成 Dump + 修复于单一工具中 - 区域感知的分块 Dump(可处理 200+ MB 的库) - 实时进度跟踪 ## 许可证 MIT 许可证 —— 详见 [LICENSE](LICENSE)。
标签:360加固, ADB调试, Android安全, ARM64, ELF32, ELF64, ELF重构, Ghidra, Hook检测, IDA Pro, Native库分析, Ruby on Rails, SecList, SO文件Dump, UPX脱壳, URL提取, 二进制分析, 云安全运维, 云资产清单, 内存取证, 内存转储, 加壳识别, 反编译, 后渗透, 流量嗅探, 目录枚举, 移动安全, 端点检测与响应, 脱壳工具, 腾讯加固, 进程内存, 逆向工具, 逆向工程, 配置审计