进程注入-ptrace实现代码注入

ptrace简介

ptrace是一个系统调用,使用过Linux系统多多少少会接触方便我们查看执行的程序的系统调用的strace命令或者编程时使用gdb进行程序调试。他们幕后原理工作其实就是ptrace完成的。
我们通过man ptrace命令可以查看ptrace的使用说明。
ptrace系统调从名字上看是用于进程跟踪的,它提供了父进程可以观察和控制其子进程执行的能力,并允许父进程检查和替换子进程的内核镜像(包括寄存器)的值。其基本原理是: 当使用了ptrace跟踪后,所有发送给被跟踪的子进程的信号(除了SIGKILL),都会被转发给父进程,而子进程则会被阻塞,这时子进程的状态就会被系统标注为TASK_TRACED。而父进程收到信号后,就可以对停止下来的子进程进行检查和修改,然后让子进程继续运行。

ptrace函数的定义

#include <sys/ptrace.h>
long ptrace(int request, int pid, int addr, int data);

函数描述:

request参数决定了系统调用的功能:
PTRACE_TRACEME:0
本进程被其父进程所跟踪。其父进程应该希望跟踪子进程。
PTRACE_PEEKTEXT, PTRACE_PEEKDATA:1
从内存地址中读取一个字节,内存地址由addr给出。
PTRACE_PEEKUSR:3
从USER区域中读取一个字节,偏移量为addr。
PTRACE_POKETEXT:4, PTRACE_POKEDATA:5
往内存地址中写入一个字节。内存地址由addr给出。
PTRACE_POKEUSER:6
往USER区域中写入一个字节。偏移量为addr。
PTRACE_SYSCALL:24, PTRACE_CONT:7
重新运行。
PTRACE_KILL:8
杀掉子进程,使它退出。
PTRACE_SINGLESTEP:9
设置单步执行标志
PTRACE_ATTACH:16
跟踪指定pid 进程。
PTRACE_DETACH:17
结束跟踪

Intel386特有:

PTRACE_GETREGS
读取寄存器
PTRACE_SETREGS
设置寄存器
PTRACE_GETFPREGS
读取浮点寄存器
PTRACE_SETFPREGS
设置浮点寄存器
返回值
成功返回0,出错返回-1;

注意:init这类初始化文件不可以使用patrace

初次尝试

//gcc flag.c
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <unistd.h>


int main()
{   pid_t child;
    long orig_eax;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else {
        wait(NULL);
        orig_rax = ptrace(PTRACE_PEEKUSER,
                          child, 8 * ORIG_RAX,
                          NULL);
        printf("The child made a "
               "system call %ld\n", orig_rax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }
    return 0;
}

image.png
image.png
程序首先fork一个子进程,然后暂停子进程等待追踪,然后会返回0给父进程,就会进入else,wait等待内核通知,收到通知后,父进程就接管了子进程,然后PTRACE_PEEKUSR读取rax寄存器的内容存在orig_rax,打印rax,然后重启子进程执行ls。

注入测试

测试文件

#include<unistd.h>
#include<stdio.h>

int main()
{ 
   int i;
   printf("pid=%d\n",getpid());
    for(i = 0;i < 10; ++i) {
        printf("My counter: %d \n", i);
        sleep(2);
    }
    return 0;
}

注入文件

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <asm/ptrace-abi.h>
#include <string.h>
#include <stdio.h>

const int long_size = sizeof(long);

void getdata(pid_t child, long addr, 
             char *str, int len)
{   
    char *laddr;
    int i, j;
    union u{
            long val;
            char chars[long_size];
    }data;

    i = 0;
    j = len / long_size;
    laddr = str;

    while(i < j) {
        data.val = ptrace(PTRACE_PEEKDATA, child, 
                          addr + i * 4, NULL);
        memcpy(laddr, data.chars, long_size);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) {
        data.val = ptrace(PTRACE_PEEKDATA, child, 
                          addr + i * 4, NULL);
        memcpy(laddr, data.chars, j);
    }
    str[len] = ' ';
}

void putdata(pid_t child, long addr, 
             char *str, int len)
{   
    char *laddr;
    int i, j;
    union u {
            long val;
            char chars[long_size];
    }data;

    i = 0;
    j = len / long_size;
    laddr = str;
    while(i < j) {
        memcpy(data.chars, laddr, long_size);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) {
        memcpy(data.chars, laddr, j);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
    }
}
long freespaceaddr(pid_t pid)
{
    FILE *fp;
    char filename[30];
    char line[85];
    long addr;
    char str[20];
    sprintf(filename, "/proc/%d/maps", pid);
    fp = fopen(filename, "r");
    if(fp == NULL)
        exit(1);
    while(fgets(line, 85, fp) != NULL) {
        sscanf(line, "%lx-%*lx %*s %*s %s", &addr, 
               str, str, str, str);
        if(strcmp(str, "00:00") == 0)
            break;
    }
    fclose(fp);
    return addr;
}
int main(int argc, char *argv[])
{ 
pid_t traced_process;
    struct user_regs_struct regs, newregs;
    long ins;
    int len = 132;
    char insertcode[] =
        "\xeb\x15\x5e\xb8\x04\x00"
        "\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
        "\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
        "\x72\x6c\x64\x0a\x00";
    char backup[len];
    if(argc != 2) {
        printf("Usage: %s <pid to be traced> ", 
               argv[0], argv[1]);
        exit(1);
    }
    traced_process = atoi(argv[1]);
    ptrace(PTRACE_ATTACH, traced_process, 
           NULL, NULL);
    wait(NULL);
    ptrace(PTRACE_GETREGS, traced_process, 
           NULL, &regs);
    getdata(traced_process, regs.rip, backup, len);
    putdata(traced_process, regs.rip, 
            insertcode, len);
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &regs);
    ptrace(PTRACE_CONT, traced_process, 
           NULL, NULL);
    wait(NULL);
    printf("The process stopped, Putting back "
           "the original instructions ");
    putdata(traced_process, regs.rip, backup, len);
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &regs);
    printf("Letting it continue with "
           "original flow ");
    ptrace(PTRACE_DETACH, traced_process,
           NULL, NULL);
    return 0;
}
~/Desktop/IOT/GDB$ ./test
pid=31166
My counter: 0 
My counter: 1 
My counter: 2 
My counter: 3 
My counter: 4 
Hello World
My counter: 5 
My counter: 6 
My counter: 7 
My counter: 8 
My counter: 9
~/Desktop/IOT/GDB$ ./shell 3604
The process stopped, Putting back the original instructions Letting it continue with original flow
posted @ 2024-07-25 13:39  津门湖志津香  阅读(546)  评论(0)    收藏  举报