使用ptrace将标准输出重定位到文件-编程思维

首先使用PTRACE_SYSCALL获取到系统调用号,如果是write则将文件描述符从标准输出变为我们打开的文件

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

using namespace std;
#if __WORDSIZE == 64
#define REG(reg) reg.orig_rax
#else
#define REG(reg) reg.orig_eax
#endif
const int long_size = sizeof(int);

//获取addr处也就是buf参数
void getdata(pid_t child, long addr,
             char *str, int len)
{   char *laddr;
    int i, j;
    union u {
            int 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] = '\0';
}
int main(int argc, char *argv[]){
    int fp;
    fp = open("./a.txt",O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH);
    pid_t child;
    int status;
    int64_t sys_num = -1;
    
    child = fork();
    if(child == 0){
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);				//子进程标记为trace,并执行ls
    }else{
        while(1){
	    struct user_regs_struct regs; 
        wait(&status);
        if(WIFEXITED(status))
            break;
        ptrace(PTRACE_SYSCALL, child, NULL, NULL);		//在系统调用处发送信号到父进程
        waitpid(child, &status, 0);
        ptrace(PTRACE_GETREGS, child, NULL, &regs);		//获取寄存器参数
	    sys_num=REG(regs);
	    if(sys_num==1){										//write调用的系统调用号
			printf("syscall write\n");
			printf("change I/O from %llu to file\n",regs.rdi);
			size_t size = regs.rdx;
            char * buffer = new char[size];					//存储write的数据
			getdata(child, regs.rsi, buffer, size);
			printf("%s\n",buffer);
			regs.rdi = fp;
			ptrace(PTRACE_SETREGS, child, 0, &regs);		//将write的输出从标准输出改为fp
	    }
	    ptrace(PTRACE_SYSCALL, child, NULL, NULL);			//继续trace
	    
        }
    }
    close(fp);
    return 0;
}

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://www.cnblogs.com/awesome-red/p/15499871.html