Код вызова, хранящийся в куче от 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).