我正在测试一个汇编器,该汇编器生成X86指令。我想做类似于这样的事情来测试指令是否起作用。
#include<stdio.h>
unsigned char code[2] = {0xc9, 0xc3};
int main() {
void (*foo)();
foo = &code;
foo();
return 0;
}
然而,由于DEP的原因,OS X似乎在阻止这种操作。是否有办法(a)为该程序禁用DEP或(b)以其他格式输入字节,以便我可以跳转到它们。
const unsigned char code[2] = {0xc9, 0xc3};
^^^^^
const
关键字会导致编译器将其放置在const
段中(警告!这是一个实现细节!),该段与text
段在同一段中。整个段应该是可执行的。使用以下方式可能更加可移植:
__attribute__((section("text"))
const unsigned char code[2] = {0xc9, 0xc3};
您可以始终在汇编文件中完成它,
.text
.globl code
code:
.byte 0xc9
.byte 0xc3
然而:如果你想在运行时修改代码,你需要使用mprotect
。默认情况下,内存中没有同时具有写入和执行权限的映射。
下面是一个例子:
#include <stdlib.h>
#include <sys/mman.h>
#include <err.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
unsigned char *p = malloc(4);
int r;
// This is x86_64 code
p[0] = 0x8d;
p[1] = 0x47;
p[2] = 0x01;
p[3] = 0xc3;
// This is hackish, and in production you should do better.
// Casting 4095 to uintptr_t is actually necessary on 64-bit.
r = mprotect((void *) ((uintptr_t) p & ~(uintptr_t) 4095), 4096,
PROT_READ | PROT_WRITE | PROT_EXEC);
if (r)
err(1, "mprotect");
// f(x) = x + 1
int (*f)(int) = (int (*)(int)) p;
return f(1);
}
mprotect
规范规定,如果内存最初没有使用 mmap
进行映射,则其行为是未定义的,但是您正在进行测试而不是发布,所以请知道在 OS X 上它可以正常工作,因为 OS X 的 malloc
在幕后使用 mmap
(我认为是排他性的)。
不知道你在OSX上的DEP情况,但另一件事情是你可以使用malloc()分配内存来写代码,然后跳转到这个malloc分配的区域。至少在Linux上,这段内存不会被执行保护(实际上这就是JIT通常使用的技巧)。
grep /proc/cpuinfo nx
)? 上一次我使用的是没有NX的系统。 - Dietrich Epp
mprotect(2)
来启用PROT_EXEC。看起来这也是在[OSX](http://developer.apple.com/library/mac/#documentation/darwin/reference/manpages/man2/mprotect.2.html)上的正确方法,但我不是专家。 - user786653mprotect
可能会起作用,但是记得阅读手册页面,因为对于一些平台,页面需要使用'mmap'进行分配。 - Some programmer dude