关于ptrace
ptrace可以用来监控和控制一个进程的运行,获取或更改目标进程的内存和寄存器,它主要用来进行断点调试或跟踪,
参数
ptrace函数体1
2
3#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
- enum __ptrace_request request:指示了ptrace要执行的命令。
- pid_t pid: 指示ptrace要跟踪的进程。
- void *addr: 指示要监控的内存地址。
- void *data: 存放读取出的或者要写入的数据。
ptrace的第一个参数决定了其行为,常用到的有如下几种:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16PTRACE_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。
stat
/proc/pid/stat 和 /proc/pid/task/pid/stat:调试状态下,括号后面的第一个字母应该为t
wchan
/proc/pid/wchan 和 /proc/pid/task/pid/wchan:调试状态下,里面内容为ptrace_stop
实例
假设目标进程如下: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
32int 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;
}
参考资料: