Переход к сегменту данных - PullRequest
5 голосов
/ 18 ноября 2011

Я тестирую пишущий ассемблер, который генерирует инструкции для X86.Я хотел бы сделать что-то подобное, чтобы проверить, работают ли инструкции.

#include<stdio.h>

unsigned char code[2] = {0xc9, 0xc3};

int main() {
  void (*foo)();
  foo = &code;
  foo();
  return 0;
}

Однако, похоже, OS X предотвращает это из-за DEP.Есть ли способ либо (а) отключить DEP для этой программы, либо (б) ввести байты в другом формате, чтобы я мог перейти к ним.

Ответы [ 2 ]

6 голосов
/ 18 ноября 2011

Если вам просто нужно протестировать, попробуйте это вместо этого, это magic ...

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 за кулисами (исключительно, я думаю).

0 голосов
/ 18 ноября 2011

Не знаю о вашем DEP в OSX, но вы могли бы также выполнить malloc () памяти, в которую вы пишете код, и затем перейти в эту область malloc. По крайней мере, в Linux эта память не будет защищена exec (и на самом деле именно так JIT обычно делает свое дело).

...