вызывающий код хранится в куче из vc ++ - PullRequest
11 голосов
/ 29 декабря 2008

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

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, как если бы это была функция? (Я использую VC ++ 2008 Express).

Спасибо

Ответы [ 4 ]

12 голосов
/ 29 декабря 2008

На самом деле, 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. Кто знает.

12 голосов
/ 29 декабря 2008

В комментарии не хватило места. 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 и от AMD - хорошие справочные материалы - получите их, если у вас их нет.

6 голосов
/ 29 декабря 2008

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

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)();

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

0 голосов
/ 13 января 2012

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

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

...