栈溢出jmp esp原理

栈溢出source code test2.c如下

为确定溢出长度和地址,使用测试数据1234567890*N组合,如果正确溢出则查看错误报告

Code=c5说明存在溢出,address = 0x36353433 = 3456小端序,说明溢出地址为3456

所以长度确定为10+2 =12([1234567890][12]+XXXX)

所以溢出payload = [1-0][12][3456] 出错地址等同于payload = [1-0][1-0]

经典的jmp esp跳转 编写shellcode原理

在无溢出的test1.c程序中,payload = [1-6]小于数组长度8

当程序执行完strcpy(),要执行retn返回时,此时栈顶esp = 0x0012FF84

执行retn,返回到main的下一条指令,此时栈顶esp = 0x0012FF88

在存在溢出的test2.exe测试,执行完strcpy()后,在retn前,栈顶esp = 0x12FF84,并且保存的内容为34657890

执行retn操作后,虽然返回的代码窗口为空,但此时栈帧 esp = 0x0012FF88,内容为7890

也就是说无论是否存在溢出,返回的esp地址都是相同的,指向的是返回地址(0x12FF84)的下一个地址。

构造shellcode的思想就是使用payload = [1-0]*N+[1-m]先造成溢出,然后返回地址填写的就是jmp esp命令地址,这样运行后会跳转到例如uer32.dll的空间执行jmp esp跳转回来,之后执行填充的栈空间的shellcode,总体构造思路为:

  Payload = overflow + jmp esp address + shellcode

查找user32.dll中的jmp esp命令的源码如下

#include <windows.h>
#include <stdio.h>
#define DLL_NAME "user32.dll"
int 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\n",address);
            }
        }
        catch(...)
        {
            int address = (int)ptr + position;
            printf("END OF 0x%x\n", address);
            done_flag = true;
        }
    }
    getchar();
    return 0;
}  

运行找到很多user32.dll中的jmp esp地址,可以使用其中某个地址作为jmp esp指令地址,有些地址跟系统和运行程序相关,有些地址是通用的

您可能还喜欢...