П О Р Т А Л                            
С Е Т Е В Ы Х                          
П Р О Е К Т О В                        
  
Поиск по сайту:
                                                 
Главная

О проекте

Web-мастеру
     HTML & JavaScript
     SSI
     Perl
     PHP
     XML & XSLT
     Unix Shell

MySQL

Безопасность

Хостинг

Другое








Самое читаемое:

Учебник PHP - "Для Чайника".
Просмотров 4098 раз(а).

Иллюстрированный самоучитель по созданию сайтов.
Просмотров 6759 раз(а).

Учебник HTML.
Просмотров 3720 раз(а).

Руководство по PHP5.
Просмотров 5993 раз(а).

Хостинг через призму DNS.
Просмотров 4815 раз(а).

Подборка текстов стандартных документов.
Просмотров 56246 раз(а).

Учебник PHP - Самоучитель
Просмотров 3706 раз(а).

Документация на MySQL (учебник & справочное руководство)
Просмотров 8346 раз(а).

Внешние атаки...
Просмотров 4566 раз(а).

Учебник PHP.
Просмотров 3175 раз(а).

SSI в примерах.
Просмотров 176 раз(а).






 
 
| Добавить в избранное | Сделать стартовой Project.Net.Ru | Помощь





Стек и printf()

Прогулка по стеку

Следующая программа будет нашим проводником на протяжении этого раздела и поможет нам понять взаимосвязь стека и printf():

/* stack.c */
 1: #include <stdio.h>
 2:
 3: int
 4  main(int argc, char **argv)
 5: {
 6:   int i = 1;
 7:   char buffer[64];
 8:   char tmp[] = "\x01\x02\x03";
 9:
10:   snprintf(buffer, sizeof buffer, argv[1]);
11:   buffer[sizeof (buffer) - 1] = 0;
12:   printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
13:   printf ("i = %d (%p)\n", i, &i);
14: }
Данная программа просто копирует аргумент в символьный массив buffer . Мы заботимся о том, чтобы не допустить переполнения некоторых важных данных (атака при помощи строк форматирования более аккуратная чем переполнения буфера ;-)
>>gcc stack.c -o stack
>>./stack toto
buffer : [toto] (4)
i = 1 (bffff674)
Она работает так как мы и ожидали :) Перед тем как продолжить, посмотрим, что происходит с точки зрения стека при вызове snprintf() в строке 8.
Рис. 1 : стек в начале выполнения snprintf()
snprintf()

Рисунок 1 изображает состояние стека в момент, когда программа заходит в функцию snprintf()(мы увидим, что это не так ... однако нам это нужно всего лишь за тем, чтобы дать вам представление, что происходит). Нам не интересен регистр %esp. Он где-то ниже регистра %ebp. Как мы видели в предыдущей статье, первые два значения, расположенные в %ebp и %ebp+4 содержат соответствующие резервные копии регистров %ebp и %eip. Далее идут аргументы функции snprintf():

  1. адрес назначения;
  2. число сиволов для копирования;
  3. адрес строки форматирования argv[1], которая также выполняет функцию данных.
И наконец, стек завершается массивом 4 символов tmp, 64 байтами переменной buffer и целой переменной i.

Строка argv[1] используется одновременно и как строка форматирования и как данные. Согласно обычному порядку подпрограммы snprintf(), argv[1] выступает взамен строки форматирования. Так как вы можете использовать строку форматирования без директив формата (просто текст), все нормально :)

Что получается, если argv[1] также содержит и директивы форматирования? Обычно, snprintf() интерпретирует их так, какие они есть ... и нет причины, почему она будет вести себя по другому! Но здесь, вы можете удивиться, какие аргументы будут использованы в качестве данных для форматирования выходной строки? Фактически, snprintf() забирает данные из стека! Вы можете увидеть это при помощи нашей программы stack:

>>./stack "123 %x"
buffer : [123 30201] (9)
i = 1 (bffff674)

Сначала, строка "123 " копируется в buffer. Директива %x требует snprintf() перевести первое значение в шеснадцатиричный вид. Из рисунка 1 видно, что этот первый аргумент не что иное, как переменная tmp, которая содержит строку \x01\x02\x03\x00. Она отображается как шеснадцатиричное число 0x00030201 в соответствии с прямым порядоком байтов, который принят в процессорах x86.

>>./stack "123 %x %x"
buffer : [123 30201 20333231] (18)
i = 1 (bffff674)

Добавление второго %x дает возможность поднятся выше по стеку. Директива говорит snprintf() искать следующие 4 байта после переменной tmp. Эти 4 байта - фактически 4 первых байта buffer. Однако, buffer содержит строку "123 ", что мы можем увидеть, как шеснадцатиричное число 0x20333231 (0x20=пробел, 0x31='1'...). То есть, для каждого %x, snprintf() "прыгает" на 4 байта дальше в buffer (4 потому что unsigned int занимает 4 байта на процессоре x86). Эта переменная выступает как двойной агент, так как:

  1. пишет в буфер назначения;
  2. считывает данные для формата.
Мы можем "лезть вверх" по стеку до тех пор, пока наш буфер содержит байты:
>>./stack "%#010x %#010x %#010x %#010x %#010x %#010x"
buffer : [0x00030201 0x30307830 0x32303330 0x30203130 0x33303378
         0x333837] (63)
i = 1 (bffff654)

Назад | Содержание | Вперед



Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
 





Copyright © 2005-2016 Project.Net.Ru