ice-wzl/goDumper
GitHub: ice-wzl/goDumper
goDumper 是一个用 Go 编写的轻量级进程内存转储脚本,支持在 Linux 和嵌入式系统上对指定进程进行定向或完整的内存转储。
Stars: 5 | Forks: 1
# goDumper
一个用于在 Linux 操作系统以及 MikroTik 等嵌入式系统中转储进程内存的简单脚本。goDumper 提供定向转储或完整内存转储功能。
# 用法
- 这个简单的脚本有两种模式:针对特定内存区域(如进程 heap 或 stack)的定向转储,或者完整转储(goDumper 将尝试转储进程的整个内存空间)。
## 完整转储
- 完整的进程内存转储:使用 `-p `
```
./godumper -p 1226246
[+] goDumper started
[+] Target PID: 1226246
[+] Successful memory dump for pid: 1226246
```
- 常见的情况是,某些内存区域无法被转储。goDumper 会直接跳过这些部分并提醒您它们已被跳过。goDumper 会提供其无法读取的内存范围,允许用户检查被跳过的区域。有关某些内存区域无法访问的一些原因,请参阅底部的 FAQ 部分。
- 验证被跳过的区域,以确保它不是像 `[stack]` 或 `[heap]` 这样的关键区域
```
cat /proc/1226246/maps
--snip--
7675b9b64000-7675b9b72000 r--p 0001f000 103:02 7892597 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.3
7675b9b72000-7675b9b76000 r--p 0002c000 103:02 7892597 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.3
7675b9b76000-7675b9b77000 rw-p 00030000 103:02 7892597 /usr/lib/x86_64-linux-gnu/libtinfo.so.6.3
7675b9b90000-7675b9b97000 r--s 00000000 103:02 7866848 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7675b9b97000-7675b9b99000 rw-p 00000000 00:00 0
7675b9b99000-7675b9b9b000 r--p 00000000 103:02 7866467 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7675b9b9b000-7675b9bc5000 r-xp 00002000 103:02 7866467 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7675b9bc5000-7675b9bd0000 r--p 0002c000 103:02 7866467 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7675b9bd1000-7675b9bd3000 r--p 00037000 103:02 7866467 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7675b9bd3000-7675b9bd5000 rw-p 00039000 103:02 7866467 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffe9803f000-7ffe98060000 rw-p 00000000 00:00 0 [stack]
7ffe98081000-7ffe98085000 r--p 00000000 00:00 0 [vvar] <-- The memory region we failed to access, expected
7ffe98085000-7ffe98087000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
```
## 定向转储
- 要进行定向转储,请使用 `-p` 指定目标 pid,并使用 `-r` 指定内存范围,后跟具体的内存范围。
- 通过查看 `/proc` 目录下进程的 `maps` 文件来获取内存范围
```
cat /proc/1226246/maps
--snip--
7ffe9803f000-7ffe98060000 rw-p 00000000 00:00 0 [stack] <-- Our target range to dump
7ffe98081000-7ffe98085000 r--p 00000000 00:00 0 [vvar]
7ffe98085000-7ffe98087000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
```
- 现在我们可以将内存范围提供给 goDumper。这是该进程 stack 的内存范围
```
./godumper -p 1226246 -r 7ffe9803f000-7ffe98060000
[+] goDumper started
[+] Target PID: 1226246
[+] Successful memory dump for pid: 1226246
```
- 转储文件将在 `goDumper` 二进制文件的 `pwd` 中创建,并命名为 `dump.`。例如,上述转储的结果文件名为 `dump.1226246`
## 编译
- 标准编译
```
git clone https://github.com/ice-wzl/goDumper.git
go build goDumper.go
# Binary 大小 amd64: 2.1M
```
- 为嵌入式系统编译更小的体积
```
go build -a -gcflags=all="-l -B" -ldflags="-w -s" goDumper.go
# Binary 大小 amd64: 1.4M
```
## FAQ
- **使用这个简单的脚本进行内存转储时,为什么某些内存部分会失败?**
- 内核级保护:即使内存区域具有读取权限,某些内核级的保护也可能阻止直接访问。例如,某些内存区域(特别是那些与设备文件相关的区域,如 /dev/jiffies,或特定的共享内存区域)可能具有限制,导致非 root 用户或从用户空间无法访问。
- 动态内存和映射文件更改:进程可能会在执行期间动态更改其内存映射。如果在读取 /proc/[pid]/maps 和尝试访问 /proc/[pid]/mem 之间内存映射发生了变化,您可能最终会尝试读取不再被映射或权限已更改的内存,从而导致输入/输出错误。
- 文件支持的内存区域:maps 文件中的某些条目指向内存映射文件(如 libc.so 或 libuc++.so)。即使具有读取权限,由于内核管理文件支持的内存区域的方式,访问它们有时也可能会导致错误。
- 物理或虚拟内存边界:当您尝试跨内存边界读取时,尤其是在 segment 的末尾,可能会遇到输入/输出错误。例如,如果内存 segment 之间的地址存在某些重叠,或者范围没有完美对齐,就可能发生这种情况。
- **为什么不使用功能更全面的工具,例如:https://github.com/PhilippePitzClairoux/go-memory-dumper**
- 我想保持这个脚本的简单和轻量级,以便它可以在没有任何外部依赖的情况下使用,仅需 stdlib。此外,我想尽可能保持二进制文件体积的最小化,以便在嵌入式系统上更好地使用。我通常在磁盘空间和资源受到更多限制的嵌入式系统上使用这个程序。这个脚本只是完成工作的另一个工具,请选择最适合您特定应用的方式!
## TODO
标签:EVTX分析, Ruby on Rails, 内存转储, 嵌入式系统, 日志审计, 流量嗅探, 系统底层, 进程内存