5

我正在测试我正在编写的生成 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)以另一种格式输入字节,以便我可以跳转到它们。

4

2 回答 2

6

如果你只是需要测试,试试这个,它很神奇......

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)。

于 2011-11-18T07:40:39.013 回答
0

不知道你在 OSX 上的 DEP,但你可以做的另一件事是 malloc() 你编写代码的内存,然后跳转到这个 malloc'ed 区域。至少在 Linux 上,这个内存不会受到 exec 保护(事实上,这就是 JIT 通常的作用)。

于 2011-11-18T07:27:41.373 回答