[Ptrace]Linux内存替换(四)代码注入

在上一节中完成了B程序对A程序的执行控制实例,在此基础上,本节将int80/ int3替换成简单的shellcode,使代码注入过程更加直观。

【环境】
CentOS 6.6 (Final)
Linux version 2.6.32-504.el6.i686
Gcc version 4.4.7 20120313

【A程序:counter.c】

#include 
#include 

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

【C程序:asmhello.c】

void main()
{
    __asm__(
            "jmp forward\n\t"
            "backward:\n\t"
            "popl %esi\n\t"
            "movl $4, %eax\n\t"
            "movl $2, %ebx\n\t"
            "movl %esi, %ecx\n\t"
            "movl $12, %edx\n\t"
            "int $0x80\n\t"
            "int3\n\t"
            "forward:\n\t"
            "call backward\n\t"
            ".string \"Hello World\\n\"\n\t"
           );
}

gcc -o asmhello asmhello.c

在backward和forward之间的跳转是为了使程序能够找到”hello world” 字符串的地址。 获取二进制代码过程如下:
gdb asmhello

(gdb) disas main
Dump of assembler code for function main:
   0x08048394 <+0 >:    push   %ebp
   0x08048395 <+1 >:    mov    %esp,%ebp
   0x08048397 <+3 >:    jmp    0x80483ae 
   0x08048399 <+5 >:    pop    %esi
   0x0804839a <+6 >:    mov    $0x4,%eax
   0x0804839f <+11>:    mov    $0x2,%ebx
   0x080483a4 <+16>:    mov    %esi,%ecx
   0x080483a6 <+18>:    mov    $0xc,%edx
   0x080483ab <+23>:    int    $0x80
   0x080483ad <+25>:    int3   
   0x080483ae <+0 >:    call   0x8048399 5>
   0x080483b3 <+5 >:    dec    %eax
   0x080483b4 <+6 >:    gs
   0x080483b5 <+7 >:    insb   (%dx),%es:(%edi)
   0x080483b6 <+8 >:    insb   (%dx),%es:(%edi)
   0x080483b7 <+9 >:    outsl  %ds:(%esi),(%dx)
   0x080483b8 <+10>:    and    %dl,0x6f(%edi)
   0x080483bb <+13>:    jb     0x8048429 <__libc_csu_init+73>
   0x080483bd <+15>:    or     %fs:(%eax),%al
   0x080483c0 <+18>:    pop    %ebp
   0x080483c1 <+19>:    ret    
End of assembler dump.
(gdb) x /50bx main+3
0x8048397 <main+3>: 0xeb    0x15    0x5e    0xb8    0x04    0x00    0x00    0x00
0x804839f <main+11>:    0xbb    0x02    0x00    0x00    0x00    0x89    0xf1    0xba
0x80483a7 <main+19>:    0x0c    0x00    0x00    0x00    0xcd    0x80    0xcc    0xe8
0x80483af <forward+1>:  0xe6    0xff    0xff    0xff    0x48    0x65    0x6c    0x6c
0x80483b7 <forward+9>:  0x6f    0x20    0x57    0x6f    0x72    0x6c    0x64    0x0a
0x80483bf <forward+17>: 0x00    0x5d    0xc3    0x90    0x90    0x90    0x90    0x90
0x80483c7 <forward+25>: 0x90    0x90

shellcode实际位置为main+3到forward+17,共41个字节,所以最终shellcode如下:

    char code[] =
        "\xeb\x15\x5e\xb8\x04\x00\x00\x00"
        "\xbb\x02\x00\x00\x00\x89\xf1\xba"
        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8"
        "\xe6\xff\xff\xff\x48\x65\x6c\x6c"
        "\x6f\x20\x57\x6f\x72\x6c\x64\x0a\x00";

【B程序:injecthello.c】

#include 
#include 
#include 
#include 
#include 
#include 

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");
            return;
        }
        ++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");
            return;
        }
    }
}


int main(int argc, char *argv[])
{
    pid_t traced_process;
    struct user_regs_struct regs, newregs;
    int len = 41;

    /* hello world */
    char code[] =
        "\xeb\x15\x5e\xb8\x04\x00\x00\x00"
        "\xbb\x02\x00\x00\x00\x89\xf1\xba"
        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8"
        "\xe6\xff\xff\xff\x48\x65\x6c\x6c"
        "\x6f\x20\x57\x6f\x72\x6c\x64\x0a\x00";

    //char code[] = {0xcd,0x80,0xcc,0};
    char backup[len+1];

    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, len);
    /* Put the breakpoint */
    putdata(traced_process, regs.eip, code, len);
    /* Let the process continue and execute 
        the int 3 instruction */
    ptrace(PTRACE_CONT, traced_process, NULL, NULL);
    wait(NULL);

    putdata(traced_process, regs.eip, backup, len);
    /* 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 injecthello injecthello.c

【执行】
1. run counter
./counter
2. find pid of counter
ps aux | grep counter
3. run injecthello(root)
./injecthello %pid%

【结果】
A进程部分输出如下,输出helloworld证明B进程代码注入成功。
My Counter: 0
1000429
My Counter: 1
1000207
My Counter: 2
1000513
My Counter: 3
1000581
My Counter: 4
1000143
My Counter: 5
1000624
My Counter: 6
Hello World
1000680
My Counter: 7
1000546
My Counter: 8
Hello World
1000652

【参考】
http://www.cnblogs.com/wangkangluo1/archive/2012/06/05/2535484.html

你可能感兴趣的:(信息安全,编程研发,Linux内存替换)