Ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image。它主要用于实现断点调试。一个被跟踪的进程运行中,直到发生一个信号。则进程被中止,并且通知其父进程。在进程中止的状态下,进程的内存空间可以被读写。父进程还可以使子进程继续执行,并选择是否是否忽略引起中止的信号
long ptrace(
enum __ptrace_request request,//参数request:请求ptrace执行的操作
pid_t pid,///参数pid:目标进程的ID
void *addr,参数addr:目标进程的地址值
void *data);//参数data:作用则根据request的不同而变化,如果需要向目标进程中写入数据,data存放的是需要写入的数据;如果从目标进程中读数据,data将存放返回的数据
下面的的代码是i386cpu实现的不是arm
1 int main(int argc, char *argv[])
2 { pid_t traced_process;
3 struct user_regs_struct regs, newregs;
4 long ins;
5 int len = 41;
6 char insertcode[] =
7 "\xeb\x15\x5e\xb8\x04\x00"
8 "\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
9 "\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
10 "\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
11 "\x72\x6c\x64\x0a\x00";
12 char backup[len];
13 if(argc != 2) {
14 printf("Usage: %s \n" ,
15 argv[0], argv[1]);
16 exit(1);
17 }
18 traced_process = atoi(argv[1]);
19 ptrace(PTRACE_ATTACH, traced_process,
20 NULL, NULL);
21 wait(NULL);
22 ptrace(PTRACE_GETREGS, traced_process,
23 NULL, ®s);
24 getdata(traced_process, regs.eip, backup, len);
25 putdata(traced_process, regs.eip,
26 insertcode, len);
27 ptrace(PTRACE_SETREGS, traced_process,
28 NULL, ®s);
29 ptrace(PTRACE_CONT, traced_process,
30 NULL, NULL);
31 wait(NULL);
32 printf("The process stopped, Putting back "
33 "the original instructions\n");
34 putdata(traced_process, regs.eip, backup, len);
35 ptrace(PTRACE_SETREGS, traced_process,
36 NULL, ®s);
37 printf("Letting it continue with "
38 "original flow\n");
39 ptrace(PTRACE_DETACH, traced_process,
40 NULL, NULL);
41 return 0;
42 }
等待子进程退出。NULL的意思是退出状态不关注。如果要获取退出状态应该写成wait(&status);
将代码注入空闲内存中
在前面的示例中,我们将代码直接注入执行指令流。但是,调试器可能会与这种行为混淆,所以让我们找到进程中的空闲内存并将代码注入其中。
/proc/pid/maps
我们可以通过检查跟踪进程的**/proc/pid/maps文件来找到空闲内存**。下面的函数会找到这个的起始地址: