您的位置:首页 > 编程语言

重定向已经运行进程的标准输出到文件的办法(通过ptrace注入代码到其他进程并运行)

2013-05-23 16:51 716 查看


重定向已经运行进程的标准输出到文件的办法(通过ptrace注入代码到其他进程并运行)

上次看到CSDN里面有人问这个问题,我觉得用ptrace这个系统调用是可以实现的。前两天在IBM developworks看到中兴工程师写的一篇文章是用ptrace来挂钩系统调用然后获取已运行进程的网络包的,他文章里面把程序之间通讯用的网络包分离出来然后在wireshrark中分析。通过这篇文档,证实我之前的想法应该也是可行的。最近工作偷懒,就试试这个吧。

1、重定向标准输出,用dup2系统调用,dup2(file,1)把一个打开的文件描述符的复制到标准输出1去应该就可以了吧。参考“Understanding+The+Linux+Kernel+3rd.pdf” 一书关于管道使用那一章举的ls| more 例子。

2、ptrace这个系统调用功能很强大,可以用来调试进程,挂钩系统调用函数,等待。Windows上面的read/writeprocessmemory以及hook api技术都可以通过这个来实现。调试器也都可以使用这个来做了,不知道GDB是不是也是用ptrace来实现的?

我们用重定向标准输出,就用ptrace注入一段调试代码到目标进程,然后在里面调用dup2等几个函数就可以了。

3、ptrace也有一个缺陷,就是如果要attach的进程如果本来就有父进程的话,那么被我们用ptrace处理之后,他原本的父进程是没有办法再受到来自被attach进程的消息了。好像也没有办法恢复。自己看一下ptrace的文档吧,不知道我理解错了没有。反正如果目标进程有父进程的话,用这个办法难免有些影响,实际运用的时候要考虑一下。

4、代码大多从“Playing with ptrace, Part II http://www.linuxjournal.com/node/6210/print”这篇文章里面复制过来,可以去看看原文关于ptrace的用法说名吧。只是我把他本来打印“hello world”的汇编代码改为调用两个系统调用的了。

调用Linux系统调用通过int $80的80号中断来进行,调用时,其中eax存放系统中断号码,ebx ,ecx等等依次为传给系统调用的参数。系统调用返回时eax为返回值。可以参考一下“Professional+Assembly+Language.pdf” 一书关于在汇编中使用文件系统调用来操作文件的例子。

其实,好像说新的cpu可以通过sysenter指令来进入系统调用的,那个性能要比int 80要好些。大家可以试试吧。我对汇编不是很熟悉就不试了。我在virtuabox + ubuntu 10.04上面测试int $80还是可以正常工作的,可能现在系统对两种办法都还支持吧。

代码如下:

----------test.c---------------------------------------------

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/ptrace.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <asm/ptrace.h>

#include <string.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] = '\0';

}

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);

}

}

int main(int argc, char *argv[])

