Переполнение стека 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, и значения других регистров.