我想探索生命过程的记忆,当我这样做时,过程一定不会受到干扰 - 所以将gdb附加到进程(这会阻止它)不是一种选择.因此,我想从/ proc/kcore获取此信息(如果您知道另一种方法,请告诉我).所以我做了一个小实验.我创建了一个名为TEST的文件,里面只有"EXTRATESTEXTRA".然后我少用它打开它
$ less TEST
Run Code Online (Sandbox Code Playgroud)
我得到了这个过程的PID
$ ps aux | grep TEST
user 7785 0.0 0.0 17944 992 pts/8 S+ 16:15 0:00 less TEST
user 7798 0.0 0.0 13584 904 pts/9 S+ 16:16 0:00 grep TEST
Run Code Online (Sandbox Code Playgroud)
然后我使用此脚本创建所有文件的转储:
#!/bin/bash
grep rw-p /proc/$1/maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' | while read start stop; do gdb --batch --pid $1 -ex "dump memory $1-$start-$stop.dump 0x$start 0x$stop"; done
Run Code Online (Sandbox Code Playgroud)
(我在这个网站上找到了它https://serverfault.com/questions/173999/dump-a-linux-processs-memory-to-file)
$ sudo ./dump_all_pid_memory.sh 7785
Run Code Online (Sandbox Code Playgroud)
在此之后,我在所有转储文件中查找"TRATESTEX":
$ grep -a -o -e '...TRATESTEX...' ./*.dump
./7785-00624000-00628000.dump:HEXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
Run Code Online (Sandbox Code Playgroud)
所以我得出结论,必须在0x00624000和0x00628000之间出现这个字符串.因此我将偏移转换为十进制数,并使用dd从/ proc/kcore获取内存:
$ sudo dd if="/proc/kcore" of="./y.txt" skip="0" count="1638400" bs=1
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,文件y.txt充满了零(我没有找到我在其中寻找的字符串).
作为一个额外的惊喜,我使用不同的测试文件同时运行了一个simmilar测试,发现我正在使用的另一个测试字符串(两个进程同时运行较少)应该在同一个位置找到(倾销和greping给了相同的抵消).所以必须有一些我不明白的东西.
是不是/ proc/pid/maps应该显示内存的偏移量(即:如果它说"XXX"在偏移量0x10,另一个程序不能使用相同的偏移量,我是对的吗? - 这是我的第二个惊喜的来源)
如何读取/ proc/kmap以获取属于我知道的pid进程的内存?
总结答案并添加我自己的评论: - /proc/pid/maps显示内存的各个部分,因为进程看到它(每个进程都不同,在linux上搜索内存映射),所以不同的进程似乎是使用相同的内存部分(从他们的角度看).您可以从/ proc/pid/mem中读取此处指定的部分作为超级用户(或者像gdb这样的父进程使用ptrace) - 内存__CODE__与进程中的内存不同__CODE__- 所以要搜索进程的内存__CODE__,人们必须弄清楚进程的内存如何映射到内核内存(很多乱七八糟的东西和耗时)所以为了获得进程内存,首先要读取它的哪些区域__CODE__允许读/写/然后转储复制区域__CODE__.下面的脚本转储所有可写区域(来源:https://unix.stackexchange.com/questions/6301/how-do-i-read-from-proc-pid-mem-under-linux).编辑:修改后的工作python脚本被移动到它自己的答案,因此它可以被评论与问题不同.
dr *_*bob 28
如果您具有root访问权限且位于Linux系统上,则可以使用以下linux脚本(改编自Gilles优秀的unix.stackexchange.com答案以及上述问题中最初给出的答案,但包括SyntaxErrors而不是pythonic):
#!/usr/bin/env python
import re
import sys
def print_memory_of_pid(pid, only_writable=True):
"""
Run as root, take an integer PID and return the contents of memory to STDOUT
"""
memory_permissions = 'rw' if only_writable else 'r-'
sys.stderr.write("PID = %d" % pid)
with open("/proc/%d/maps" % pid, 'r') as maps_file:
with open("/proc/%d/mem" % pid, 'r', 0) as mem_file:
for line in maps_file.readlines(): # for each mapped region
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r][-w])', line)
if m.group(3) == memory_permissions:
sys.stderr.write("\nOK : \n" + line+"\n")
start = int(m.group(1), 16)
if start > 0xFFFFFFFFFFFF:
continue
end = int(m.group(2), 16)
sys.stderr.write( "start = " + str(start) + "\n")
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
print chunk, # dump contents to standard output
else:
sys.stderr.write("\nPASS : \n" + line+"\n")
if __name__ == '__main__': # Execute this code when run from the commandline.
try:
assert len(sys.argv) == 2, "Provide exactly 1 PID (process ID)"
pid = int(sys.argv[1])
print_memory_of_pid(pid)
except (AssertionError, ValueError) as e:
print "Please provide 1 PID as a commandline argument."
print "You entered: %s" % ' '.join(sys.argv)
raise e
Run Code Online (Sandbox Code Playgroud)
如果你将它保存为write_mem.py,你可以运行它(使用python2.6或2.7)或早期在python2.5(如果你添加from __future__ import with_statement):
sudo python write_mem.py 1234 > pid1234_memory_dump
Run Code Online (Sandbox Code Playgroud)
将pid1234内存转储到文件pid1234_memory_dump.
Bas*_*tch 17
对于过程1234,您可以通过顺序读取/proc/1234/maps(文本伪文件)来获取其存储器映射,并通过例如读取(2) -ing或mmap(2)读取虚拟存储器/proc/1234/mem- 稀疏伪文件的适当段.
但是,我相信你无法避免某种同步(可能与ptrace(2)一样gdb),因为进程1234可以(并且确实)随时改变其地址空间(使用mmap&related syscalls).
如果受监视的进程1234不是任意的,但是如果您可以改进它以便以某种方式与监视进程通信,则情况是不同的.
我不明白你为什么这么问.并且gdb能够在watch不停止过程的情况下进入某个位置.