8 Nov 2019

ptrace反调试

ptrace反调试

ptrace

#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:需要读/写数据的内存未被映射

gdb调试方式

  • 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运行在目标机,通过二者之间定义的数据格式进行通信

ptrace反调试

一个进程在同一时间只能被一个进程跟踪

1

如图,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

2

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

3

在ptrace下断,单步执行

4

可以看到rax是0xffffffffffffffff

反ptrace反调试

可以在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

改返回值

5

pwndbg> set $rax=0

6

可以看到rax被改为0

继续执行

7

改链接库

//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>

现在他是这样的

8

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

继续执行

9


Tags:
0 comments



本作品采用知识共享署名-非商业性使用-禁止演绎 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).