Как устроен исполняемый файл(.EXE) Windows. Reverse engineering для самых маленьких(часть 3).

Сегодня, мы изучим под микроскопом структуру исполняемых файлов Windows (Portable EXEcutable, или просто PE).

Portable Executable файл (PE-файл) — это отдельный исполняемый файл с расширением .exe (или .dll), получаемый в процессе сборки (компиляции) программы для выполнения в Windows. В него включены код, ресурсы (иконки и другие данные), библиотеки, данные программы и т.д..

Что бы заглянуть внутрь файла мы будем использовать популярный редактор двоичных файлов или просто HEX-редактор, ориентированный на работу с кодом — Hiew ( простонародье Хью ). За одно получиться руководство к нему )))

Запускаем редактор, выбираем файл который будем использовать. Например этот crack.exe из прошлой статье.

  • Нажимаем F4(Mode).
  • Выбираем режим HEX.

Заголовок.

Структура исполняемого файла состоит из двух частей:

  • Заголовки.
  • Секции.

Заголовки идут в начает файли и содержат всю техническую информацию для запуска файла. Сколько исполняемый код и данные занимают памяти, описание данных которые хранятся в секциях , сколько секций и т.д.

Структура заголовков:

  • DOS заголовок.
  • DOS стаб, небольшая DOS программа.
  • PE заголовок.
  • Таблица секций.

DOS заголовок.

Это заголовок для DOS программы. В полях заголовка хранятся данные для запуска в MS-DOS, если кто-то попытается запустить PE-файл. Не кто не стал переписывать формат из за того что многие уже не знают что это такое. Структура заголовка выглядит так :

  • e_magic;
  • e_cblp;
  • e_cp;
  • e_crlc;
  • e_cparhdr;
  • e_minalloc;
  • e_maxalloc;
  • e_ss;
  • e_sp;
  • e_csum;
  • e_ip;
  • e_cs;
  • e_lfarlc;
  • e_ovno;
  • e_res[4];
  • e_oemid;
  • e_oeminfo;
  • e_res2[10];
  • e_lfanew;

Для нас интересны только два поля: e_magic — двухбайтовое поле хранит в себе специальную сигнатуру. Эта сигнатура нужна, чтобы указать что это действительно исполняемый файл. Вот она — «MZ» (0x4D 0x5A) . Каждый PE-файл обязан начинаться с неё.

Последнее поле e_lfanew — четырёхбайтовое поле хранит в себе смещение до заголовка PE относительно начала файла. Только этот адрес хранится в обратном порядке : B8 00 00 00 —> 00 00 00 B8

Вы можете нажать клавишу F5 и ввести адрес «B8» что бы сразу попасть на заголовок PE

DOS стаб.

Дальше у нас идет область DOS-стаб которая продолжается до PE заголовка. Это код программы который выполниться если мы попытаемся запустить программу в MS-DOS. Она выводит надпись что эта программа не может работать в DOS и закроет ее.

PE — заголовок.

Теперь мы переходим к самому важному для нас месту, PE-заголовок, который на самом деле, состоит из трёх частей: сигнатуры, файлового подзаголовка и дополнительного подзаголовка.

  • Signature
    Это четырёхбайтовое поле содержит сигнатуру, а именно значение 50 45 00 00 (или «PE\x00\x00»). Эта сигнатура указывает на то, что перед нами действительно PE-файл .
  • FileHeader
    Это обязательный подзаголовок PE-заголовка. Он хранит в себе базовые характеристики исполняемого файла.
    • Machine; // Архитектура процессора
    • NumberOfSections; // Кол-во секций
    • TimeDateStamp; // Дата и время создания программы
    • PointerToSymbolTable; // Указатель на таблицу символов
    • NumberOfSymbols; // Число символов в таблицу
    • SizeOfOptionalHeader; // Размер дополнительного заголовка
    • Characteristics; // Характеристика
  • OptionalHeader — это ещё один обязательный подзаголовок PE-файла. В нём хранится необходимая информация для загрузки PE-файла.

Давайте рассмотрим FileHeader более детально:

  • Machine — двухбайтовое поле содержит информацию о характеристике процессора, на котором может быть выполнена данная программа.
    • (0x014c —> 4c 01) — означает, что программа может выполняться на x32.
    • (0x0200 —> 00 02) — означает, что программа может выполняться на процессорах Intel Itanium (Intel x64).
    • (0x8664 —> 64 86) — означает, что программа может выполняться на процессорах AMD64 (x64).
  • NumberOfSections — двухбайтовое поле содержит в себе число секций в PE-файле.
  • TimeDateStamp — четырехбайтовое поле.
  • PointerToSymbolTable — четырехбайтовое поле.
  • NumberOfSymbols — четырехбайтовое поле.
  • SizeOfOptionalHeader — двухбайтовое поле содержащее размер дополнительного заголовка, который идёт сразу за файловым заголовком.
  • Characteristics— данное двухбайтовое поле содержит характеристики PE-файла. Например, является ли это exe-файлом, или dll. Также, тут описано, является ли данная программа x64-битной или x86-битной.

