8(495)909-90-01
8(964)644-46-00
pro@sio.su
Главная
Системы видеонаблюдения
Охранная сигнализация
Пожарная сигнализация
Система пожаротушения
Система контроля удаленного доступа
Оповещение и эвакуация
Контроль периметра
Система домофонии
Парковочные системы
Проектирование слаботочных сетей
Аварийный
контроль
Раздел: Документация

0 ... 84 85 86 87 88 89 90 ... 102

Листинг А.8. Содержимое окна Call Stacks отладчика Microsoft Visual Studio Debugger

teSTCF-DIT! 004C1362O MFC42! 6c2922ae() MFC42! 6c298fc5() MFC42! 6c292976() tf№\ 6c29dcc() MFC42! 6c291cea() №С42! 6c291c73() HFC42! 6c291bfb() №С42! 6c291bba()

Попробуем найти в стеке адреса 6C2922AEh и 6C298FC5h, соответствующие двум последним ступеням исполнения. Нажимаем Alt+б для перехода в окно дамна и, воспользовавшись комбинацией клавиш Ctrl+G в качестве базового адреса отображения, выбираем ESP. Прокручивая окно дамна вниз, мы обнаруживаем оба адреса возврата (в листинге А.9 они выделены рамками).

Листинг А.9. Содержимое стека после раскрутки

C012F488 0012FA64 0012FA64 004012FF <г 0040136F.ret. 8 первый адрес возврата

0012F494 00000Q0C C0000Q64 00403458 <г 30401328:рор esi

0012F4AO FFFFFFFF 0012F4C4 6С291СЕА

0012F4AC 00000019 00000000 6C32FAF0

0012F4B8 0012F4C0 0012FA64 01100059

0D12F4C4 00320774 002F5788 00000000

0012F4DO 00320701 77Е16383 004C1F20

0D12F4DC 00320774 002F5788 00000000

C012F4E8 000003E8 0012FA64 004F8CD8

0012F4F4 0012F4DC 002F5788 0012F560

0Q12F5CC 77F.6ID49 6C2923D8 00403458 <r C04G132C:ret:

0012F5CC 00000111 0£M0(6§9pAE]<-6C29237t:pop cbx/pop ebp/ret ICh

0012F518 C012FA64 0000C3F8 00000000

0012F53S 0012FA64 000003Е8 00000000

00I2F524 0C4012F0 00000000 0000000С

M12F530 00000000 00000000 C012FA64

0012F53C 0СО003Е8 0012F564 ГбС298ТС5]

0012F548 OOOC03E8 00000000 00000000

°°12F554 00000000 000003Е8 0012FA64

Ячейки памяти, лежащие выше адресов возврата, представляют собой значения регистров, сохраненные в стеке при входе в функцию и восстанавливаемые ее завершении. Ячейки памяти, лежащие ниже адресов возврата, оккупи-аны аргументами функции (если, конечно, у функции есть аргументы) или Ия "ИНаллежат локальным переменным материнской функции, если дочер-4 Функция не принимает никаких аргументов.

вращаясь к листингу A.G, отметим, что два двойных слова, лежащие на вер-;ia Кестека, соответствуют машинным командам POP EDI и POP ESI, а следующий umii адрес - 4012FFh — :>то тот самый адрес, управление которому нередает-40136Fh:RET 8. Для продолжения раскрутки стека мы должны ди-г,мблировать код по этому адресу (листинг АЛО).


Листинг А.10. Дизассемблерный листинг праматеринской функции («бабушки»)

004012FA

call

00401350

004012FF

cmp

eax.OFFh

00401302

je

0C40132D

00401304

push

eax

00401305

lea

eax.[esp+8]

00401309

push

405054П

0040130Е

push

eax

C040130F

call

dword ptr ds:[4033B4h]

С0401315

add

esp.OCh

С0401318

lea

ecx.[esp+4]

0040131С

push

0

004013IE

push

0

00401320

push

ecx

00401321

rnov

ecx.esi

00401323

call

00401BC4

00401328

pop

esi

00401329

add

esp.64h

0040132С

ret

