您的位置:首页 > 运维架构 > Linux

[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】

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: