Может ли кто-нибудь помочь в объяснении вывода обратной трассировки, имеющего термин «разбить стек»? - PullRequest
1 голос
/ 26 апреля 2009

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

    *** stack smashing detected ***: ./a.out terminated
             ======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xb7f856d8]
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0xb7f85690]
./a.out[0x804845f]
    [0x666a6473]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:07 91312      /home/mawia/a.out
08049000-0804a000 r--p 00000000 08:07 91312      /home/mawia/a.out 
0804a000-0804b000 rw-p 00001000 08:07 91312      /home/mawia/a.out
084cd000-084ee000 rw-p 084cd000 00:00 0          [heap]
b7e6d000-b7e7a000 r-xp 00000000 08:07 221205     /lib/libgcc_s.so.1
b7e7a000-b7e7b000 r--p 0000c000 08:07 221205     /lib/libgcc_s.so.1
b7e7b000-b7e7c000 rw-p 0000d000 08:07 221205     /lib/libgcc_s.so.1
b7e8a000-b7e8b000 rw-p b7e8a000 00:00 0 
b7e8b000-b7fe3000 r-xp 00000000 08:07 238955     /lib/tls/i686/cmov/libc-2.8.90.so
b7fe3000-b7fe5000 r--p 00158000 08:07 238955     /lib/tls/i686/cmov/libc-2.8.90.so
b7fe5000-b7fe6000 rw-p 0015a000 08:07 238955     /lib/tls/i686/cmov/libc-2.8.90.so
b7fe6000-b7fe9000 rw-p b7fe6000 00:00 0 
b7ff6000-b7ff9000 rw-p b7ff6000 00:00 0 
b7ff9000-b8013000 r-xp 00000000 08:07 221196     /lib/ld-2.8.90.so
b8013000-b8014000 r-xp b8013000 00:00 0          [vdso]
b8014000-b8015000 r--p 0001a000 08:07 221196     /lib/ld-2.8.90.so
b8015000-b8016000 rw-p 0001b000 08:07 221196     /lib/ld-2.8.90.so
bfd00000-bfd15000 rw-p bffeb000 00:00 0          [stack]
Aborted

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

EDIT

код - просто ввести строку. Я специально ввел строку, размер которой был больше, чем длина массива символов, который я определил, чтобы получить разбивку стека. код:

 int main()

 {
  int a;
  char s[10];
  scanf("%s",s);
  return 0;
 }

Спасибо.

Ответы [ 3 ]

9 голосов
/ 26 апреля 2009

Редактировать: просто перечитайте название вашей проблемы. Вы хотите знать, почему это называется Stack Smash. Когда вы вызывали функцию, массив которой был создан в C, генерировали фрейм для всех ваших локальных переменных, аргументы функции и адрес возврата для функции. Этот кадр был сделан в стеке и известен как кадр стека; звучит достаточно справедливо. Предполагается, что этот кадр стека принадлежит только этой функции и имеет границы от других кадров стека вокруг него; если это может изменить другие кадры стека, последствия могут быть ужасными. Это разрушило бы всю идею «функции имеют свою область видимости». Поэтому, поскольку ваш массив является локальной переменной, он был помещен в этот кадр стека, и когда вы поместили в него слишком много информации, вы писали, просто продолжали писать, пока не достигли границы кадра стека, а затем продолжили, C будет позволь тебе сделать это. Он устанавливает границы и позволяет вам нарушать их по желанию. Этот выход за пределы фрейма называется «разбиванием» стека, потому что вы перебрали другие важные данные. Разрушение стека уничтожает данные стека, записывая туда, куда не следует.

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

Backtrace сообщает вам, какой код был запущен непосредственно перед тем, как произошел сбой; а именно ваша программа, которая вызвала код libc в массиве, который вы переполнили.

Карта памяти показывает, какие части памяти были выделены для чего, например, где вы программируете, где находятся библиотеки, где они называются, где находится куча и где находится стек. Он также дал вам разрешения для этих областей памяти rwxp (чтение, запись, исполняемый файл, PROC_STACK), хотя я не уверен насчет бита PROC_STACK.

По сути, если вы не знаете отображения вашей программы в памяти, это бесполезная информация. Вы также можете использовать свой отладчик, который гораздо полезнее. Это говорит вам о нескольких вещах:

  1. Ваша программа сломалась в libc, что может означать множество вещей.
  2. Вы разбили стек своим кодом.

Я предполагаю, что вы знаете, что ваш массив был инициализирован в кадре стека для вызывающей его функции, и поэтому, когда вы выдавили слишком много значений, вы вышли из кадра и разбили стек.

Надеюсь, это поможет. Если вы хотите узнать больше, просто спросите.

2 голосов
/ 26 апреля 2009

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

Возьмите адрес, по которому написано, что ваша программа потерпела крах (0x804845f), вычтите его из базового адреса сегмента .text вашей программы (0x08048000) и найдите полученное смещение в файле .map для вашей программы.

Если у вас нет файла .map, отредактируйте ваш Makefile, чтобы передать опцию компоновщика, которая позволяет генерировать файл карты (который зависит от того, какой компилятор / компоновщик вы используете). Вот как это сделать для GCC: -Wl,-Map,output.map.

Вы также можете искать адреса символов с помощью отладчика.

1 голос
/ 26 апреля 2009

Похоже, вы не можете (по какой-то причине) опубликовать свой код. Итак, вот код, который будет запускать то же поведение. Вы можете использовать это, чтобы помочь определить, где вы идете неправильно в вашей собственной программе:

#include <stdio.h>

/* Feel free to edit this snippet, I wrote it in a hurry and it smells
 * like feet -- Tinkertim */

int main(void)
{
        char buff[10];
        unsigned int i;
        int n;

        printf("Stack protector complains in ");

        for (i = 0, n = 10 * sizeof(buff); i < n; i++, n--) {
                buff[i] = 'c';
                printf("%d, ", n);
        }

        /* This should not be reached if the stack protector is
         * enabled */

        printf("\nLook ma, no stack protector!\n");

        return 0;
}

Это отключает мою защиту стека (gcc / Linux), когда я пытаюсь записать в 2 раза больше положительного эффекта [] или 20. Я понятия не имею, насколько похожи различные защитники стека в других системах.

То, что все сказали вам до сих пор, на 100% точно. Я даю этот ответ в качестве дополнения, чтобы проиллюстрировать как это происходит с очень коротким примером.

Скомпилируйте с помощью gcc -Wall -o smash smash.c .. так как вы будете использовать C (простите за каламбур), язык позволит вам нарушить все правила. Это позволит вам совершить убийство, но не даст вам сойти с рук (в большинстве случаев).

Попробуйте скомпилировать его (снова), но добавьте флаг компилятора -fno-stack-protector, чтобы увидеть неопределенное поведение, вызванное переполнением.

ПРИМЕЧАНИЯ:

  • это не означает, что отключение вашей защиты стека является решением вашей проблемы:)
  • Защитники стека не защищают от переполнения, они просто защищают стек, между ними есть большая разница.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...