/proc/<pid>/mem 是一个可以 lseek 的文件,文件偏移量就是虚拟地址。
pid=2453 start=$((0x7f8d4c000000)) # 起始地址 size=$((0x100000)) # 大小 sudo dd if=/proc/$pid/mem of=/tmp/dump.bin bs=1M skip=$start count=$size iflag=skip_bytes,count_bytes status=progress
关键点:
bs 只是 I/O 块大小,skip_bytes,count_bytes 让 skip/count 以字节为单位,否则 dd 会按 bs 计数。
如果 dd 版本老,不支持 skip_bytes,就用:
sudo dd if=/proc/$pid/mem of=/tmp/dump.bin bs=1 skip=$start count=$size
shell example:
#!/bin/sh
PID=$1
OUTFILE="/opt/mem_dump.bin"
# 清空旧文件
> $OUTFILE
# 逐行解析 /proc/$PID/maps
while read -r line; do
start_addr=$(echo $line | awk '{print $1}' | cut -d'-' -f1)
end_addr=$(echo $line | awk '{print $1}' | cut -d'-' -f2)
dd if=/proc/$PID/mem bs=1 skip=$(($(printf "%d" "0x$start_addr"))) count=$(($(printf "%d" "0x$end_addr") - $(printf "%d" "0x$start_addr"))) >> $OUTFILE 2>/dev/null
done < /proc/$PID/maps
shell example:
PID=$1
YOUR_ADDRESS=$2
gdb -batch -ex "attach $PID" \
-ex "x/200s 0x${YOUR_ADDRESS}" \
-ex "detach" \
-ex "quit" /proc/$PID/exe 2>/dev/null
shell example:
# Use gdb to search
PID=$1
gdb -batch \
-ex "attach $PID" \
-ex "set logging on /tmp/gdb_output.txt" \
-ex "printf \"Searching heap for 'avRecord'...\\n\"" \
-ex "find /s 0x004c0000, +0x10000, \"avRecord\"" \
-ex "printf \"\\n=== Found addresses, examining content ===\\n\"" \
-ex "x/300s \$1" \
-ex "x/300s \$2" \
-ex "x/300s \$3" \
-ex "detach" \
-ex "quit" /proc/$PID/exe 2>/dev/null
echo ""
echo "=== Results saved to /tmp/gdb_output.txt ==="
grep -B2 -A10 "avRecord" /tmp/gdb_output.txt | head -100
shell example:
#!/bin/bash
# dump_heap_region.sh
PID=1925
HEAP_START=0x004c0000
HEAP_SIZE_KB=212716
HEAP_SIZE_BYTES=$((HEAP_SIZE_KB * 1024))
echo "=== Dumping heap region ==="
echo "Start: $HEAP_START"
echo "Size: $HEAP_SIZE_KB KB ($HEAP_SIZE_BYTES bytes)"
# Method 1: Use gdb to dump this region
gdb -batch \
-ex "attach $PID" \
-ex "dump memory /tmp/heap_004c0000.bin 0x004c0000 0x004c0000 + $HEAP_SIZE_BYTES" \
-ex "detach" \
-ex "quit" /proc/$PID/exe 2>/dev/null
echo ""
echo "=== Searching for avRecord strings ==="
strings /tmp/heap_004c0000.bin | grep -B3 -A10 "avRecord" | head -100
echo ""
echo "=== Statistics ==="
echo "Total strings found: $(strings /tmp/heap_004c0000.bin | wc -l)"
echo "avRecord count: $(strings /tmp/heap_004c0000.bin | grep -c 'avRecord')"
echo "msgType count: $(strings /tmp/heap_004c0000.bin | grep -c 'msgType')"
echo "mediaId count: $(strings /tmp/heap_004c0000.bin | grep -c 'mediaId')"
echo ""
echo "=== Sample leaked messages ==="
strings /tmp/heap_004c0000.bin | grep '"cmd":"avRecord' | head -5
# Cleanup
rm -f /tmp/heap_004c0000.bin
Run it:
bash
chmod +x dump_heap_region.sh
sudo ./dump_heap_region.sh
🔧 Quick Interactive Check
bash
# Attach with gdb
gdb -p 1925
# Search for avRecord in the growing heap region
(gdb) find /b 0x004c0000, 0x004c0000 + 212716*1024, {0x61, 0x76, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64}
# This will take a moment to scan 208MB...
# Expected output:
# Pattern found at 0x07a12345
# Pattern found at 0x07b23456
# Pattern found at 0x08c34567
# ...
# 156 patterns found
# Examine first few matches
(gdb) x/50s 0x07a12345
(gdb) x/50s 0x07b23456
# You should see JSON like:
# 0x07a12345: "{\"cmd\":\"avRecord\",\"data\":[{\"beginTime\":\"2026-07-20 14:37:23\",..."
# Detach
(gdb) detach
(gdb) quit
shell example:
#!/bin/bash
# dump_heap_region.sh
PID=$1
HEAP_START=0x$2
HEAP_SIZE_KB=$3
HEAP_SIZE_BYTES=$((HEAP_SIZE_KB * 1024))
echo "=== Dumping heap region ==="
echo "Start: $HEAP_START"
echo "Size: $HEAP_SIZE_KB KB ($HEAP_SIZE_BYTES bytes)"
# Method 1: Use gdb to dump this region
gdb -batch \
-ex "attach $PID" \
-ex "dump memory /tmp/heap_004c0000.bin $HEAP_START $HEAP_START + $HEAP_SIZE_BYTES" \
-ex "detach" \
-ex "quit" /proc/$PID/exe 2>/dev/null