[Ptrace]Linux内存替换(三)运行控制
2015-08-04 12:03
656 查看
在上一节中利用Ptrace实现了B程序对A程序进程信息的读取,下面一个实例将实现B进程对A进程的运行控制,即利用B进程暂停A进程固定时间后再恢复运行(以操作者手动输入任意字符后恢复执行的方式,A始终恢复失败,报段错误,具体原因请好心人指点)。
【环境】
CentOS 6.6 (Final)
Linux version 2.6.32-504.el6.i686
Gcc version 4.4.7 20120313
【A程序:counter.c】
gcc -o counter counter.c
【B程序:pause.c】
gcc -o pause pause.c
【执行】
1. run counter
./counter
2. find pid of counter
ps aux | grep counter
3. run pause(root)
./pause %pid%
【结果】
A进程部分输出如下,从时间间隔上可以明显区分出B程序控制A程序运行的时机。
My Counter: 0
1000217
My Counter: 1
6001265
My Counter: 2
1000604
My Counter: 3
1000585
My Counter: 4
6001558
My Counter: 5
1000564
…
【补充说明】
通过进一步思考,作者认为以上测试只能说明A程序被成功暂停和恢复(只利用ptrace的附加和脱离操作也可实现以上测试结果)。
基于以上测试,作者又做了两项尝试:一是只去除恢复原代码函数(putdata(traced_process, regs.eip, backup, 3)),测试结果发现A程序崩溃,提示Trace/breakpoint trap;二是将替换代码int80/int3 (char code[] = {0,0,0,0})全部修改成零,再去除恢复原代码函数,测试结果发现A程序崩溃,提示Segmentation Fault;
结合以上两项附加测试,作者认为可以充分证明代码注入成功。
【参考】
http://www.cnblogs.com/wangkangluo1/archive/2012/06/05/2535484.html
【环境】
CentOS 6.6 (Final)
Linux version 2.6.32-504.el6.i686
Gcc version 4.4.7 20120313
【A程序:counter.c】
#include <sys/time.h> #include <stdio.h> long long timeum(){ struct timeval tim; gettimeofday (&tim , NULL); return (long long)tim.tv_sec*1000000+tim.tv_usec; } int main() { int i; long long start,tmp; start = timeum(); for(i = 0; i < 60; ++i){ printf("My Counter: %d\n", i); sleep(1); tmp = timeum(); printf("Time Interval: %lld\n",tmp-start); start = tmp; } return 0; }
gcc -o counter counter.c
【B程序:pause.c】
#include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/user.h> #include <stdio.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] = ' '; } 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; long rst; i = 0; j = len / long_size; laddr = str; while(i < j){ memcpy(data.chars, laddr, long_size); rst = ptrace(PTRACE_POKEDATA, child, addr + i*4, data.val); if (rst < 0) printf("Putdata Failed! \n"); ++i; laddr += long_size; } j = len % long_size; if(j != 0){ memcpy(data.chars, laddr, j); rst = ptrace(PTRACE_POKEDATA, child, addr + i*4, data.val); if (rst < 0) printf("Putdata Failed! \n"); } } int main(int argc, char *argv[]) { pid_t traced_process; struct user_regs_struct regs, newregs; /* int 0x80, int3 */ char code[] = {0xcd,0x80,0xcc,0}; //char code[] = {0,0,0,0}; //TEST char backup[4]; if(argc != 2) { printf("PID?\n"); return 1; } traced_process = atoi(argv[1]); ptrace(PTRACE_ATTACH, traced_process, NULL, NULL); int pid = wait(NULL); printf("Attach Pid: %d\n",pid); ptrace(PTRACE_GETREGS, traced_process, NULL, ®s); /* Copy instructions into a backup variable */ getdata(traced_process, regs.eip, backup, 3); /* Put the breakpoint */ putdata(traced_process, regs.eip, code, 3); /* Let the process continue and execute the int 3 instruction */ ptrace(PTRACE_CONT, traced_process, NULL, NULL); wait(NULL); sleep(5); /*Segmentation fault (core dumped) printf("The process stopped, putting back " "the original instructions "); printf("Press <enter> to continue "); getchar();*/ putdata(traced_process, regs.eip, backup, 3); //putdata(traced_process, regs.eip, backup, 3); //TEST /* Setting the eip back to the original instruction to let the process continue */ ptrace(PTRACE_SETREGS, traced_process, NULL, ®s); ptrace(PTRACE_DETACH, traced_process, NULL, NULL); return 0; }
gcc -o pause pause.c
【执行】
1. run counter
./counter
2. find pid of counter
ps aux | grep counter
3. run pause(root)
./pause %pid%
【结果】
A进程部分输出如下,从时间间隔上可以明显区分出B程序控制A程序运行的时机。
My Counter: 0
1000217
My Counter: 1
6001265
My Counter: 2
1000604
My Counter: 3
1000585
My Counter: 4
6001558
My Counter: 5
1000564
…
【补充说明】
通过进一步思考,作者认为以上测试只能说明A程序被成功暂停和恢复(只利用ptrace的附加和脱离操作也可实现以上测试结果)。
基于以上测试,作者又做了两项尝试:一是只去除恢复原代码函数(putdata(traced_process, regs.eip, backup, 3)),测试结果发现A程序崩溃,提示Trace/breakpoint trap;二是将替换代码int80/int3 (char code[] = {0,0,0,0})全部修改成零,再去除恢复原代码函数,测试结果发现A程序崩溃,提示Segmentation Fault;
结合以上两项附加测试,作者认为可以充分证明代码注入成功。
【参考】
http://www.cnblogs.com/wangkangluo1/archive/2012/06/05/2535484.html
相关文章推荐
- 每天一个linux命令
- Linux查找方法
- CentOS6.4上glusterfs安装配置
- Linux命令详解 -- tar
- linux kafka 搭建运行环境
- centos6.6_x64升级firefox
- Linux下的top命令
- Linux操作系统-标准IO库(1)
- linux 内存中buffer 和cache 的区别
- 通过 Linux文件描述符/Windows句柄 来看 C语言里的"FILE"
- 用socket实现Linux和Windows之间的通信
- Centos 下 mysql root 密码重置
- Linux基础学习-01
- 64位 CentOS NDK 编译 FFMPEG
- linux rm 删除指令新用
- centOS 安装mysql5.5版本
- [linux]解决DNS配置重启丢失
- CentOS 有gcc没有g++
- Linux命令详解 -- cat tac more less head tail
- linux 下编译安装Qt