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

时间:2011-06-03 19:01:38

标签: linux assembly arm x86-64

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

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

到目前为止它的确有效,但我不确定它是否是做这些事情的优雅方式。我想知道可执行加载器是如何做到的?

2 个答案:

答案 0 :(得分:13)

这实际上是可执行加载器的工作方式;在他们的情况下,他们执行文件的mmap,而不是匿名映射,但除此之外,它基本上是相同的。

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

答案 1 :(得分:13)

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

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

相关问题