如何分配可执行内存缓冲区?

Joh*_*ith 6 c++ malloc executable jit compiler-optimization

我想分配一个我可以在Win32上执行的缓冲区,但我在visual studio中有一个例外,因为malloc函数返回一个不可执行的内存区域.我读到有一个NX标志要禁用...我的目标是在飞行时将字节码转换为asm x86并牢记性能.

有人可以帮助我吗?

JS

Chr*_*ckl 13

你没有用malloc它.无论如何,你为什么要在C++程序中?但是,您也不new用于可执行内存.有特定于Windows的VirtualAlloc函数来保留内存,然后使用VirtualProtect应用的函数标记为可执行文件,例如PAGE_EXECUTE_READ标志.

完成后,可以将指向已分配内存的指针强制转换为适当的函数指针类型,然后调用该函数.完成后不要忘记打电话VirtualFree.

下面是一些非常基本的示例代码,没有错误处理或其他健全性检查,只是为了向您展示如何在现代C++中完成此操作(程序打印5):

#include <windows.h>
#include <vector>
#include <iostream>
#include <cstring>

int main()
{
    std::vector<unsigned char> const code =
    {
        0xb8,                   // move the following value to EAX:
        0x05, 0x00, 0x00, 0x00, // 5
        0xc3                    // return what's currently in EAX
    };    

    SYSTEM_INFO system_info;
    GetSystemInfo(&system_info);
    auto const page_size = system_info.dwPageSize;

    // prepare the memory in which the machine code will be put (it's not executable yet):
    auto const buffer = VirtualAlloc(nullptr, page_size, MEM_COMMIT, PAGE_READWRITE);

    // copy the machine code into that memory:
    std::memcpy(buffer, code.data(), code.size());

    // mark the memory as executable:
    DWORD dummy;
    VirtualProtect(buffer, code.size(), PAGE_EXECUTE_READ, &dummy);

    // interpret the beginning of the (now) executable memory as the entry
    // point of a function taking no arguments and returning a 4-byte int:
    auto const function_ptr = reinterpret_cast<std::int32_t(*)()>(buffer);

    // call the function and store the result in a local std::int32_t object:
    auto const result = function_ptr();

    // free the executable memory:
    VirtualFree(buffer, 0, MEM_RELEASE);

    // use your std::int32_t:
    std::cout << result << "\n";
}
Run Code Online (Sandbox Code Playgroud)

与普通的C++内存管理相比,这是非常不寻常的,但不是真正的火箭科学.困难的部分是让实际的机器代码正确.请注意,我的示例只是非常基本的x64代码.

  • 在C ++程序中使用malloc的原因是要从堆中分配动态内存。完全正常。 (2认同)
  • @KyleSweet:在 C++ 中,您使用 `new`(“普通”或放置 new,如 `std::allocator`)从空闲存储(而不是堆)动态分配。从技术上讲,您可以使用 `malloc`,但您实际上是在编写 C 而不是(惯用的)C++。对于 OP 的问题,`VirtualAlloc` 和 `malloc` 之间的区别也很重要。 (2认同)
  • 我只是在回答你提出的问题。如果您想要的只是堆中的一些快速而又脏的内存,请不要害怕使用malloc! (2认同)

zx4*_*485 5

扩展以上答案,一个好的做法是:

  • 使用VirtualAlloc和读写访问权限分配内存。
  • 用您的代码填充该区域
  • 更改该区域的保护VirtualProtect以执行读取访问
  • 跳转到/调用该区域的入口点

所以看起来可能像这样:

adr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// write code to the region
ok  = VirtualProtect(adr, size, PAGE_EXECUTE_READ, &oldProtection);
// execute the code in the region
Run Code Online (Sandbox Code Playgroud)

  • 根据规范,如果最后一个参数为 NULL,VirtualProtect 将失败。必须使用指向(虚拟)输出变量的指针。 (2认同)