Я наткнулся на этот фрагмент кода (для всей программы см. Страницу this, см. Программу под названием «srop.c»).C литье функции ассемблера
Мой вопрос касается того, как func
используется в методе main
. Я только сохранил код, который, как я думал, может быть связан.
Это строка *ret = (int)func +4;
, которая меня смущает.
Есть три вопроса, я по поводу этого:
func(void)
является функцией, если она не будет вызвана сfunc()
(обратите внимание на скобки)- Признавая, что это может быть какой-то мне неизвестно способ вызов функции, как ее можно отличить до
int
, когда он должен вернутьvoid
? - Я понимаю, что автор не хочет сохранять указатель кадра и не обновлять его (пролог), как указывает его комментарий. Как это пропуская две линии вперед достигнуты с литой функции до
int
и добавлением четырех?
.
(gdb) disassemble func
Dump of assembler code for function func:
0x000000000040069b <+0>: push %rbp
0x000000000040069c <+1>: mov %rsp,%rbp
0x000000000040069f <+4>: mov $0xf,%rax
0x00000000004006a6 <+11>: retq
0x00000000004006a7 <+12>: pop %rbp
0x00000000004006a8 <+13>: retq
End of assembler dump.
Возможно отношение в том, что при компиляции GCC говорит мне следующее:
warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
Пожалуйста, смотрите ниже код.
void func(void)
{
asm("mov $0xf,%rax\n\t");
asm("retq\n\t");
}
int main(void)
{
unsigned long *ret;
/*...*/
/* overflowing */
ret = (unsigned long *)&ret + 2;
*ret = (int)func +4; //skip gadget's function prologue
/*...*/
return 0;
}
[Редактировать] После очень полезные советы, вот некоторые дополнительные данные:
calling func returns a pointer to the start of the function: 0x400530
casting this to an int is dangerous (in hex) 400530
casting this to an int in decimal 4195632
safe cast to unsigned long 4195632
size of void pointer: 8
size of int: 4
size of unsigned long: 8
[Edit 2:] @cmaster: Не могли бы вы указать мне еще немного информации о том, как поставить функция ассемблера в отдельном файле и ссылка на него? Исходная программа не будет компилироваться, потому что она не знает, что функция prog
(если она помещена в файл ассемблера), поэтому она должна быть добавлена либо до, либо во время компиляции?
Кроме того, gcc -S
при запуске файла C, включая только команды сборки, похоже, добавляет много дополнительной информации, не может func(void)
быть представлен следующим кодом ассемблера?
func:
mov $0xf,%rax
retq
Спасибо, отличный ответ. Проверка предположения №4, и вы были полностью правы, однако адреса памяти настолько низки, что они работают даже при усечении. Не могли бы вы связать мне дополнительную информацию о том, как связать две программы, как при компиляции, так и как вызвать функцию сборки из программы C? –
Поскольку вы изменяете сгенерированный файл ассемблера, у вас уже есть необходимые точки входа (они определяются директивами ассемблера, которые обычно начинаются с точки '.'). То есть, связь точно такая же, как если бы вы компилировались из файла .c, который использовался для создания вашего шаблона.Чтобы вызвать функцию ассемблера, вам нужно только «указать» правильный прототип функции в файле заголовка C. Я говорю «только», потому что ваш компилятор не будет проверять его правильность, и вам нужно будет подчиняться соглашениям о вызовах, которые использует ваш компилятор. – cmaster
Что касается дальнейшего чтения: google для «ABI <ваше системное имя><ваша архитектура процессора><ваш компилятор>", и вы должны найти некоторые спецификации со всеми соответствующими данными (ABI означает «абстрактный двоичный интерфейс»). Для менее формальной информации повторите попытку с «вызовами конвенций». Обратите внимание, что существует несколько радикально отличающихся ABI для процессоров X86, вам нужно найти тот, который используется в вашей системе. Один из этих ABI передает все аргументы в стек, например, в то время как другой использует регистры для первых нескольких аргументов. Хорошим началом может быть: http://en.wikipedia.org/wiki/X86_calling_conventions – cmaster