ptrace

关于ptrace

ptrace可以用来监控和控制一个进程的运行,获取或更改目标进程的内存和寄存器,它主要用来进行断点调试或跟踪,

参数

ptrace函数体

1
2
3
#include <sys/ptrace.h>

long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

  1. enum __ptrace_request request:指示了ptrace要执行的命令。
  2. pid_t pid: 指示ptrace要跟踪的进程。
  3. void *addr: 指示要监控的内存地址。
  4. void *data: 存放读取出的或者要写入的数据。

ptrace的第一个参数决定了其行为,常用到的有如下几种:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PTRACE_ATTACH	attach进程
PTRACE_TRACEME 子进程让父进程跟踪自己
PTRACE_PEEKTEXT 从内存地址中读取一个word
PTRACE_PEEKDATA 同上
PTRACE_PEEKUSER 从USER区域中读取一个word
PTRACE_POKETEXT 往内存地址中写入一个word
PTRACE_POKEDATA 同上
PTRACE_POKEUSER 往USER区写入一个word
PTRACE_GETREGS 读取寄存器
PTRACE_GETFPREGS 同上
PTRACE_SETREGS 写入寄存器
PTRACE_SETFPREGS 同上
PTRACE_CONT 继续执行 可同时向子进程交付指定的信号
PTRACE_SYSCALL 继续执行 进入系统调用读取参数,退出系统调用时读取返回值
PTRACE_SINGLESTEP 继续执行 单步调试
PTRACE_DETACH deattach

ptrace检测

进程被ptrace后通常会有一些特征,这些特征也常常作为反调试的判断依据:

status

/proc/pid/status 和 /proc/pid/task/pid/status:普通状态下,TracerPid这项应该为0;调试状态下为调试进程的PID。
upload successful

stat

/proc/pid/stat 和 /proc/pid/task/pid/stat:调试状态下,括号后面的第一个字母应该为t

upload successful

wchan

/proc/pid/wchan 和 /proc/pid/task/pid/wchan:调试状态下,里面内容为ptrace_stop
upload successful

实例

假设目标进程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//target.c
#include <stdio.h>

int main(int argc,char* argv[])
{
while(1)
{
printf("Target is running:%d\n", count);
count++;
sleep(3);
}
return 0;
}

利用ptrace操作目标进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("please input pid...\n");
return 1;
}

pid_t traced_process;
int status;
traced_process = atoi(argv[1]);

if( ptrace(PTRACE_ATTACH, traced_process, NULL, NULL) != 0)
{
printf("Trace process failed:%d.\n", errno);
return 1;
}
while(1)
{
wait(&status);
if(WIFEXITED(status))
{
break;
}
tracePro(traced_process);
ptrace(PTRACE_SYSCALL, traced_process, NULL, NULL);
}

ptrace(PTRACE_DETACH, traced_process, NULL, NULL);

return 0;
}

参考资料:

  1. ptrace http://man7.org/linux/man-pages/man2/ptrace.2.html