ptrace
是一种系统调用,也就是进程追踪(process trace);用于对进程的执行进行干涉以及寄存器状态(值)的读取以及设置,内存的写入与读取;我们常用的Linux下的gdb主要功能实现就是通过ptrace系统调用的:
#include
long ptrace(enum __ptrace_request request, pid_t pid,void *addr, void *data);
通过request
参数的不同来实现不同的功能;
PTRACE_ATTACH
:建立不同进程间的跟踪关系,附加成功后,目标进程将处于挂起状态;被跟踪进程,将会发送SIGSTOP
信号给跟踪者;跟踪着需要调用wait()
函数接收被跟踪进程传来的SIGSTOP
信号,使用此参数时pid,addr,data参数都会被忽略:ptrace(PTRACE_ATTACH, pid,NULL,NULL);
PTRACE_TRACEME
:指示其父进程,对其进行跟踪;使用此参数时pid,addr,data参数都会被忽略:if (ptrace(PTRACE_TRACEME, pid, NULL, NULL) < 0) {
perror("PTRACE_TRACEME");
exit(0);
}
PTRACE_PEEKTEXT
或PTRACE_PEEKDATA
:从addr参数指示的地址开始读
取一个WORD
的长度的数据并通过返回值
传递回来;使用此参数时data参数会被忽略:data = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
if (errno != 0) {
perror("PTRACE_PEEKTEXT");
exit(0);
}
PTRACE_POKETEXT
或PTRACE_POKEDATA
:从addr参数指示的地址开始写
入一个WORD
长度的数据:if (ptrace(PTRACE_POKETEXT, pid, addr, data) < 0) {
perror("PTRACE_POKETEXT");
exit(0);
}
PTRACE_GETREGS
:从被跟踪的进程中读取
用户寄存器的值到一个struct user_regs_struct
结构体中,使用此参数时addr和data参数会被忽略:#include
struct user_regs_struct reg;
if (ptrace(PTRACE_GETREGS, pid, NULL, ®) < 0) {
perror("PTRACE_GETREGS");
exit(0);
}
printf("RIP: %p\n",reg.rip);
PTRACE_SETREGS
:将一个struct user_regs_struct
类型的结构体中变量的值设置到被跟踪进程的用户寄存器中去;与上一个PTRACE_GETREGS
请求配合使用,使用此参数时addr和data参数会被忽略:if (ptrace(PTRACE_SETREGS, pid, NULL, ®) < 0) {
perror("PTRACE_SETREGS");
exit(0);
}
PTRACE_CONT
:恢复pid指定的进程执行;当data参数不为零时,data将会被解释为一个signal
,传递给被跟踪进程,使用此参数时addr参数被忽略:if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
perror("PTRACE_CONT");
exit(0);
}
PTRACE_DETACH
或PTRACE_KILL
:将会把SIGKILL
发送给被跟踪进程,脱离进程间的跟踪关系,使用此参数时addr和data参数会被忽略:if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
perror("PTRACE_KILL");
exit(0);
}
思路:
0xcc
(int 3);re.c:
#include
#include
#include
void show()
{
printf("Hello, ptrace! [pid:%d]\n", getpid());
}
int main() {
while(1){
show();
sleep(2);
}
return 0;
}
编译:
gcc re.c -o re
hook.c
#include
#include
#include
#include
#include
#include
#include
#include
#include /* For constants ORIG_EAX etc */
#include
void new_show()
{
printf("Hooked by cc-sir!\n");
}
int main(int argc, char *argv[])
{
if(argc!=2) {
printf("Usage: %s pid\n", argv[0]);
return 0;
}
printf("new_show_addr: %p\n",new_show);
struct user_regs_struct reg;
pid_t pid = atoi(argv[1]);
ptrace(PTRACE_ATTACH, pid,NULL,NULL);
wait(NULL);
ptrace(PTRACE_GETREGS,pid,NULL,®);
printf("rip: 0x%lx\n",reg.rip);
long addr = reg.rip;
long show_addr = 0x400586;
long code = 0xcc80cd;
long back_code;
int id;
back_code = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL); //保留源码
printf("back_code: %llx\n",back_code);
if(ptrace(PTRACE_POKETEXT, pid, addr, code) < 0){ //修改源码
perror("PTRACE_POKETEXT");
return 0;
}
ptrace(PTRACE_CONT, pid, NULL, NULL);
wait(NULL);
printf("The process has int 0x3!\n");
getchar();
if(ptrace(PTRACE_POKETEXT, pid, addr, back_code) < 0){ //还原代码
perror("PTRACE_POKETEXT");
return 0;
}
ptrace(PTRACE_SETREGS, pid, NULL, ®); //还原寄存器
ptrace(PTRACE_CONT, pid, NULL, NULL);
printf("The process has continue run!\n");
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return 0;
}
编译:
gcc hook.c -o hook