2014-09-25 61 views
4

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

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

gdb如何做到这一点?

我在SO中阅读了相关问题,似乎没有文章回答这一点。

+0

这个问题并不宽泛。问题是关于调试器访问进程内存空间的概念。 – cppcoder 2014-09-25 07:09:03

+0

这实际上取决于涉及的调试器以及它连接到目标进程的方式。你可能想缩小它的范围(例如,当使用'gdb'来启动进程时)。我没有投票结束,但是你可能会缩小它的范围,或者将你想了解的方法命名(比如远程调试)。 – Mario 2014-09-25 07:11:52

回答

9

由于问题标记为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_PEEKTEXTPTRACE_PEEKDATA实际上同样的功能,所以你可以给代码PTRACE_PEEKDATA的地址和一个地址,比如PTRACE_PEEKTEXT的栈,它会很高兴地为你复制这个地址。区别在于内存在数据存储器和代码存储器之间“分离”的操作系统/处理器组合。大多数现代操作系统和处理器都没有这样的区别。 PTRACE_POKEDATAPTRACE_POKETEXT也同样适用。

所以说,“调试程序”的用途:

long data = ptrace(PTRACE_PEEKDATA, pid, 0x12340128, NULL); 

当OS是带一个PTRACE_PEEKDATA的地址0x12340128,将“看”的内存相应的内存映射在0x12340128(页如果它存在,它将被映射到内核中,然后将数据从地址0x12340128复制到本地内存中,未映射的内存以及作为返回值传回的复制数据。

手动状态的使用作为的发起:

母体可以通过调用叉(2)和具有 所得子做PTRACE_TRACEME发起跟踪,随后(通常)由一个exec( 3)。 或者,父母可以使用PTRACE_ATTACH开始对现有过程 的追踪。

若要了解更多信息,请拨打man ptrace

+0

'ptrace'在linux中可用。在基于unix的操作系统中可以使用哪些系统调用? – cppcoder 2014-09-25 15:43:44

+0

'ptrace'并不是Linux所特有的,它在大多数(如果不是全部的话)Unix发行版中都很常见。它的实现就像在Windows中一样,遵循相同的概念。 – 2014-09-25 19:34:10

0

当每一道工序都有没有外部进程可以访问自己的私有内存空间......

那是假的。具有正确权限的外部进程和使用正确的API 可以访问其他进程的内存。

1

对于Linux调试,系统调用ptrace可以控制系统上的另一个进程。事实上,如果您是流程的所有者并且您尚未手动删除权限,则需要有权执行此操作,通常会给出相应权限。

os调用ptrace本身允许访问内存,程序计数器,寄存器和几乎所有其他相关的内容来读写。

详情请参阅man ptrace

如果您有兴趣在调试器中如何使用它,请查看 gdb-x.x.x/gdb/linux-nat.c中的文件。在那里你可以找到访问其他进程进行调试的核心内容。