没有DEP的堆栈中shellcode的执行失败

逆向工程 开发
2021-06-28 00:37:54

这是显示我的问题的最简单示例。一切都在禁用 DEP 的 WinXp sp3 中。

char f() {
    // shellcode starting with some NOPs,
    char shellcode[400]= {
            0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
            0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
            0x66, ... some basic shellcode here ...   0x30. 
            0xCC
    };

    // Overwriting Return address in stack to return to NOPs in shellcode above
    b[404]=0xf0;
    b[405]=0xfb;
    b[406]=0x12;
    b[407]=0x00;
}

这以失败告终:

(920.e7c): Illegal instruction - code c000001d (!!! second chance !!!)
eax=7c801d7b ebx=7c80262c ecx=7c801bfa edx=00060002 esi=00000000 edi=7c802654
eip=0012fc15 esp=0012ff08 ebp=7e410000 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
0012fc15 d9907ca5e490    fst     dword ptr [eax-6F1B5A84h] ds:0023:0d64c2f7=????????

但是如果我直接执行shellcode,它的工作原理是:

char f() {
    // shellcode starting with some NOPs,
    char shellcode[400]= {
            0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,  
            0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
            0x66, ... some basic shellcode here ...   0x30. 
            0xCC
    };

    void *exec = shellcode;

    ((void(*)())exec)();
}

这将正常工作。

我确实跟踪了上述两种情况下的执行情况。并且在这两种情况下,EIP 确实成功登陆 NOPs 区域并继续执行。但我不知道为什么第一个案例失败了。

一种猜测是,在第一种情况下,当 f() 返回到 0x0012fbf0 时,堆栈帧外区域中的 shellcode(即,此时 ESP 位于 SHELLCODE 区域下方)。

任何人都可以知道为什么第一个案例失败了?

1个回答

您的“ESP 低于 SHELLCODE”可能应该是“ESP高于SHELLCODE”,因为在 x86 中,堆栈向下增长。

无论如何,您的 shell 代码位于“刚好超出”堆栈指针的区域内,这可能是您的问题。每当您从 shell 代码调用函数时,该函数都会在堆栈上分配一些空间。当该函数调用另一个函数时,堆栈上有更多空间。这些函数放在堆栈上的东西会在某一时刻开始覆盖你的 shell 代码。如果它们覆盖了您尝试启动的可执行文件的名称,您的 shellcode 将尝试启动一个无意义的名称,这将失败。如果它们覆盖了您的 shell 代码的结尾,则返回到您的 shell 代码,就像您在第一个示例中所做的那样。

您可能希望将 asub esp, 0x200放在您的 shell 代码的开头,以再次将堆栈的分配部分扩展到您的 shell 代码之外。(当然,您需要减去的数字取决于您的 shellcode 的大小)。或者,让您的数组更大,并从更多0x90字节开始,以增加您的堆栈不会增长到您的 shellcode 的“有用”部分的机会。