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_POKEDATA和PTRACE_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.