Прокручивая экран вниз, мы замечаем инструкцию ADD ESP, 64, закрывающую текущий кадр стека. Еще восемь байт снимает инструкция 40136Fh:RET 8, и четыре байта оттягивает на себя 401328:POP ESI. Таким образом, позиция адреса возврата в стеке равна: currentESP + 64h + 8 + 4 == 70h. Спускаемся на 70h байт ниже и видим:

0012F5G0 77E61D49 6C2923D8 00403458 <- 004С1328:Р0Р ESI/ret:

Первое двойное слово — это значение регистра ESI, который нам предстоит вручную восстановить; второе — адрес возврата из функции. Нажатием Ctrl+G, 0x6C2923D8 мы продолжаем раскручивать стек (листинг АЛ 1).

Листинг А.11. Дизассемблерный листинг прапраматеринской функции

6C2923D8 jrnp 6С29237В

6С292373

mov

eax.ebx

6C29237D

pop

esi

6С29237Е

pop

ebx

6С29237-

pop

ebp

6С292380

ret

ICh

Вот мы и добрались до восстановления регистров! Сместившись на одно двойное слово вправо (оно только что было вытолкнуто из стека командой RET), переходим в окно Registers и восстанавливаем регистры, ESI, EBX, ЕВР, извлекая со храненные значения из стека: 0012F500 77E61D49 6C2923D8 ШШШ «- 6C29237D:pop esi 0012F5CC 00000111 Ш12£МД[6C2922AEJ «-6C29237E:pop ebx/pop ebp/ret ICh

Как вариант можно переместить регистр EIP на адрес 6C29237Dh, а регистр ESP на адрес 12F508h, после чего нажать F5 для продолжения выполнения программы-


Программная часть

271

1д этот прием действительно срабатывает! Причем реанимированная программа уже «ис ругается» на ошибку последнем операции (как это было при восстановлении путем принудительного выхода из функции), а просто со не выполняет. Красота!

ПЕРЕДАЧА УПРАВЛЕНИЯ НА ФУНКЦИЮ ОБРАБОТКИ СООБЩЕНИЙ

Двум предыдущим способам «реанимации» приложений присуши серьезные ограничения и недостатки. При тяжелых разрушениях стека, вызванных атаками типа buffer overfull или же просто алгоритмическими ошибками, содержимое важнейших регистров процессора окажется искажено, и мы уже иссякшем ни совершить откат (стек утерян), пи выйти из текущей функции (EIP «смотрит в космос»). В консольных приложениях и такой ситуации действительно очень мало что можно сделать... Вот GUI —другое дело! Концепция событийно ориентированной архитектуры наделяет всякое оконное приложение определенными серверными функциями. Даже если текущий контекст выполнения необратимо утерян, мы можем передать управление на цикл извлечения ц диспетчеризации сообщений, заставляя программу продолжить обработку действий пользователя.

Классический цикл обработки сообщений выглядит так (листинг А.12).

Листинг А.12. Классический цикл обработки сообщений

while (Getltesage(tasg. MULL. 0. 0)) {

TranslateMessage(Smsg): Dispatch"essage(&msg):

}

Все, что нам нужно, — это передать управление на цикл while, даже не заботясь о настройке кадра стека, поскольку оптимизированные программы (а таковых большинство) адресуют свои локальные переменные не через ЕВР, а непосредственно через сам ESP. Конечно, при обращении к переменной msg, функция «угробит» содержимое стека, лежащее ниже его вершины, но это уже неважно. Правда, при выходе из приложения оно упадет окончательно (ведь вместо адреса возврата из функции обработки сообщений машинная команда RET обнаружит на вершине стека неизвестно что), но это произойдет после сохранения Всех данных и потому никакой угрозы не несет. Исключение составляют приложения, «забывающие» закрыть все открытые файлы и перекладывающие эту Раооту на плечи функции ExitProcess. Что ж! Можно так подправить адрес возврата, чтобы он указывал на ExitProcess!

Давайте создадим простейшее Windows-приложение и поэкспериментируем с Ним. Запустив Microsoft Visual Studio выберем New ► Project ► Win32 Application итам — Typical Hello, World application. Добавим новый пункт меню, а в нем: char *р; *р= о,- и откомпилируем этот проект с отладочной информацией. *Роняем» приложение на пол, запустив отладчик, подгоняем мышь к первой строке цикла обработки сообщений и в появившемся контекстном Меню



0 ... 84 85 86 87 88 89 90 ... 102