无法为Shell编码溢出缓冲区

3
我有一个shell代码,它应该打开一个MessageBox。当我使用https://github.com/NytroRST/ShellcodeCompiler测试时,它有效,但是当我使用C创建一个新的控制台应用程序并尝试编译它时,就会出现问题。
#include <stdio.h>
#include <Windows.h>

unsigned char rc[] = "\x31\xC3\x89\x64\xE2\x80\xB9\x41\x30\xE2\x80\xB9\x40\x0C\xE2\x80\xB9\x70\x14\xC2\xAD\xE2\x80\x93\xC2\xAD\xE2\x80\xB9\x58\x10\xE2\x80\xB9\x53\x3C\x01\xC3\x9A\xE2\x80\xB9\x52\x78\x01\xC3\x9A\xE2\x80\xB9\x72\x20\x01\xC3\x9E\x31\xC3\x89\x41\xC2\xAD\x01\xC3\x98\xC2\x81\x38\x47\x65\x74\x50\x75\xC3\xB4\xC2\x81\x78\x04\x72\x6F\x63\x41\x75\xC3\xAB\xC2\x81\x78\x08\x64\x64\x72\x65\x75\xC3\xA2\xE2\x80\xB9\x72\x24\x01\xC3\x9E\x66\xE2\x80\xB9\x0C\x4E\x49\xE2\x80\xB9\x72\x1C\x01\xC3\x9E\xE2\x80\xB9\x14\xC5\xBD\x01\xC3\x9A\x31\xC3\x89\x53\x52\x51\x68\x61\x72\x79\x41\x68\x4C\x69\x62\x72\x68\x4C\x6F\x61\x64\x54\x53\xC3\xBF\xC3\x92\x92\xC3\x84\x0C\x59\x50\x31\xC3\x80\x66\xC2\xB8\x6C\x6C\x50\x68\x33\x32\x2E\x64\x68\x75\x73\x65\x72\x54\xC3\xBF\x54\x24\x10\xC6\x92\xC3\x84\x0C\x50\x31\xC3\x80\xC2\xB8\x6F\x78\x41\x23\x50\xC6\x92\x6C\x24\x03\x23\x68\x61\x67\x65\x42\x68\x4D\x65\x73\x73\x54\xC3\xBF\x74\x24\x10\xC3\xBF\x54\x24\x1C\xC6\x92\xC3\x84\x0C\x50\x31\xC3\x80\xC2\xB8\x65\x73\x73\x23\x50\xC6\x92\x6C\x24\x03\x23\x68\x50\x72\x6F\x63\x68\x45\x78\x69\x74\x54\xC3\xBF\x74\x24\x20\xC3\xBF\x54\x24\x20\xC6\x92\xC3\x84\x0C\x50\x31\xC3\x80\xC2\xB8\x59\x6F\x75\x23\x50\xC6\x92\x6C\x24\x03\x23\x68\x41\x72\x65\x20\x68\x48\x6F\x77\x20\x68\x48\x65\x79\x20\x54\x31\xC3\x80\x50\x68\x54\x65\x73\x74\x54\x31\xC3\x80\x50\xC3\xBF\x74\x24\x04\xC3\xBF\x74\x24\x14\x31\xC3\x80\x50\xC3\xBF\x54\x24\x34\x92\xC3\x84\x20\x31\xC3\x80\x50\xC3\xBF\x54\x24\x04\x6e";

int main() {
    (*(void(*)()) rc)();
}

每次运行它后都会抛出访问冲突异常,如果我更改shell代码注入位置的内存保护,就可以摆脱这个异常。但仍然无法显示MessageBox。我确定shell代码有效,因为上面的链接有一个测试shellcode的程序,它可以完美地工作。他们的利用方法与我不同,他们使用C++而我使用C。

1
你需要更改内存页面权限并检查shell代码是否正确。 - JohnySiuu
2个回答

3
因为你正在尝试调用rc的地址,而它的内存保护PAGE_READWRITE,因此会出现访问冲突错误。
为了使其正常工作,您需要分配一个缓冲区,并将保护设置为PAGE_EXECUTE_READ
助手函数:
void* AllocFunction(const void* rawData, const size_t size)
{
    void* pFunction = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
    if (pFunction == nullptr) throw;

    memcpy(pFunction, rawData, size);

    DWORD dwOldProtect;
    if (!VirtualProtect(pFunction, size, PAGE_EXECUTE_READ, &dwOldProtect)) throw;

    return pFunction;
}

用法:

void (*lpFunction)() = nullptr;
*(void**)&lpFunction = AllocFunction(rc, sizeof(rc));

lpFunction();

0
使用 VirtualProtect
DWORD oldProt = 0;
VirtualProtect(rc, sizeof(rc), PAGE_EXECUTE_READWRITE, &oldProt);

你不应该这样做,因为更改虚拟保护不仅会改变所需的大小,还会改变整个页面的保护。而且,出于某种原因,我过去曾经这样做过,在x86_64上崩溃了,但在x86上没有。 - thedemons
@thedemons,这对我有用,缓冲区的内存地址始终是只读的。公平地说,我应该调用VirtualQuery()并删除rc作为大小。例如:VirtualProtect(rc, 1, PAGE_EXECUTE_READWRITE, &oldProt) - JohnySiuu
这段代码在x64中具有未定义的行为。为什么它被标记为已接受? - user20279575
@JohnySiuu 仅仅因为代码可运行并不意味着你就应该这样做。缓冲区的内存地址一直是只读的 不,它并不是,因为它没有被声明为 const - thedemons
@tokputi 这个 shell 代码只适用于 x86。 - JohnySiuu
@thedemons 不需要声明为 const - JohnySiuu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接