{

// int log;

// log = open("/tmp/widebright.txt",O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH );

//printf ("result =%d\n",log);

//exit(0);

// if (log != -1){

// int result =dup2(log,1); //重定向标准输出

//if (result == -1)

// printf ("dup2 return failed\n");

//printf ("result =%d\n", write (log, "failed\n", 5));

// }

//printf("ddddd,hahahha\n");



// close (log);

/*

__asm__ (

"jmp forward\n\t"

"backward:\n\t"

"popl %esi #get path string address \n\t"

"movl $5, %eax #sys_open number arch/x86/kernel/syscall_table_32.S\n\t"

"movl %esi, %ebx\n\t"

"movl $0x242, %ecx\n\t"

"movl $0x1b6, %edx #all has read and write permissions\n\t"

"int $0x80\n\t"

"test %eax,%eax\n\t"

"js end\n\t"

"mov %eax , %ebx # parm 1\n\t"

"movl $63, %eax #sys_dup2 number arch/x86/kernel/syscall_table_32.S\n\t"

"movl $1, %ecx # parm 2\n\t "

"int $0x80\n\t"

"#jmp end\n\t"

"end:\n\t"

"int3\n\t"

"forward:\n\t"

"call backward\n\t"

".string \"/tmp/widebright.txt\"\n\t"

"#end:\n\t"

);

(gdb) x/66xb backward-2

0x8048c10 <main+53>: 0xeb 0x27 0x5e 0xb8 0x05 0x00 0x00 0x00

0x8048c18 <main+61>: 0x89 0xf3 0xb9 0x42 0x02 0x00 0x00 0xba

0x8048c20 <main+69>: 0xb6 0x01 0x00 0x00 0xcd 0x80 0x85 0xc0

0x8048c28 <main+77>: 0x78 0x0e 0x89 0xc3 0xb8 0x3f 0x00 0x00

0x8048c30 <main+85>: 0x00 0xb9 0x01 0x00 0x00 0x00 0xcd 0x80

0x8048c38 <end>: 0xcc 0xe8 0xd4 0xff 0xff 0xff 0x2f 0x74

0x8048c40 <forward+7>: 0x6d 0x70 0x2f 0x77 0x69 0x64 0x65 0x62

0x8048c48 <forward+15>: 0x72 0x69 0x67 0x68 0x74 0x2e 0x74 0x78

0x8048c50 <forward+23>: 0x74 0x00

*/

//printf("ddddd,hahahha\n");

// return 0;

pid_t traced_process;

struct pt_regs regs, newregs;

long ins;

const int len = 66;

char insertcode[] =

{0xeb, 0x27, 0x5e, 0xb8, 0x05, 0x00, 0x00, 0x00,

0x89, 0xf3, 0xb9, 0x42, 0x02, 0x00, 0x00, 0xba,

0xb6, 0x01, 0x00, 0x00, 0xcd, 0x80, 0x85, 0xc0,

0x78, 0x0e, 0x89, 0xc3, 0xb8, 0x3f, 0x00, 0x00,

0x00, 0xb9, 0x01, 0x00, 0x00, 0x00, 0xcd, 0x80,

0xcc, 0xe8, 0xd4, 0xff, 0xff, 0xff, 0x2f, 0x74,

0x6d, 0x70, 0x2f, 0x77, 0x69, 0x64, 0x65, 0x62,

0x72, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x74, 0x78,

0x74, 0x00};

char backup[len];

if(argc != 2) {

printf("Usage: %s <pid to be traced>\n",

argv[0], argv[1]);

exit(1);

}

traced_process = atoi(argv[1]);

ptrace(PTRACE_ATTACH, traced_process,

NULL, NULL);

wait(NULL); //等待attach成功。目标进程被断下

ptrace(PTRACE_GETREGS, traced_process,

NULL, ®s); //获取目标进程当前的寄存器状态

getdata(traced_process, regs.eip, backup, len);

putdata(traced_process, regs.eip,

insertcode, len); //注入我们的指令到当前运行的位置。

ptrace(PTRACE_SETREGS, traced_process,

NULL, ®s);

ptrace(PTRACE_CONT, traced_process,

NULL, NULL); //继续运行

wait(NULL); //等待我们汇编代码里面的int3 调试断点。

printf("The process stopped, Putting back "

"the original instructions\n");

ptrace(PTRACE_GETREGS, traced_process,

NULL, &newregs);

// printf("\n%ld-%ld\n",regs.eip,newregs.eip);

// sleep(10);

putdata(traced_process, regs.eip, backup, len); //还原原本的代码

ptrace(PTRACE_SETREGS, traced_process,

NULL, ®s);

printf("Letting it continue with "

"original flow\n");

ptrace(PTRACE_DETACH, traced_process,

NULL, NULL);

return 0;

}

-------------写一个简单的测试例子 test2.c--------------------

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main(void)

{

int i = 0;

while (i < 20000000)

{

printf("current number is %d\n",i);

i++;

sleep(5);

}

}

------------------------------------------

测试一下。

gcc test2.c -o test.exe

桌面$ ./test.exe

current number is 0

current number is 1

current number is 2

current number is 3

current number is 4

current number is 5

current number is 6

current number is 7

current number is 8

current number is 9

current number is 10

current number is 11

current number is 12

current number is 13

current number is 14

^C

-----------

桌面$ ps -ef |grep test.exe

1000 4609 3554 0 10:51 pts/0 00:00:00 ./test.exe

1000 4667 4295 0 10:52 pts/1 00:00:00 grep --color=auto test.exe

桌面$ ./a.out 4609

The process stopped, Putting back the original instructions

Letting it continue with original flow

桌面$ cat /tmp/widebright.txt

current number is 15

桌面$ cat /tmp/widebright.txt

current number is 15

current number is 16

桌面$ cat /tmp/widebright.txt

current number is 15

current number is 16

可以看到test。exe的标准输出确实被我们重定向到这个/tmp/widebright.txt文件里面去了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