【问题标题】:C++ Run Byte Array in memoryC++ 在内存中运行字节数组
【发布时间】:2015-01-11 03:03:43
【问题描述】:

我正在尝试开发我认为可以称为启动器的东西?这个概念是将所有二进制文件写入缓冲区,然后将缓冲区加载到内存中。我经常看到这段代码跳来跳去(我已经编写了 exe,所以我可以访问其中的代码。):

//HardCoded Binary For testing Reason, reading to launch didn't work neither did this
char RawCode[11414] = {
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0xFF, 0xFF, ............................................... 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}


//Main Function
int main(int argc, char* argv[])
{
    int(*f)();
    f = (int(*)())&RawCode;
    (int)(*f)();
}

我最初的想法是空字节可能会影响执行导致访问冲突,所以经过一些研究,我发现了一个格式为“/x41/x41/.......x41/”的消息框shellcode没有空字节,但这仍然没有奏效。我有点迷茫,因为没有太多关于此的信息。有没有人对一些好的文章或有用的教程有一些参考,因为我发现没有一个很有帮助。谢谢大家的时间!

【问题讨论】:

    标签: c++ memory


    【解决方案1】:

    很长一段时间以来,所有现代操作系统都实现了某种形式的data execution prevention。这意味着您不能只是将代码放在内存中的某个位置并运行它;必须标记内存区域以允许首先执行。原因是安全性——这使得利用远程代码执行漏洞变得更加困难。

    这也意味着在你尝试这种愚蠢的事情之前,你应该仔细思考,因为它会在你的操作系统试图保护你的过程中撕开一个巨大的漏洞。

    因此,在您可以从内存中运行代码之前,您必须将相关区域标记为可执行。

    在 Windows 下,这可以通过 VirtualProtect 函数来完成。但是,它不能用于任意的内存区域。它必须在页面边界处对齐,并且必须使用相同的 VirtualAlloc 调用分配页面。所以最终,你会得到

    DWORD old_protect;
    LPVOID executable_area = VirtualAlloc(NULL, 11414, MEM_RESERVE, PAGE_READWRITE);
    
    memcpy(executable_area, Rawcode, 11414);
    VirtualProtect(executable_area, 11414, PAGE_EXECUTE, &old_protect);
    
    int(*f)() = (int(*)()) executable_area;
    f();
    
    // Note: RAII this in C++. Restore old flags, free memory.
    VirtualProtect(executable_area, 11414, old_protect, &old_protect);
    VirtualFree(executable_area, 11414, MEM_RELEASE);
    

    【讨论】:

    • 在类 Unix 系统(MacOS、Linux 等)上,您需要使用 mmap 代替 VirtualAlloc 和 mprotect 而不是 VirtualProtect。跨度>
    • 谢谢。这仍然会产生错误,但我认为我现在已经超出了我的能力。错误是:Cons3.exe 中 0x66ACF8C5 (msvcr120.dll) 处的未处理异常:0xC0000005:访问冲突写入位置 0x01070000。我想我是时候回去再玩一些更简单的东西了,直到我更好地掌握了内存区域是如何工作的。谢谢
    • 嗯...函数是自修改的吗?你有时会在小型演示中得到这一点。在这种情况下,您必须使用PAGE_EXECUTE_READWRITE 而不是PAGE_EXECUTE。
    • 我已经尝试过了,但没有运气。稍后我会在 olly 中打开程序,看看我是否能看到代码更深处发生了什么。 Visual Studio 没有世界上最好的调试器,哈哈。如果我发现任何东西,我会发布它。谁知道也许其他人有时会在这里找到他们需要的知识。
    • @404Usernamenotfound 您需要在代码之前剥离可执行文件头和/或元数据,进行一些修复和其他内务处理,然后才能成功执行。如果这是一个 PE 文件,格式会记录在案,并且有许多为其创建加载器的示例。如果它是一个 EXE,它可能不会工作,因为它可能不包含重定位信息。
    【解决方案2】:

    首先,您的数组是否包含可执行文件的表示形式,还是包含可执行机器代码?如果是前者,它可能行不通:大多数可执行文件格式都以操作系统用来加载程序的各种元数据开头;可执行的机器代码在文件的后面。

    其次,您的系统是否使用了类似于 DEP 的东西?很可能您的操作系统将数组标记为不可执行,因此尝试执行它会失败。

    【讨论】:

    • 没关系,这应该是一条评论说“警告:可能不起作用” - 他搞砸了指针。
    • 嗯。我从来没有想过这样的事情。谢谢。我可能需要找出一些不同的东西,我猜哈哈
    【解决方案3】:

    (抱歉回复晚了)

    从数组中执行字节是一个坏主意。它不是跨平台的,会带来巨大的安全隐患。

    执行外部代码的一种更安全的方法是字节码解释器。您可以将程序的访问权限限制为仅触及它需要的内容。缺点是您要么必须编写自己的编译器,要么自己编写原始字节码。

    一个很好的教程链接在这里:http://gameprogrammingpatterns.com/bytecode.html

    另一个不太安全的解决方案是使用 DLL。 (动态链接库)这样您就不必编写自己的编译器了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      相关资源
      最近更新 更多