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

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

2011-02-22 17:27 701 查看
上次看到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文件里面去了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 职场 休闲
相关文章推荐