美文网首页Linux
linux动态注入(含视频演示)

linux动态注入(含视频演示)

作者: 看雪学院 | 来源:发表于2018-09-26 18:09 被阅读126次

    如果纯粹用文字来描述什么是动态注入,可能还是不太容易理解,所以本篇文章从如下一段代码开始:

    //who.c

    #include <stdio.h>

    #include <unistd.h>

    int main()

    {

    while(1) {

    printf("who are you ?\n");

    sleep(2);

    }

    return0;

    }

    这段代码本身没有什么意思,执行"gcc who.c -o who -g -Wall"完成编译并启动who程序,每隔2s会向终端打印一句"who are you ?",但有意思的是,可能会出现一种"诡异"的现象,比如屏幕上突然冒出一句"it's me ~"。

    1. 为什么可以出现这种“诡异”的现象?

    通过反汇编who程序可以看出,程序最终会进入while(1)循环体,重复执行"bf24064000"、"e8c5feffff"、"bd0x000000"、"e8ebfeffff"、"ebea"这5条机器指令:

    如果who进程执行到某条指令(比如"e8c5feffff")时暂停了,并且在恢复执行之前,0x400586处的指令块被替换成打印"it's me ~"的代码,那么who进程下次执行,自然就会打印"it's me ~"。

    2. 怎么获取打印"it's me ~"的机器码?

    32位系统,编译如下代码并在反汇编结果中提取:

    //isme32.c

    int main()

    {

    __asm__(

    "jmp forward\n\t"

    "backward: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:call backward\n\t"

    ".string \"it's me ~\\n\""

    );

    return0;

    }

    64位系统,编译如下代码并在反汇编结果中提取:

    //isme64.c

    int main()

    {

    __asm__(

    "jmp forward\n\t"

    "backward:popq %rsi\n\t"

    "movq $1, %rax\n\t"

    "movq $2, %rdi\n\t"

    "movq $12, %rdx\n\t"

    "syscall\n\t"

    "int3\n\t"

    "forward:call backward\n\t"

    ".string \"it's me ~\\n\""

    );

    return0;

    }

    本篇文章的实验环境是64位ubuntu系统,所以执行"gcc isme64.c -oisme64 -g -Wall"生成isme64可执行文件,并通过反汇编isme64文件提取机器码:

    用蓝色、绿色标记出来的16进制内容,即为打印"it's me ~"的机器码,但有2点需要说明:

    绿色部分其实是"it's me ~\n\0"这串字符的ascii码值,也被objdump解释成汇编指令了,这是反汇编工具很难避免的一个问题,用gdb/disassemble反汇编的结果也是一样的,因为它们选择的都是线性扫描算法,递归下降算法效果会好一些,但仍然不能保证得到精确的结果;

    C程序实现打印"it's me ~",写一条printf("it's me ~")语句不就可以了么,为什么要写成这种"奇奇怪怪"的样子?因为如果用C语法来实现的话,"it's me ~"这个字符串会被编译器安排到isme64程序的.data段,就没办法随着指令块一起注入到目标进程中,而且这段代码中取"it's me ~"地址的技巧,对于汇编初学者是很有意思的,代码不长,建议在大脑里执行一遍,并找到其中的奥妙。

    3. 怎么实现注入?

    本篇文章仅仅用于学习目的,注入的场景和方法都比较简单,思路在文章第1节已经介绍过了,就是"暂停被注入进程 -> 替换即将执行的指令块 -> 通知被注入进程继续执行",由于有些场合还需要保证注入操作的隐蔽性,所以以下程序还在注入指令块完整执行后,将被注入进程恢复到了注入前的状态:

    (理解这段代码,至少需要学习ptrace()系统调用的作用,如果有内核基础,也可以更深入的学习一下ptrace()的内部原理,另外,CODE宏对应的内容,即为利用文章第2节描述的方法,提取的机器码)

    // inject.c

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <sys/ptrace.h>

    #include <sys/types.h>

    #include <sys/wait.h>

    #include <sys/user.h>

    #include <errno.h>

    // 注入指令块(打印"it's me ~")

    #ifdef ENV_I386

    #define 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\x69\x74\x27\x73"\

        "\x20\x6d\x65\x20\x7e\x0a\x00"

    #define REG_IP  regs.eip

    #else   // X_64

    #define CODE \

        "\xeb\x19\x5e\x48\xc7\xc0\x01\x00"\

        "\x00\x00\x48\xc7\xc7\x02\x00\x00"\

        "\x00\x48\xc7\xc2\x0c\x00\x00\x00"\

        "\x0f\x05\xcc\xe8\xe2\xff\xff\xff"\

        "\x69\x74\x27\x73\x20\x6d\x65\x20"\

        "\x7e\x0a\x00"

    #define REG_IP  regs.rip

    #endif

    #define CODE_SIZE (sizeof(CODE)-1)

    /* 往pid进程的addr地址处写数据 */

    voidputdata(pid_t pid, unsigned longaddr, void*vptr, intlen)

    {

        intcount = 0;

        longword;

        while(count < len)

        {

            memcpy(&word, vptr+count, sizeof(word));

            word = ptrace(PTRACE_POKEDATA, pid, addr+count, word);

            count += sizeof(word);

            if(errno!= 0)

                printf("putdata failed: %p\n", (void*)(addr+count));

        }

    }

    /* 读pid进程addr地址处的数据 */

    voidgetdata(pid_t pid, unsigned longaddr, void*vptr, intlen)

    {

        inti = 0, count = 0;

        longword;

        unsigned long*ptr = (unsigned long*)vptr;

        while(count < len)

        {

            word = ptrace(PTRACE_PEEKDATA, pid, addr+count, NULL);

            count += sizeof(word);

            ptr[i++]  = word;

            if(errno!= 0)

                printf("getdata failed: %p\n", (void*)(addr+count));

        }

    }

    intmain(intargc, char*argv[])

    {

        pid_t pid;

        structuser_regs_struct regs;

        charbackup[CODE_SIZE+1];

        if(argc != 2) {

            printf("Usage: %s {pid}\n", argv[0]);

            return-1;

        }

        // 通过启动参数,获取被注入进程号,并attach

        pid = atoi(argv[1]);

        ptrace(PTRACE_ATTACH, pid, NULL, NULL);  // SIGTRAP

        if(errno!= 0)

            printf("attach failed: %s\n", strerror(errno));

        wait(NULL);  // 收到回复信号,保证后续过程在attach完成的情况下执行

        // 获取被注入进程当前寄存器值

        ptrace(PTRACE_GETREGS, pid, NULL, &regs);

        // 备份*ip寄存器指向的指令块

        getdata(pid, REG_IP, backup, CODE_SIZE);

        // 替换为CODE指令块

        putdata(pid, REG_IP, CODE, CODE_SIZE);

        // 恢复被注入进程的执行

        ptrace(PTRACE_CONT, pid, NULL, NULL);    // SIGCONT

        // 注入程序最后一条指令为int3,此为即为等待注入指令块执行完毕

        wait(NULL);

        // 等待用户输入,方便查看结果

        printf("continue to execute the orginal process, press any key ..\n");

        getchar();

        // 将修改的指令块恢复为备份内容

        putdata(pid, REG_IP, backup, CODE_SIZE);

        // 恢复被注入进程寄存器值

        ptrace(PTRACE_SETREGS, pid, NULL, &regs);

        // detach,被注入进程恢复正常执行

        ptrace(PTRACE_DETACH, pid, NULL, NULL);

        return0;

    }


    4. 视频演示

    a. 执行gcc inject.c -oinject -g -Wall,编译生成注入程序

    b. 查看who进程号N,并执行sudo inject N,进行动态注入操作

    c. 观察who程序执行窗口是否打印了"it's me ~"

    d. 回到inject程序执行窗口,按任意键结束inject进程,并恢复who进程到注入前的状态,继续不停的打印"who are you ?"

    视频链接:https://v.youku.com/v_show/id_XMzgzMTM1NTU1Ng==.html?spm=a2h0k.11417342.soresults.dposter

    5. 参考

    ptrace实现动态注入:http://www.cnblogs.com/r1ng0/p/9585356.html

    https://blog.csdn.net/u012658346/article/details/51159971

    原文作者:xinpoo

    原文链接:https://bbs.pediy.com/thread-246948.htm

    转载请注明,转自看雪论坛

    看雪阅读推荐:

    1、[原创]小白文——好玩不贵的无线遥控器克隆指南

    2、[翻译]内核模式Rootkits:文件删除保护

    3、[翻译]国外2018最新区块链教程英文版,大胆翻译,助力论坛『区块链安全』开设第四棒!

    4、[原创]看雪安全峰会—《从WPA2四次握手看KRACK密钥重装攻击》

    5、[原创]2018看雪CTF第十五题WP

    相关文章

      网友评论

        本文标题:linux动态注入(含视频演示)

        本文链接:https://www.haomeiwen.com/subject/dmsjoftx.html