Мы будем снова продолжать практиковаться с упражнением PRACTICA41B, но на этот раз в WINDBG, используя MONA вне IDA. Конечно, мы будем использовать тот же исполняемый файл, который уже имеет байты EB FE и поэтому программа зациклена. В любом случае, хорошо держать файл также открытым в ЗАГРУЗЧИКЕ IDA без отладки, чтобы всё было ясно.
Основная идея состоит в том, чтобы увидеть какую информацию мы получаем в обоих случаях, используя WINDBG внутри IDA или используя WINDBG вне IDA, но пользуясь помощью MONA.
В этом случае, IDA в ЗАГРУЗЧИКЕ показывает мне адрес БЕСКОНЕЧНОГО ЦИКЛА на моей машине равном 0xC610A7 и секция кода начинается в SEGMENTS.
Если я делаю вычитание из начала кодовой секции, ЦИКЛ будет находится по смещению 0xA7 байт, а если делаю вычитание из IMAGEBASE равной 0xC60000 ЦИКЛ будет находится по смещению 0x10A7.
Я запускаю скрипт и процесс будет зациклен. Поэтому я открываю WINDBG у которого уже установлена MONA, как мы видели в предыдущих частях.
Когда я присоединяю WINDBG и процесс останавливается, я вижу IMAGEBASE поскольку исполняемый модуль имеет ASLR. С помощью команды LM я увижу список модулей.
Имя, в этом случае, совпадает с тем, которое было указано при компиляции.
Если я добавлю значение 0x10A7 к IMAGEBASE 0xEF0000, то у меня получится адрес 0xEF10A7 где находится инструкция JMP.
Если я хочу, чтобы адреса в IDA совпадали с процессом, который запущен в WINDBG, я иду в следующий пункт.
Я ввожу IMAGEBASE процесса, который запущен в WINDBG. Он был равен 0xEF0000.
Видно, что сейчас адрес соответствует адресу процесса в WINDBG. Очевидно, каждый раз когда я перегружаю процесс, адрес будет меняться и я должен повторить REBASE.
Здесь я вижу инструкцию. Я устанавливаю BP на выполнение с помощью такой команды.
Я установил BP и нажал "G" для запуска процесса. Он останавливается. Как только я загружу MONA я могу пользоваться её командами для работы с кучей.
Мы сравниваем результат с тем, что даёт нам WINDBG. Нет большого различая. MONA просто даёт мне один из ключей шифрования.
Давайте посмотрим, что MONA расскажет нам о чанках (блоках).
Напомним, что в этот момент регистр EAX имел адрес USER блока (без заголовка)
Если мы поищем значение 4588, мы увидим, что в списках значение всегда по этому адресу, который включает в себя заголовок.
Там мы видим, что блок BUSY, размер USER 0x6С и общий размер, который равен 0x78, т.е. 120 десятичных байт. Если мы сделаем то же самое с помощью WINDBG используя команду !HEAP -A 0x00410000.
То увидим, что информация схожа.
Как и раньше в WINDBG мы увидим блок информации.
Размер был умножен на 8, чтобы увидеть сумму.
HEX(0xF * 0x8)
0x78 т.е. 120 десятичных.
В MONA
Как всегда, в позиции 0x50, у нас есть ключи, чтобы расшифровать их. Давайте посмотрим на них.
Один из двух ключей совпадает с тем, который показывает нам MONA.
У нас есть команда в MONA, про которую я не знаю есть ли она в WINDBG.
!py mona heap -t layout -v
Вывод очень длинный, но MONA пытается увидеть, что он использует блок кучи и перечисляет их.
Здесь это наш блок.
Если я посмотрю содержимое любого из них.
0:000> da 00458d27
00458d27 "AMDAPPSDKROOT=C:\Program Files \("…..
Содержимое такое же как и показывает список.
Данные соответствуют. Блок свободен. Это означает, что программа сохранила там информацию, но блок был освобожден для нового использования.
В этом случае нет, но мы должны всегда обращать внимание на выделенные объекты, потому что они имеют VTABLES, которые являются виртуальными таблицами, которые могут быть перезаписаны и могут заставить нас контролировать выполнение программы.
Это пример для Вас, чтобы увидеть как выглядит там ОБЪЕКТ и VFTABLE. Хорошая цель для перезаписи если есть переполнение.
В IDA мы можем видеть байты, которые мы изменили, чтобы установить бесконечный цикл. Их можно увидеть через EDIT→ PATCHED BYTES.
В WINDBG на вкладке MEMORY я перехожу на адрес где находятся байты EB FE и меняю их на 74 18.
Если сейчас я исполняю команду U EIP, я увижу, какое изменение произошло в условном переходе.
Я могу нажать RUN или G и принять скрипт и продолжить работу программы до сбоя. Мы знаем, что PAGE HEAP не помечена как FULL. Таким образом, нет никакой истории, и программа не будет терпеть сбой при записи. Сбой будет только при переходе на выполнение.
Я буду добираться до нужного места, как и раньше, хотя адреса будут разными.
На этот раз появилось имя.
Я посмотрю на кучу с помощью MONA.
0:000> !py mona heap -a
Hold on...
[+] Command used:
!py C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\mona.py heap -a
Peb : 0x7efde000, NtGlobalFlag : 0x00000000
Heaps:
------
0x004f0000 (1 segment(s) : 0x004f0000) * Default process heap [LFH enabled, _LFH_HEAP at 0x004fb348] Encoding key: 0x13f60872
Я нажимаю G и затем клавишу ENTER в скрипте, для того чтобы продолжить выполнение.
Программа перешла, чтобы выполнить код. Давайте посмотрим, что она говорит нам о блоке.
То же самое. Посмотрим на макет.
Команда показывает нам блок полный A и следующий также с A. WINDBG показывает мне следующий блок размером 0x4141. Размер выглядит поврежденным.
Если мы используем -X, WINDBG сообщит нам, поврежден ли блок.
Хорошо. WINDBG даёт нам много информации. MONA немного больше. Она имеет некоторые команды для работы с объектами, которые мы пока не может использовать. Все это будет помогать нам в практики и поможет решить оставленное упражнение из 44 главы. Мы увидим в следующей части.
Автор оригинального текста — Рикардо Нарваха.
Перевод и адаптация на английский язык — IvinsonCLS.
Перевод и адаптация на русский язык — Яша Яшечкин.
Перевод специально для форума системного и низкоуровневого программирования - WASM.IN