没有VC如何用CodeBlocks运行shellcode

在《0day安全:软件漏洞分析技术(第二版)》的第3章中,作者给出了一种便捷运行shellcode的方法:

    char shellcode[]="\x66\x81\xEC\x40\x04\x33\xDB......";//欲调试的十六进制机器码
    void main()
    {
        __asm
        {
             lea    eax, shellcode
             push   eax
             ret
        }
    }

原书作者是用Visual C++6.0编译代码的,操作系统是Windows XP SP2。我在Windows XP SP3下用CodeBlocks编译如上代码时则会出错,因为Visual C++6.0中的编译器和CodeBlocks中的默认编译器gcc关于内联汇编的语法有很大不同,可参考64位ubuntu中c与intel汇编混合编程之C语言内联汇编,虽然这篇文章是介绍Linux环境下的,但gcc编译器C语言内嵌汇编的语法在Windows下和Linux下是一样的。简单尝试后得到如下可行代码:

    int main() {
        char popup_general[]=
            "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1"
            "\x4F\x68\x32\x74\x91\x0C\x8B\xF4\x8D\x7E"
            "\x0C\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33"
            "\x32\x53\x68\x75\x73\x65\x72\x54\x33\xD2"
            "\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B\x49\x1C"
            "\x57\x56\x8B\x69\x08\x8B\x79\x20\x8B\x09"
            "\x66\x39\x57\x18\x75\xF2\x5E\x5F\xAD\x3D"
            "\x6A\x0A\x38\x1E\x75\x05\x95\xFF\x57\xF8"
            "\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03"
            "\xCD\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B"
            "\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A\xC4"
            "\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1"
            "\x3B\x54\x24\x1C\x75\xE4\x8B\x59\x24\x03"
            "\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD"
            "\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A"
            "\x0A\x38\x1E\x75\xA9\x33\xDB\x53\x68\x57"
            "\x21\x21\x21\x68\x5A\x5A\x5A\x47\x8B\xC4"
            "\x53\x50\x50\x53\xFF\x57\xFC\x53\xFF\x57"
            "\xF8";
        char *p=popup_general;
        // the asm code:
        asm (
             "push  %0;\n"
             "ret;"
              :"=r"(p)
              :
              :
            );
        return 0;
    }

编译命令是:

    gcc -masm=intel shellcode.c -o shellcode

参数-masm=intel表明内联汇编采用intel语法,而不是gcc默认的AT&T语法。内嵌汇编中的%0指的便是第一个参数p,gcc编译时会把p保存到某个通用寄存器中(关键字r指明这一点),故可以直接push %0,之后紧接着ret指令将EIP寄存器的值修改为刚刚压入栈中的值,即p的值,这样shellcode便会紧接着运行。这段shellcode会弹出一个消息框,之后正常退出,运行结果如下图所示:

补充说明一下gcc编译器的参数问题,你可以在codeblocks中通过图形化界面设置参数,也可以和我一样找到gcc所在的路径,设置环境变量,然后在cmd命令行窗口中手动输入整个编译命令。我的机器上gcc所在的目录是:C:\Program Files\CodeBlocks\MINGW\bin\。嫌每次都输命令麻烦可以写一个简单的批处理shellcode.bat:

    gcc -masm=intel shellcode.c -o shellcode
    pause

(2016年8月3日更新)

在exploit-db看到shellcode是这样运行的:

    #include<stdio.h>
    char shellcode[]=
            "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
            "\x8B\xF4\x8D\x7E\x0C\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
            "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
            "\x49\x1C\x57\x56\x8B\x69\x08\x8B\x79\x20\x8B\x09\x66\x39\x57\x18"
            "\x75\xF2\x5E\x5F\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95\xFF\x57\xF8"
            "\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59\x20\x03\xDD"
            "\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A\xC4\x74\x08"
            "\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75\xE4\x8B\x59"
            "\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03\x2C\xBB\x95"
            "\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB\x53\x68\x57"
            "\x21\x21\x21\x68\x5A\x5A\x5A\x47\x8B\xC4\x53\x50\x50\x53\xFF\x57"
            "\xFC\x53\xFF\x57\xF8"//181
            ;
    main()
    {
        (* (int(*)()) shellcode)();
    }

我的理解如下: int()() 是一个函数指针,该函数的参数为空,返回值为int型,( int()() ) shellcode 是强制类型转换,将原本为char [ ]的变量转换为函数指针,* ( int(*)() shellcode )取出该函数,最后的()表示函数调用。这样不用内联汇编,便可以执行shellcode,果然是人外有人,天外有天。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

18 + 6 =