Linux Hook--ptrace的常用参数使用

简介

ptrace是一种系统调用,也就是进程追踪(process trace);用于对进程的执行进行干涉以及寄存器状态(值)的读取以及设置,内存的写入与读取;我们常用的Linux下的gdb主要功能实现就是通过ptrace系统调用的:

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

通过request参数的不同来实现不同的功能;

常用的Ptrace参数

  1. PTRACE_ATTACH:建立不同进程间的跟踪关系,附加成功后,目标进程将处于挂起状态;被跟踪进程,将会发送SIGSTOP信号给跟踪者;跟踪着需要调用wait()函数接收被跟踪进程传来的SIGSTOP信号,使用此参数时pid,addr,data参数都会被忽略:
ptrace(PTRACE_ATTACH, pid,NULL,NULL);
  1. PTRACE_TRACEME:指示其父进程,对其进行跟踪;使用此参数时pid,addr,data参数都会被忽略:
if (ptrace(PTRACE_TRACEME, pid, NULL, NULL) < 0) {
	perror("PTRACE_TRACEME");
	exit(0);
}
  1. PTRACE_PEEKTEXTPTRACE_PEEKDATA:从addr参数指示的地址开始取一个WORD的长度的数据并通过返回值传递回来;使用此参数时data参数会被忽略:
data = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
if (errno != 0) {
	perror("PTRACE_PEEKTEXT");
	exit(0);
}
  1. PTRACE_POKETEXTPTRACE_POKEDATA:从addr参数指示的地址开始入一个WORD长度的数据:
if (ptrace(PTRACE_POKETEXT, pid, addr, data) < 0) {
	perror("PTRACE_POKETEXT");
	exit(0);
}
  1. PTRACE_GETREGS:从被跟踪的进程中读取用户寄存器的值到一个struct user_regs_struct结构体中,使用此参数时addr和data参数会被忽略:
#include
struct user_regs_struct reg;
if (ptrace(PTRACE_GETREGS, pid, NULL, &reg) < 0) {
	perror("PTRACE_GETREGS");
	exit(0);
}
printf("RIP: %p\n",reg.rip);
  1. PTRACE_SETREGS:将一个struct user_regs_struct类型的结构体中变量的值设置到被跟踪进程的用户寄存器中去;与上一个PTRACE_GETREGS请求配合使用,使用此参数时addr和data参数会被忽略:
if (ptrace(PTRACE_SETREGS, pid, NULL, &reg) < 0) {
	perror("PTRACE_SETREGS");
	exit(0);
}
  1. PTRACE_CONT:恢复pid指定的进程执行;当data参数不为零时,data将会被解释为一个signal,传递给被跟踪进程,使用此参数时addr参数被忽略:
if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
	perror("PTRACE_CONT");
	exit(0);
}
  1. PTRACE_DETACHPTRACE_KILL:将会把SIGKILL发送给被跟踪进程,脱离进程间的跟踪关系,使用此参数时addr和data参数会被忽略:
if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
	perror("PTRACE_KILL");
	exit(0);
}

模拟gdb的break和continue操作

思路:

  1. 将需要下断点的地址的代码读出并保存;
  2. 将需要下断点的地址的代码修改为0xcc(int 3);
  3. 将需要下断点的地址的代码恢复.

被attach的程序

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

Ptarce程序

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,&reg);
    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, &reg); //还原寄存器
    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

结果:
Linux Hook--ptrace的常用参数使用_第1张图片

你可能感兴趣的:(LInux)