跳转到数据段

时间:2011-11-18 07:13:14

标签: c macos assembly dep

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

2 个答案:

答案 0 :(得分: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(我认为是专门的)。

答案 1 :(得分:0)

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