Linux中基于ptrace的外挂程序设计

所谓的外挂程序就是在某个进程执行的过程中,其他进程可以动态的修改进程中的数据或代码,从而影响程序的执行路径,并最终影响程序的运行结果。在windows上我们有系统库函数writeprocess()可以直接完成该项功能。而在linux上没有相同功能的函数可以使用,不过使用ptrace也可以完成类似的功能。

首先,Ptrace的使用形式如下:

#include <sys/ptrace.h>

int ptrace(int request, int pid, int addr, int data);

Ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image的方式。它主要用于实现断点调试。一个被跟踪的进程在运行中,发生一个信号的时候进程被中止,并且通知其父进程。在进程中止的状态下,进程的内存空间可以被读写。父进程还可以使子进程继续执行,并选择是否是否忽略引起中止的信号。

#include <sys/ptrace.h>  

#include <sys/types.h>  

#include <sys/wait.h>  

#include <unistd.h>  

#include <sys/syscall.h>  

#include <sys/reg.h>

  

const int int_size = sizeof(int);  

  

void putdata(pid_t child, int addr,   //向进程号为child的进程的addr这个地址空间写入str

             char *str, int len)  

{     

    char *laddr;  

    int i, j;  

    union u {  

            int val;  

            char chars[int_size];  

    }data;  

  

    i = 0;  

    j = len / int_size;  

    laddr = str;  

    while(i < j) {  

        memcpy(data.chars, laddr, int_size);  

        ptrace(PTRACE_POKEDATA, child,   //每次写入长度为int_size的数据

               addr + i * 4, data.val);  

        ++i;  

        laddr += int_size;  

    }  

    j = len % int_size;  

    if(j != 0) {  

        memcpy(data.chars, laddr, j);  

        ptrace(PTRACE_POKEDATA, child,   

               addr + i * 4, data.val);  

    }  

}  

  

int main()  

{     

   pid_t child;  

   child = fork();  

   if(child == 0) {  

      ptrace(PTRACE_TRACEME, 0, NULL, NULL);  //设置自进程由父进程监控

      execl("./test", "test", NULL);  //由父进程启动自进程

   }  

   else 

   {  

      int orig_eax;  

      int params[3];  

      int status;  

      char *str, *laddr;  

      int toggle = 0;  

      while(1) {  

         wait(&status);  //阻塞自己,等待子进程信号

         if(WIFEXITED(status))  // 子进程结束

             break;  

         orig_eax = ptrace(PTRACE_PEEKUSER,   //获取寄存器信息

                           child, 4 * ORIG_EAX,   

                           NULL);  

         if(orig_eax == SYS_write) {  //如果是写系统调用,修改细节具体参见系统write调用

         

               params[0] = ptrace(PTRACE_PEEKUSER,   

                                  child, 4 * EBX,   

                                  NULL);  

               params[1] = ptrace(PTRACE_PEEKUSER,   

                                  child, 4 * ECX,   

                                  NULL);  

               params[2] = ptrace(PTRACE_PEEKUSER,  

                                  child, 4 * EDX,   

                                  NULL);  

               char* writedata =  "The winner of 100 billion dollars is:gagaga\n";

               putdata(child, params[1],writedata,   

                       params[2]);  

         }  

       ptrace(PTRACE_SYSCALL, child, NULL, NULL);  //设置子进程系统调用或者终止时暂停

      }  

   }  

   return 0;  

}  

 

 

子进程代码:

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

 

int main()

{

srand((unsigned)(time(NULL)));

int i = 0;

for(i=0;i<120;i++)

{

int choose = rand()%4;

char* name="gagaga";

switch(choose)

{

case 0: name="hahaha";break;

case 1: name="papapa";break;

case 2: name="lalala";break;

}

printf("The winner of 100 billion dollars is:%s\n",name);

}

    return 0;

}

这样在子进程系统调用write的时候,父进程就可以修改write的参数值,并进一步影响了信息的输出。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。