Print This Post PE-формат. Часть 2 — Немного практики: выводим информацию о секциях исполняемого файла

Вторник, 2. Август 2011
Раздел: C/C++, Windows, Для новичков, автор:

Тем, кто мало знаком с PE-форматом, или совсем с ним не знаком, наверное, было непросто понять то море информации, которое было излито в моей предыдущей статье, поэтому я решил пока немного отложить изучение экспортов, импортов и прочих служебных таблиц в PE-файлах. В этой статье мы займемся практикой: напишем программку, которая выведет список секций произвольного исполняемого файла и некоторую информацию о них. Впоследствии, когда дойдет дело до написания упаковщика, этим кодом мы воспользуемся, ведь упаковывать мы будем как раз данные секций.


Писать будем на C++. Никаких извратов не будет, поэтому код должен быть понятен, тем более, я его досконально прокомментирую.
Начнем с инклюдов:

Далее - несколько макросов, которые предоставил Крис Касперски в своей статье про формат PE. Мы будем чаще всего использовать ALIGN_UP - макрос для выравнивания числа на заданную границу.

Итак, тело главной функции. В качестве единственного аргумента нашей программе будет передаваться путь к исполняемому файлу для анализа.

Теперь пришла пора открыть файл, имя которого нам передали через консоль.

Как я писал в предыдущей статье, в самом начале файла должна лежать структура IMAGE_DOS_HEADER. Считаем ее и немного проверим.

Теперь необходимо считать структуру IMAGE_NT_HEADERS. Я программу писал исключительно под PE32, хотя сделать ее для PE64 или вообще универсальной труда никакого не составляет. Читать будем, соответственно, структуру IMAGE_NT_HEADERS32 (это 32-разрядная версия IMAGE_NT_HEADERS, они все определены в глубине Windows.h). Сейчас я пропускаю множество необходимых проверок полей заголовка PE-файла (например, не проверяю выравнивания), потому что они сейчас не являются критичными.

Теперь нам необходимо переместиться к таблице секций, которую мы и будем читать, чтобы получить информацию о секциях исполняемого файла. Можно было бы воспользоваться макросом IMAGE_FIRST_SECTION, но я сделал это руками, чтобы было понятнее:

Немного подготовим консоль для удобного вывода информации. Выставим выравнивание текста по левому краю и вывод чисел в 16-ричной системе счисления. std::showbase добавит перед 16-разрядными числами "0x" автоматически.

Теперь начнем читать таблицу секций. Количество секций лежит в IMAGE_NT_HEADERS.FileHeader.NumberOfSections.

Дальше я добавил всевозможные проверки корректности таблицы секций. Разберем их.

Если вам сейчас трудно вспомнить, что это всё такое - виртуальный размер, реальный адрес, выравнивание, то советую вернуться к первой статье и всё повторить.

Пришло время вывести информацию о секции - раз уж она прошла все проверки :)

Вот и все, наша программа готова, и ей можно через консоль скормить любой исполняемый файл (PE32), чтобы получить информацию о его секциях. На первом скриншоте как раз показан вывод этой программы при анализе самой себя, собранной в Visual Studio 2010 в отладочной версии.

Полная версия кода (без комментариев): скачать (txt).

 Обсудить на форуме


Получать обновления на почту:     

Комментариев: 15 к “PE-формат. Часть 2 — Немного практики: выводим информацию о секциях исполняемого файла”

  1. Вам не кажется, что с File Mapping'ом код был бы раз в 5 проще?

    [Ответить]

    dx:

    Ну напишите, включите туда все проверки, которые включил я, потом сравним. Не думаю, что он был бы проще в 5 раз, разве что совсем немного) Да и я писал на C++ же, без винапи.

    [Ответить]

    гроссеншланг:

    нуну, не отмазывайтесь.) можно подумать с++ с потолка узнал о DWORD и IMAGE_NT_HEADERS =)

    [Ответить]

    dx:

    А это не винапи, это структуры обычные. Их можно и без windows.h объявить.


  2. itspeeow :

    Спасибо! Не думал, что найду это именно здесь!

    [Ответить]


  3. Александр :

    Спасибо хороший гайд

    [Ответить]

  4. Если у кого на Win7 не пашет, меняем 0x108 на IMAGE_NT_OPTIONAL_HDR32_MAGIC.

    По крайней мере у меня не работало, покопавшись в MSDN нашел решение проблемы.

    [Ответить]

  5. Еще забыл добавить, для версии x64 используем IMAGE_NT_HEADERS64 вместо IMAGE_NT_HEADERS32. Вроде по все баги которые у меня полезли.

    Спасибо за гайд. =)

    [Ответить]


  6. Игорь :

    http://pastebin.com/index/UU8q1Lwj

    И свой вопрос я еще подробно изложил на форуме:

    http://www.cyberforum.ru/cpp-beginners/thread1126186.html

    по логике при вводе значения 9 в операторе if( x >= 10 ) - возвращаться должно false.

    [Ответить]

    Kaimi:

    При 9 выведется "Less than 10..". И что с того?

    [Ответить]


  7. Cris :

    Как правильно запускать программу?
    Пишу в консоли sections.exe sections.exe, ошибка: Error reading section header

    [Ответить]

    dx:

    Запускаешь вроде правильно. Но не исключено, что в примере есть ошибка, тогда надо разбираться. А каким компилятором собирал пример?

    [Ответить]


  8. Cris :

    Visual C++ 2013.
    В коде, где считывается заголовок секции IMAGE_SECTION_HEADER, закоментировал проверку и стало нормально отрабатывать.

    [Ответить]

    dx:

    Дошли руки проверить. Странно, но у меня всё нормально отрабатывает на бинарнике, собранном в VS2013. Был бы благодарен, если зальёшь куда-нибудь тот бинарник, на котором у тебя не сработало.

    [Ответить]


Оставьте ваш комментарий