Переполнение стека ext x86 vs x86_64 простой код C
Позвольте мне пропустить введение и перейти к хорошей части.
Я читаю "Руководство по этическим хакерам" и пробую примерный код (около p175).
----------------------------------------------- ------------------------------------------
Цель: переполнение EIP в стеке
Пример кода:
##> cat overflow.c
main(){
char str1[10]; // declare a 10byte string
// next, copy 35 bytes of 'A' to 'str1'
strcpy(str1,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}
----------------------------------------------- ------------------------------------------
Если я компилирую и запускаю его на своем ноутбуке x86, результат будет таким, как ожидалось.
результат на X86 с openSuse 12.1
##> uname -a
Linux linux-tzxm.site 3.1.0-1.2-desktop #1 SMP PREEMPT
Thu Nov 3 14:45:45 UTC 2011 (187dde0) i686 i686 i386 GNU/Linux
##> cat /proc/sys/kernel/randomize_va_space
1
##> gcc version 4.6.2 (SUSE Linux)
##> GNU gdb (GDB) SUSE (7.3-41.1.2)
##> gdb -q overflow
Reading symbols from /home/administrator/Programming/C/testProgs/overflow...done.
(gdb) run
Starting program: /home/administrator/Programming/C/testProgs/overflow
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info reg eip
eip 0x41414141 0x41414141
----------------------------------------------- ------------------------------------------
Однако, если я делаю то же самое на своем ноутбуке x86_64, тогда результат будет отличаться и не ожидается (с моей небольшой точки зрения знаний)
результат на x86_64 с openSuse 11.3
##> uname -a
Linux linux-2mna.site 2.6.34.10-0.4-desktop #1 SMP PREEMPT 2011-10-19 22:16:41 +0200 x86_64 x86_64 x86_64 GNU/Linux
##> cat /proc/sys/kernel/randomize_va_space
1
##> gcc version 4.5.0 20100604
##> GNU gdb (GDB) SUSE (7.1-3.12)
##> gdb -q overflow2
Reading symbols from /home/jojojorn/Documents/Personal/HACKING/C_Prog/Tests/testProgs/overflow2...done.
(gdb) run
Starting program: /home/jojojorn/Documents/Personal/HACKING/C_Prog/Tests/testProgs/overflow2
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400553 in main () at overflow.c:11
11 }
(gdb) info reg eip
Invalid register `eip'
(gdb)
----------------------------------------------- ------------------------------------------
Итак, вот мои вопросы:
1) почему я не могу переполнить EIP в своем стеке на моем x86_64? Есть ли разница в поведении стека между x86_64 и x86?
2), когда я запускаю скомпилированный двоичный файл x86 на моем x86_64 и проверяю его с помощью gdb, результат будет таким же, как ожидалось.
Итак, я предполагаю, что разница получается с использованием gcc 32 бит и gcc 64 бит? Для этого простого кода, что есть и почему существует разница?
3) Если я хочу, чтобы мой код на x86_64 вел себя так, как он был скомпилирован на x86, есть ли параметр gcc для установки во время компиляции?
4) Я задаю этот вопрос, а это значит, что у меня еще нет надлежащего знания, чтобы задавать лучшие вопросы. Есть ли что-то дополнительное, что приходит в ваши гениальные умы, которые я должен был спросить (и на что вы ответили бы)?
С уважением
Ответы
Ответ 1
В x86_64 указатель инструкции RIP
, not EIP
... таким образом, если вы запросите регистр EIP
в gdb
с помощью 64-битного исполняемого файла, вы не получите никаких значений так как это не допустимый 64-битный регистр. Если вы хотите сохранить свой исполняемый файл как 32-разрядный на собственной 64-битной платформе, тогда передайте gcc
флаг -m32
во время компиляции.
Если вы хотите увидеть, как работает x86_64 Unix-стек по сравнению с стеклом x86 Unix, я предлагаю прочитать x86_64 Unix ABI, разделы 3.2 и 3.4.
Ответ 2
-
Это не то, что переполнения на x86_64 нет, это просто другой способ представления исключения. Вместо того, чтобы фактически сказать вам, что он не смог выполнить код 0x4141414141414141 после фактического обновления rip
, он сообщает вам, что перед обновлением адрес назначения недопустим. Это архитектурная разница между кодом x86 и кодом x86_64 и всякий раз, когда вы выполняете 64-битный код, как это делается.
-
Опять же, у вас будет другое другое сообщение только на 64-битном коде.
-
Вам нужно будет скомпилировать его как 32-битный код. Невозможно получить одно и то же сообщение, если вы хотите скомпилировать его как код x86_64.
-
На самом деле нетрудно заметить эту разницу, если вы должны правильно отлаживать код и видеть, где указывается rip
, и значения других регистров.