调试器如何窥视另一个进程的内存?

cpp*_*der 7 c++ unix memory debugging

当每个进程都有自己的私有内存空间,没有外部进程可以访问时,调试器如何访问进程的内存空间?

例如,我可以使用gdb将gdb附加到正在运行的进程中gdb -p <pid>
.我可以通过gdb访问此进程的所有内存.

gdb如何做到这一点?

我在SO中阅读了相关问题,似乎没有帖子回答这一点.

Mat*_*son 11

由于这个问题被标记为Linux和Unix,我将对David Scwartz所说的内容进行一些扩展,简而言之就是"操作系统中有一个API".同样的基本原则也适用于Windows,但实际的实现是不同的,虽然我怀疑操作系统内部的实现做了同样的事情,但是没有真正的方法可以知道,因为我们无法检查Windows的源代码(但是,可以了解操作系统和处理器的工作原理,找出必须发生的事情!)

Linux有一个名为的函数ptrace,它允许一个进程(在某些权限检查之后)以各种方式检查另一个进程.这是一个电话,但第一个参数是"你想做什么".以下是一些最基本的例子 - 还有几十个用于较少"常见"操作:

  • PTRACE_ATTACH - 连接到流程.
  • PTRACE_PEEKTEXT - 查看附加进程的代码内存(例如反汇编代码)
  • PTRACE_PEEKDATA - 查看附加进程的'数据存储器(显示变量)
  • PTRACE_POKETEXT - 写入进程'代码存储器
  • PTRACE_POKEDATA - 写入进程'数据存储器.
  • PTRACE_GETREGS - 复制当前的寄存器值.
  • PTRACE_SETREGS- 更改当前寄存器值(例如set variable x = 7,如果x恰好在寄存器中的调试命令)

在Linux中,由于内存"完全相同",PTRACE_PEEKTEXT并且PTRACE_PEEKDATA实际上是相同的功能,因此您可以在代码中为PTRACE_PEEKDATA地址和地址提供地址,例如,在堆栈中PTRACE_PEEKTEXT,它将非常乐意为您复制.区别在于OS /处理器组合,其中存储器在DATA存储器和CODE存储器之间"分离".大多数现代操作系统和处理器都没有做出这种区分.同样明显适用于PTRACE_POKEDATAPTRACE_POKETEXT.

所以,说"调试程序"使用:

long data = ptrace(PTRACE_PEEKDATA, pid, 0x12340128, NULL); 
Run Code Online (Sandbox Code Playgroud)

当使用PTRACE_PEEKDATAfor地址0x12340128 调用OS时,它将"查看"内存的相应内存映射0x12340128(页面对齐,使得0x12340000),如果存在,它将被映射到内核,然后数据从地址0x12340128复制到本地内存,内存未映射,复制的数据作为返回值传回.

手册说明了使用的启动:

父进程可以通过调用fork(2)并让生成的子进行PTRACE_TRACEME来启动跟踪,然后(通常)执行exec(3).或者,父母可以使用PTRACE_ATTACH开始跟踪现有过程.

有几页更多信息man ptrace.