#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()成功返回0,失败返回-1同时errno被设置
errno
EPERM:权限错误,进程无法被跟踪
ESRCH:目标进程不存在或者已经被跟踪
EIO:参数request的值无效,或者从非法的内存读/写数据
EFAULT:需要读/写数据的内存未被映射
attach调试一个正在运行的进程
(gdb) attach pid
gdb将执行ptrace(PTRACE_ATTACH, pid, 0, 0)
系统调用,建立与目标程序的跟踪关系
运行并调试一个新进程
(gdb) run
gdb通过fork()
系统调用创建一个子进程,然后在子进程中执行ptrace(PTRACE_TRACEME, pid, 0, 0)
系统调用,子进程与父进程(debugger)建立跟踪关系,然后子进程执行execve()系统调用运行目标程序
远程调试目标主机的进程
gdb运行在调试机,gdbserver运行在目标机,通过二者之间定义的数据格式进行通信
一个进程在同一时间只能被一个进程跟踪
如图,pid152的1被pid153的gdb追踪,此时在pid160的gdb中无法attach 152
如果一个程序自己追踪自己,gdb就无法attach
例
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
int main(int argc, char const *argv[])
{
ptrace(PTRACE_TRACEME, 0, 0, 0);
getchar();
}
//gcc test.c -o test
运行到getchar();后,gdb attach
process 191 is already traced by process 118
提示已被追踪
上面的例子是attach调试一个正在运行的进程,如果运行并调试一个新进程,如何反调试
例
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
int main(int argc, char const *argv[])
{
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
{
puts("goodbye world");
exit(-1);
}
else
{
puts("hello world");
}
return 0;
}
//gcc test.c -o test
一个进程在同一时间只能被一个进程跟踪,gdb run后程序执行ptrace(PTRACE_TRACEME, 0, 0, 0)
必然失败,返回-1
在ptrace下断,单步执行
可以看到rax是0xffffffffffffffff
可以在ptrace下断,然后改返回值
也可以自己写个库,链接上去,干掉ptrace
继续用上面的例子
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
int main(int argc, char const *argv[])
{
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
{
puts("goodbye world");
exit(-1);
}
else
{
puts("hello world");
}
return 0;
}
//gcc test.c -o test
pwndbg> set $rax=0
可以看到rax被改为0
继续执行
//ptrace_disable.c
int ptrace(int request, int pid, int addr, int data){
return 0;
}
//gcc -shared -fPIC -o ptrace_disable.so ptrace_disable.c
进gdb
set environment LD_PRELOAD=./ptrace_disable.so
在ptrace下断,看一眼
他原来应该长这样
pwndbg> x/64gi 0x7fffff1178e0
=> 0x7fffff1178e0 <ptrace>: sub rsp,0x68
0x7fffff1178e4 <ptrace+4>: lea r8d,[rdi-0x1]
0x7fffff1178e8 <ptrace+8>: mov rax,QWORD PTR fs:0x28
0x7fffff1178f1 <ptrace+17>: mov QWORD PTR [rsp+0x28],rax
0x7fffff1178f6 <ptrace+22>: xor eax,eax
0x7fffff1178f8 <ptrace+24>: lea rax,[rsp+0x70]
0x7fffff1178fd <ptrace+29>: mov QWORD PTR [rsp+0x38],rsi
0x7fffff117902 <ptrace+34>: mov QWORD PTR [rsp+0x40],rdx
0x7fffff117907 <ptrace+39>: mov QWORD PTR [rsp+0x48],rcx
0x7fffff11790c <ptrace+44>: lea r10,[rsp+0x8]
0x7fffff117911 <ptrace+49>: cmp r8d,0x3
0x7fffff117915 <ptrace+53>: mov QWORD PTR [rsp+0x18],rax
0x7fffff11791a <ptrace+58>: lea rax,[rsp+0x30]
0x7fffff11791f <ptrace+63>: mov DWORD PTR [rsp+0x10],0x18
0x7fffff117927 <ptrace+71>: mov esi,DWORD PTR [rax+0x8]
0x7fffff11792a <ptrace+74>: mov rdx,QWORD PTR [rax+0x10]
0x7fffff11792e <ptrace+78>: mov QWORD PTR [rsp+0x20],rax
0x7fffff117933 <ptrace+83>: cmovae r10,QWORD PTR [rax+0x18]
0x7fffff117938 <ptrace+88>: mov eax,0x65
0x7fffff11793d <ptrace+93>: syscall
0x7fffff11793f <ptrace+95>: cmp rax,0xfffffffffffff000
0x7fffff117945 <ptrace+101>: ja 0x7fffff117988 <ptrace+168>
0x7fffff117947 <ptrace+103>: test rax,rax
0x7fffff11794a <ptrace+106>: js 0x7fffff117952 <ptrace+114>
0x7fffff11794c <ptrace+108>: cmp r8d,0x2
0x7fffff117950 <ptrace+112>: jbe 0x7fffff117970 <ptrace+144>
0x7fffff117952 <ptrace+114>: mov rcx,QWORD PTR [rsp+0x28]
0x7fffff117957 <ptrace+119>: xor rcx,QWORD PTR fs:0x28
0x7fffff117960 <ptrace+128>: jne 0x7fffff11799d <ptrace+189>
0x7fffff117962 <ptrace+130>: add rsp,0x68
0x7fffff117966 <ptrace+134>: ret
0x7fffff117967 <ptrace+135>: nop WORD PTR [rax+rax*1+0x0]
0x7fffff117970 <ptrace+144>: mov rax,QWORD PTR [rip+0x2d34f1] # 0x7fffff3eae68
0x7fffff117977 <ptrace+151>: mov DWORD PTR fs:[rax],0x0
0x7fffff11797e <ptrace+158>: mov rax,QWORD PTR [rsp+0x8]
0x7fffff117983 <ptrace+163>: jmp 0x7fffff117952 <ptrace+114>
0x7fffff117985 <ptrace+165>: nop DWORD PTR [rax]
0x7fffff117988 <ptrace+168>: mov rdx,QWORD PTR [rip+0x2d34d9] # 0x7fffff3eae68
0x7fffff11798f <ptrace+175>: neg eax
0x7fffff117991 <ptrace+177>: mov DWORD PTR fs:[rdx],eax
0x7fffff117994 <ptrace+180>: mov rax,0xffffffffffffffff
0x7fffff11799b <ptrace+187>: jmp 0x7fffff117952 <ptrace+114>
0x7fffff11799d <ptrace+189>: call 0x7fffff134c80 <__stack_chk_fail>
现在他是这样的
pwndbg> x/10gi 0x7fffff1f057e
=> 0x7fffff1f057e <ptrace+4>: mov DWORD PTR [rbp-0x4],edi
0x7fffff1f0581 <ptrace+7>: mov DWORD PTR [rbp-0x8],esi
0x7fffff1f0584 <ptrace+10>: mov DWORD PTR [rbp-0xc],edx
0x7fffff1f0587 <ptrace+13>: mov DWORD PTR [rbp-0x10],ecx
0x7fffff1f058a <ptrace+16>: mov eax,0x0
0x7fffff1f058f <ptrace+21>: pop rbp
0x7fffff1f0590 <ptrace+22>: ret
继续执行
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可。
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).