Третий заголовок OptionalHeader — это ещё один обязательный подзаголовок PE-файла. В нём хранится необходимая информация для загрузки PE-файла. Он имеет всего два формата PE32+ (для 64-битных программ) и PE32 (для 32-битных).

  • Magic; Это двухбайтовое поле отвечает за битность программы (x32/x64). Оно может принимать следующие значения:
    • (0B 01) — означает, что это x32 (x86) исполняемый образ.
    • (0B 02) — означает, что это x64 исполняемый образ.
    • (07 01) — означает, что это ROM образ.
  • MajorLinkerVersion;
  • MinorLinkerVersion;
  • SizeOfCode; — четырёхбайтовое поле (смещение 4 байта), обычно помещается в раздел «.text«. Если имеется несколько разделов кода, это сумма всех разделов кода. Должен быть целым числом, кратным FileAlignment, то есть размеру файла.
  • SizeOfInitializedData;
  • SizeOfUninitializedData;
  • AddressOfEntryPoint; — четырёхбайтовое поле (смещение 16 байт) содержит адрес начала кода, точка откуда программа начинает выполняться.
  • BaseOfCode;
  • BaseOfData;
  • ImageBase; — это четырёхбайтовое поле (смещение 28/24 байт) содержит предпочтительный адрес загрузки программы в память.
  • SectionAlignment; — это четырёхбайтовое поле (смещение 32 байта) содержит размер выравнивания блока в памяти. Если блок занимает меньше памяти , то в блок добавиться нулевые байты( 0x00 ) до размера выравнивания.
  • FileAlignment; — это четырёхбайтовое поле (смещение 36 байт) содержит размер выравнивания блока в файле. Да блоки в файле тоже выравниваются на целые числа.
  • MajorOperatingSystemVersion; — в этом двухбайтовом поле содержится необходимая версия Windows.
  • MinorOperatingSystemVersion; — в этом двухбайтовом поле содержится необходимая версия Windows.
  • MajorImageVersion;
  • MinorImageVersion;
  • MajorSubsystemVersion;
  • MinorSubsystemVersion;
  • Win32VersionValue;
  • SizeOfImage; — это четырёхбайтовое поле (смещение 56 байт) содержит размер (в байтах) загруженного исполняемого файла в памяти.
  • SizeOfHeaders; — четырёхбайтовое поле (смещение 60 байт) содержит размер всех заголовков + таблица разделов.
  • CheckSum;
  • Subsystem; — двухбайтовое поле содержащее тип подсистемы (GUI, CLI, Driver, …).
  • DllCharacteristics;
  • SizeOfStackReserve;
  • SizeOfStackCommit;
  • SizeOfHeapReserve;
  • SizeOfHeapCommit;
  • LoaderFlags;
  • NumberOfRvaAndSizes; — данное четырёхбайтовое поле содержит число каталогов в массиве каталогов. По умолчанию равна 16.
  • DataDirectory — это поле на самом деле массив, которая содержит информацию о каталогах. Их число определено в поле NumberOfRvaAndSizes .

Нажав клавишу F8 мы можем посмотреть основные данные заголовка.

Таблица секций.

Перейдём к последнему заголовку. Этот заголовок — таблица, которая содержит различную информацию о секциях. Мы уже знаем, что их количество определено в файловом заголовке в поле NumberOfSections. Проще говоря, это массив с NumberOfSections элементов. Этот массив содержит элементы типа IMAGE_SECTION_HEADER.

Давайте подробно рассмотрим основные поля.

  • Name
    Это поле, размером в 8 байт, содержит имя секции, в ASCII кодировке.
  • VirtualSize
    Это четырёхбайтовое поле содержит размер (в байтах) секции в виртуальной памяти.
  • VirtualAddress
    А это четырёхбайтовое поле уже содержит относительный адрес секции в виртуальной памяти.
  • SizeOfRawData
    Данное четырёхбайтовое поле содержит размер секции в файле.
  • PointerToRawData
    А указатель на эти самые данные, содержаться в этом четырёхбайтовом поле.
  • Characteristics
    Это четырёхбайтовое поле содержит атрибуты секции. Например, права чтения, записи и исполнения (Read Write Execute) (RWE).

По сути, в таблице секций просто зафиксирована информация о секциях.

Вот и всё, мы закончили изучать заголовки. Теперь мы приступаем к изучению секций. По сути, секции являются простыми последовательными блоками данных. Они следуют друг за другом и у них нет определенного формата, так как их характеристики описаны в таблице секций. А вот формат данных, в этих секциях, зависят от типа информации, которая в них хранится. Секции, как я уже сказал можно представить в виде коробок с информацией. Размер каждой секции зафиксирован в таблице секций, поэтому секции должны быть определённого размера, а для этого их дополняют NULL-байтами (00). Вот и всё, что касается секций.

Также, небольшая шпаргалка, для того, чтобы понимать какое назначение носит имя определенного заголовка секции в таблице:

  • .text: Исполняемый код.
  • .data: Инициализированные данные.
  • .bss: Неинициализированные данные.
  • .rdata: Константные (рид-онли) данные.
  • .edata: Дескрипторы экспорта.
  • .idata: Дескрипторы импорта.
  • .reloc: Таблица релокации.
  • .rsrc: Ресурсы.
  • .tls: __declspec(thread) данные.

Также, секциями являются и различные каталоги.

Нажав F8 потом F6 мы сожем посмотреть секции в файле. Выбираем любую нажимаем Enter и попадаем на начало секции.

В статье использовались материалы из статьи : codeby.net/threads/0x01-issleduem-portable-executable-exe-fajl-format-pe-fajla.65415/

Ошибка в тексте? Выделите её и нажмите «Ctrl + Enter»

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *