概述
在这篇文章的第一部分,我们了解了ptrace是怎么用来追踪系统调用并且修改系统调用参数的,在这篇文章中,我们研究更高级的技术如加入断点以及在正在运行的程序中插入代码。debuggers利用这些方法来设置断点以及运行调试handlers.与第一部分一样,我们这里讨论的都是针对i386体系结构的。
Attaching to a Running Process
在第一部分,我们在调用ptrace(PTRACE_TRECEME,..)之后,把这个进程作为子进程执行。如果你只想要看到进程是如何做系统调用并且跟踪程序的,第一部分的认识已经足够了,如果一想要跟踪或者条是一个已经在执行的程序,那么ptrace(PTRACE_ATTACH,。。)应该是你要考虑的。
当我们做ptrace(PTRACE_ATTACH,。。)并且传递要跟踪的线程的pid,那就相当于这个进程自己调用ptrace(PTRACE_TRACEME,..)并且成为这个tracing 进程的子进程。这个被跟踪的进程被发送了一个SIGSTOP信号,这样我们就可以像往常一样检查并且修改进程了。在我们完成修改或者跟踪之后,我们可以使得被跟踪的进程继续执行通过调用ptrace(PTRACE_DETACH,..)
下面tracing程序的代码
int main()
{
int i;
for(i = 0;i < 10; ++i) {
printf("My counter: %dn", i);
sleep(2);
}
return 0;
}
把这个文件保存为dummy2.c 编译并且运行它:
gcc -o dummy2 dummy2.c
./dummy2 &
这时,我们可以通过下面的程序attach到dummy2,
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
/* For user_regs_struct
etc. */
int main(int argc, char *argv[])
{
pid_t traced_process;
struct user_regs_struct regs;
long ins;
if(argc != 2) {
printf("Usage: %s <pid to be traced>n",
argv[0], argv[1]);
exit(1);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process,
NULL, NULL);
wait(NULL);
ptrace(PTRACE_GETREGS, traced_process,
NULL, ®s);
ins = ptrace(PTRACE_PEEKTEXT, traced_process,
regs.eip, NULL);
printf("EIP: %lx Instruction executed: %lxn",
regs.eip, ins);
ptrace(PTRACE_DETACH, traced_process,
NULL, NULL);
return 0;
}
上面的程序简单的attach到一个进程上,等待它完成,并且检查它的eip(指令指针),然后detach
如果要插入代码,可以再被跟踪进程停下来之后使用ptrace(PTRACE_POKETEXT,..)与ptrace(PTRACE_POKEDATA,..)
设置断点
调试器是怎么设置断点的?一般来说,他们把要执行的指令换成一个trap指令,这样被跟踪的程序就会停止,而跟踪程序,也就是debugger, 可以控制被跟踪的程序,一旦调试器继续被跟踪进程的执行,它原有的指令就会被替换。
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
const int long_size = sizeof(long);
void getdata(pid_t child, long addr,
char *str, int len)
{
char *laddr;
int i, j;
union u {
long val;
char chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while(i < j) {
data.val = ptrace(PTRACE_PEEKDATA, child,
addr + i * 4, NULL);
memcpy(laddr, data.chars, long_size);
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0) {
data.val = ptrace(PTRACE_PEEKDATA, child,
addr + i * 4, NULL);
memcpy(laddr, data.chars, j);
}
str[len] = '