EreTIk's Box » Заметки о WinDbg » Создание PE-файла по загруженному в память образу: расширение к WinDbg

Download KdExtMod

Копаясь в одном интересном boot-драйвере, который успешно скрывает информацию о себе, я довольно быстро поймал его загрузку, установив точку останова в nt!IopInitializeBuiltinDriver(...). Но загруженный образ на отлаживаемой машине, учитывая возможности дизассемблера WinDbg, мне не совсем походил. Конечно, есть команда .writemem, которая пишет дамп памяти в файл. Но после этого пришлось бы собирать из дампа нормальный PE-файл. Поэтому, посидев вечерок с чашкой кофе и трубкой, я написал расширение в WinDbg: KdExtMod.dll. Пока это расширение включает в себя только одну полезную функцию и help, но в дальнейшем я буду его развивать другими функциями работы с загруженными модулями.


Функция !pedump: воссоздание PE-файла по загруженному и развернутому в памяти образу. Формат вызова:

!pedump Image PeFileName
  • Image - Адрес начала модуля или имя модуля.
  • PeFileName - имя выходного PE-файла. Если файл с указанным именем существует, то он будет перезаписан.

Первый параметр трактуется следующим образом: пытаемся найти модуль с указанным именем, если нашли – дампим его. Иначе пытаемся рассчитать выражение и считаем, что результат – адрес начала целевого образа.


Алгоритм воссоздания PE-файла


Документов, описывающих формат PE-файла немалое количество. Поэтому я не буду его описывать, но если вы хотите освежить память (или никогда не работали с PE), то предлагаю скачать MS’овский документ Microsoft Portable Executable and Common Object File Format Specification.


Общая схема работы показана на следующем рисунке:


Dump PE-File


Часть рисунка, условно помеченная как "Mirror" Copy переноситься в файл прямым дампом. В эту часть входят данные:

  • Заголовок MZ-DOS (IMAGE_DOS_HEADER)
  • Stub-программа: память между концом заголовка и до PE-сигнатуры файла
  • PE-сигнатура (ULONG)
  • Обязательный заголовок (IMAGE_FILE_HEADER)
  • Опциональный заголовок со всеми его директориями данных (IMAGE_OPTIONAL_HEADER). Главное не забывать, что размер хранится в IMAGE_FILE_HEADER.SizeOfOptionalHeader
  • Заголовки секций. Размер этой области - ( IMAGE_FILE_HEADER.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) )
  • Конец заголовка файла: область памяти, расположенная после последнего заголовка секции и до смещения данных первой секции

Для всех этих данных рассчитывается смещение относительно базового адреса образа. Участки памяти записываются в файл по вычисленным смещениям.


После удачного дампа вышеописанных областей, приходит время разбирать и сохранять секции PE-файла(Dump by offsets). Здесь тоже нет ничего сложного: адрес чтения памяти берем из IMAGE_SECTION_HEADER.VirtualAddress, смещение в файле берется из поля IMAGE_SECTION_HEADER.pointerToRawData, а размер берем тот, какой он должен быть в файле - IMAGE_SECTION_HEADER.SizeOfRawData. При этом необходимо учесть следующее: упакованные файлы часто имеют секции, которые полностью состоящие из неинициализированных данных (IMAGE_SECTION_HEADER.pointerToRawData и IMAGE_SECTION_HEADER.SizeOfRawData содержат нули). Такие секции стоит пропустить при воссоздании PE-файла.


Тестируем расширение отладчика: !KdExtMod.pedump


Тестировать будем на exe-файле. Для начала качаем KdExtMod.dll, выбираем из архива необходимую сборку (x32 или x64). Копируем выбранный dll-файл в директорию "%WinDbg%\winxp\". Далее запускаем WinDbg и, например, запускаем на отладку notepad.exe: File->Open Executable. Образ уже развернут, но еще не начал исполнение.


Загружаем библиотеку расширений:

!load KdExtMod

Командой lm определяем адрес загруженного модуля:

start end module name 01000000 01014000 notepad (deferred) 73070000 73097000 WINSPOOL (deferred) 762b0000 762f9000 comdlg32 (deferred)

Делаем 2-а дампа notepad.exe:

!pedump notepad d:\test\notepad_name.exe !pedump 0x01000000 d:\test\notepad_addr.exe

Сперва убеждаемся, что файлы получились идентичны. И запускаем любой из них на исполнение: у меня блокнот замечательно отработал ;)




Скачать KdExtMod.dll с исходным кодом


ΞρεΤΙκ