如何用ptrace拦截系统调用并替换为自定义代码

如何用ptrace拦截系统调用并替换为自定义代码

tracer能够改变系统调用参数,改变系统调用的返回值,甚至屏蔽特定的系统调用,将特定系统调用替换为自定义的helloworld函数。
ptrace系统调用的拦截替换原理为:利用ptrace函数使父进程跟踪子进程,当子进程在执行系统调用时,断住子进程,获取并保存当前系统调用的寄存器信息。然后备份ip寄存器指向的指令块A,替换为我们要执行的code指令块B,B执行后ip地址值恢复为指令块A及寄存器内容。
下面用例子实现上面的系统调用拦截替换功能。首先我们的目标是将一个打开文件的系统调用拦截,并替换为打印输出“helloworld”的字符串。
1.先得到自定义代码的二进制码
汇编实现文件ptrace_helloworld_asm.c
在这里插入图片描述

运行指令

gcc ptrace_helloworld_asm.c -o ptrace_helloworld_asm.o
./ptrace_helloworld_asm.o

在这里插入图片描述

objdump -d ptrace_helloworld_asm.o

目标二进制代码为:
在这里插入图片描述

2.ptrace拦截系统调用并替换
在这里插入图片描述

其中的CODE变量如下:
在这里插入图片描述

这样的执行结果如下:
在这里插入图片描述
(按任意键后)
在这里插入图片描述
源码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/types.h>
#include <sys/user.h>
#include <stdlib.h>

#define CODE \
    "\xeb\x19\x5e\x48\xc7\xc0\x01\x00" \
    "\x00\x00\x48\xc7\xc7\x02\x00\x00" \
    "\x00\x48\xc7\xc2\x0c\x00\x00\x00" \
    "\x0f\x05\xcc\xe8\xe2\xff\xff\xff" \
    "\x48\x65\x6c\x6c\x6f\x20\x57\x6f" \
    "\x72\x6c\x64\x0a"

#define REG_IP  regs.rip
#define CODE_SIZE (sizeof(CODE)-1)

void putdata(pid_t pid, unsigned long addr, void *vptr, int len)
{
    int count = 0;
    long word;
 
    while (count < len)
    {
        memcpy(&word, vptr+count, sizeof(word));
        word = ptrace(PTRACE_POKEDATA, pid, addr+count, word);
        count += sizeof(word);
    }
}
 
/* 读pid进程addr地址处的数据 */
void getdata(pid_t pid, unsigned long addr, void *vptr, int len)
{
    int i = 0, count = 0;
    long word;
    unsigned long *ptr = (unsigned long*)vptr;
 
    while (count < len)
    {
        word = ptrace(PTRACE_PEEKDATA, pid, addr+count, NULL);
        count += sizeof(word);
        ptr[i++]  = word;
    }
}

int main()
{
    pid_t child;
    struct user_regs_struct regs;
    char backup[CODE_SIZE+1];

    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL); //系统调用了execve()
    }
    else {
        wait(NULL);
        // 获取被注入进程当前寄存器值
        ptrace(PTRACE_GETREGS, child, NULL, &regs);
        // 备份*ip寄存器指向的指令块
        getdata(child, REG_IP, backup, CODE_SIZE);
        // 替换为CODE指令块
        putdata(child, REG_IP, CODE, CODE_SIZE);
        // 恢复被注入进程的执行
        ptrace(PTRACE_CONT, child, NULL, NULL);
        printf("continue to execute the orginal process, press any key ..\n");
        getchar();
        putdata(child, REG_IP, backup, CODE_SIZE);
        // 恢复被注入进程寄存器值
        ptrace(PTRACE_SETREGS, child, NULL, &regs);
        // detach,被注入进程恢复正常执行
        ptrace(PTRACE_DETACH, child, NULL, NULL);
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值