在运行时将代码注入可执行文件

发布于 2024-11-13 10:47:13 字数 342 浏览 2 评论 0原文

我正在开发应用程序(用 C++ 编写),它在运行时生成一些机器代码(Linux,现在是 x86-64,但我计划迁移到 ARM)。接下来,它将生成的代码存储在内存中,并通过跳转到内存位置来执行它。很长一段时间以来,我在分配可执行内存方面遇到了问题,但我最终使用以下方法解决了它:

uint8_t *memory = mmap (NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

到目前为止它有效,但我不确定这是否是执行此类操作的优雅方法。我想知道可执行加载程序是如何做到这一点的?

I'm working on application (written in C++), which generate some machine code at runtime (Linux, x86-64 now, but I plan to migrate on ARM). Next it store generated code in memory and execute it by jumping to memory location. For a long time I had a problem with allocating executable memory, but I finally solved it using:

uint8_t *memory = mmap (NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

So far it works, but I'm not sure if it's elegant way to do such things. I wonder how executable loader do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

放血 2024-11-20 10:47:13

您的解决方案主要是应该做的:让操作系统将页面视为可执行的。但是,某些操作系统将强制执行所谓的 W^X 策略,其中页可以是可写的或可执行的,但不能同时进行。对于这样的系统(即 OpenBSD,但也有修改过的 Linux 版本),上面的 mmap() 将失败。因此,完整的解决方案需要首先使用 mmap()PROT_READ | 分配一些页面。 PROT_WRITE,然后使用mprotect()将页面切换到PROT_READ | PROT_EXEC 当代码生成时。

即使操作系统不强制执行 W^X,也强烈建议调用 mprotect(),因为存在缓存效应(数据访问和执行在 CPU 中是相互独立的;您希望确保 CPU 将使用您新编写的操作码,而不是之前 RAM 中的操作码,其中包含必要的魔法)。

Your solution is mostly what should be done: have the OS consider the pages as executable. However, some operating systems will enforce the so-called W^X policy, in which a page can be either writable or executable, but not both simultaneously. For such systems (namely OpenBSD, but there are modified Linux versions which do it too), your mmap() above will fail. So the complete solution would entail first allocating some pages with mmap() and PROT_READ | PROT_WRITE, then use mprotect() to switch the pages to PROT_READ | PROT_EXEC when the code has been generated.

Even if the OS does not enforce W^X, a call to mprotect() is highly recommended because of cache effects (data access and execution are quite separate from each other in the CPU; you want to be sure that the CPU will use your newly written opcodes and not what was in RAM immediately before; mprotect() contains the necessary magic for that).

抚笙 2024-11-20 10:47:13

这本质上就是可执行加载程序的工作方式;在他们的例子中,他们执行文件的 mmap,而不是匿名映射,但除此之外它本质上是相同的。

请注意,最好不要同时拥有写入和执行访问权限,因为这会使某些类型的安全漏洞变得更容易。您可以在初始映射后使用 mprotect 调整保护标志。

This is essentially how executable loaders do things; in their case they perform a mmap of a file, not an anonymous mapping, but apart from that it's essentially the same.

Note that it's a good idea not to have both write and execute access at the same time, as it makes certain types of security exploits easier. You can use mprotect to adjust the protection flags after the initial mapping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文