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

简介

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

#include <sys/ptrace.h>
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<sys/user.h>
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 <stdio.h>
#include <time.h>
#include <unistd.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> 
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/reg.h>   /* For constants ORIG_EAX etc */
#include <sys/user.h>

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

结果:
效果

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值