Код вызова, хранящийся в куче от vС++

Представьте, что я делаю что-то вроде этого:

void *p = malloc (1000);
*((char*)p) = some_opcode;
*((char*)p+1) = another_opcode; // for the sake of the example: the opcodes are ok

....
etc...

Как я могу определить указатель функции для вызова p, как если бы это была функция? (я использую VС++ 2008 express).

Спасибо

Ответ 1

В комментарии недостаточно места. Joe_Muc верен. Вы не должны вводить код в память, полученный с помощью malloc или new. У вас возникнут проблемы, если вы измените свойства страницы страниц, которые выделяет Windows.

Это не проблема, потому что использование VirtualAlloc() и связанных с ними API WIn32 легко: вызовите VirtualAlloc () и установите flProtect до [PAGE_EXECUTE_READWRITE][2]

Обратите внимание, что вы должны, вероятно, сделать три распределения, одну страницу защиты, страницы, которые вам нужны для вашего кода, а затем еще одну страницу охраны. Это даст вам небольшую защиту от плохого кода.

Также переносите вызовы на сгенерированный код с обработкой структурированных исключений.

Далее, Windows X86 ABI (соглашения о вызовах) не были хорошо документированы (я знаю, я посмотрел). Существует некоторая информация здесь, здесь, здесь Лучший способ увидеть, как все работает, - это посмотреть на код, сгенерированный компилятором. Это легко сделать с помощью переключателей \FA (их четыре).

Здесь вы можете найти соглашения о 64-битных вызовах .

Кроме того, вы все равно можете получить Microsoft Macro Assembler MASM здесь. Я рекомендую записать свой машинный код в MASM и посмотреть его вывод, а затем сделать генератор машинного кода похожими.

Руководства Intel по процессорам Intel и AMD являются хорошими ссылками - получить их, если у вас их нет.

Ответ 2

Собственно, malloc, вероятно, не отрежет. В Windows вам, вероятно, нужно будет вызвать что-то вроде [VirtualAlloc] (http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx), чтобы получить исполняемую страницу памяти.

Начало маленького:

void main(void)
{
    char* p = (char*)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    p[0] = (char)0xC3;  // ret

    typedef void (*functype)();
    functype func = (functype)p;
    (*func)();
}

Следующий шаг для игры с вашим кодом - сохранить регистр EBP. Это остается как упражнение.: -)

После написания этого, я запустил его с помощью malloc, и он также работал. Возможно, это связано с тем, что я запускаю учетную запись администратора на Windows 2000 Server. Другие версии Windows могут действительно нуждаться в вызове VirtualAlloc. Кто знает.

Ответ 3

Если у вас есть правильные коды операций, вызов может быть таким же простым, как отведение указателя на функцию и вызов его.

typedef void (*voidFunc)();

char *p = malloc (1000);
p[0] = some_opcode;
p[1] = another_opcode; // for the sake of the example: the opcodes are ok
p[n] = // return opcode...

((voidFunc)p)();

Обратите внимание, что если вы не отметите страницу как исполняемую, ваш процессор может не позволить вам выполнять код, сгенерированный в куче.

Ответ 4

В настоящее время я также изучаю исполняемый сгенерированный код, и хотя ответы здесь не дали мне именно то, что мне было нужно, вы, ребята, отправили меня на правильный путь.

Если вам нужно пометить страницу как исполняемую в системах POSIX (Linux, BSD и т.д.), проверьте mmap (2).