> man operating_systems
WYOS - Выпуск №12
Формат PE
на Среда, 30 Июнь 2004, 22:54
добавил: commrade список авторов печатать элемент контента создать pdf-файл  элемент контента
категория Статьи > Write Your Own OS
комментарии: 0
просмотров: 794

Разборки формата Portable Executable - часть первая.

Напиши свою ОС! #12
Здравствуйте, уважаемые подписчики!

Привет everybody's! И вот с вами снова ваш...commrade!? Так уж получилось, что этот выпуск для вас напишу я. Roman скоро должен снова появится. Ждем его с нетерпением на страницах нашей рассылки. В этом выпуске пойдет речь о формате исполняемых файлов PE. Итак он сказал поехали!!!

Вступление
Следует отметить, что формат файла слизан с аналогичного в Unix системах, кроме того, Microsoft опять пошли на изменение форматов и теперь вы можете так же лицезреть COFF формат OBJ файлов, который весьма похож на PE (собственно говоря это почти одно и то же . Добавлю, что с новым форматом объектных модулей работает только Microsoft (вполне естественно, учитывая, что они его предложили). Данный формат файлов используется начиная с Windows'95 и заканчивая , последней на сегоднишний день ОС семейства Windows, Windows Server 2003. Поговаривают, что даже на Windows 3.1 при наличии Win32s можно запустить файлы этого формата. Но как это не парадоксально данный формат получил наибольшее распространениетак как является стандартом де факто ОС Windows.

Структура файла
Начинается стандартный PE-файл с программы-заглушки, которая выводит на эран следующее сообщение: "This is programm can not be run in the DOS mode.", которая раполгается с 00h по 40h как минимум. На начало заголовка PE-файла указывает "Offset to PE Header", который распологается по адресу 3Ch. Сам же PE-файл условно можно раделить на три части: заголовок, таблица писаний секций PE-файла и собственно сами секции PE-файла. Вот об этих трех разделах и пойдет дальше речь, а чуть ниже данного текста вы можете видеть примерную стуктуру стандартного exe-файла PE-формата.

<table border='1' bgcolor='#FFFFB3'>
<caption align='right'><b>Структура исполняемого файла формата PE</b></caption>
<tr>
<td><b>DOS 2.0 Compatible EXE Header</b> Заголовок совместимый с DOS.</td>
</tr>
<tr>
<td>Зарезервировано</td>
</tr>
<tr>
<td><b>OEM Identifier & OEM Info. </b>Информация о программе.</td>
</tr>
<tr>
<td><b>Offset to PE Header. </b>Смещение указывающее на начало заголовка PE-файла.</td>
</tr>
<tr>
<td><b>DOS 2.0 Stub Program & Relocation Information. </b>На это поле указывает ReloOfs заголовка DOS 2 Header, соответственно его значение должно быть >=40h иначе такой файл как кандидат в PE рассматриваться вообще не будет.
Но на самом деле загрузчику безразлично фактическое их положение. </td>
</tr>
<tr>
<td>Зарезервировано</td>
</tr>
<tr>
<td><b>PE Header(aligned on 8-byte boundary). </b>Заголовок PE файла и, другими словами, начинается сама 32-битная программа.</td>
</tr>
<tr>
<td><b>Object Table. </b>Таблица описаний секций файла.</td>
</tr>
<tr>
<td><b>Image Pages: import info, export info, fixup info, resource info, debug info. </b>
Остальная часть запускаемого файла...</td>
</tr>
</table>

Заголовок PE-файла
Заголовок PE-файла начинается с четырехбайтовойсигнатуры 50 45 00 00h, что соответствует строке “PE” с последующими двумя байтами нулей. Заголовок PE-файла можно разбить на следующие части:

<ul>
<li>сигнатура PE-файла (Signature stamp);</li>
<li>основной заголовок PE-файла (PE header);</li>
<li>дополнительный заголовок PE-файла (PE optional header).</li>
</ul>

Сигнатура
Текущее значение сигнатуры стандартного PE-файла - PE/0/0. За символом PE обязательно должны идти два нуля.
Основной заголовок PE-файла
Основной заголовок содержит общую информацию об исполняемом приложении. Структура основного заголовка представлена ниже в таблице.

<table border='1' bgcolor='#FFFFB3'>
<caption align='right'><b>Структура основного заголовка файла формата PE</b></caption>
<tr>
<td width='17%'><div align='center'><strong>Смещение от начала </strong></div></td>
<td width='15%'><div align='center'><strong>Размер, в </strong></div></td>
<td width='68%'><div align='center'><strong></strong></div></td>
</tr>
<tr>
<td><div align='center'>00h</div></td>
<td><div align='center'>2</div></td>
<td>Тип компьютера, для которого создавалась программа. Некоторые возможные значения:<br>
<ul>
<li>0000h — неизвестный тип компьютерной платформы;</li>
<li>014ch — Intel i80x86;</li>
<li>0160h 0162h, 166, 168 — MIPS;</li>
<li>0184h — DEC Alpha AXP;</li>
<li>01f0h — Power PC;</li>
<li>0268h — Motorola 68000.</li>
</ul>
Эти константы определены во включаемом файле winnt.h (Visual C++). Система использует их для организации правильного обращения с </td>
</tr>
<tr>
<td><div align='center'>02h</div></td>
<td><div align='center'>2</div></td>
<td>Количество секций в PE-</td>
</tr>
<tr>
<td><div align='center'>04h</div></td>
<td><div align='center'>4</div></td>
<td>Время создания файла. Отсчет времени производится в секундах, прошедших с 16:00 31.12.69.</td>
</tr>
<tr>
<td><div align='center'>08h</div></td>
<td><div align='center'>4</div></td>
<td></td>
</tr>
<tr>
<td><div align='center'>0Ch</div></td>
<td><div align='center'>4</div></td>
<td></td>
</tr>
<tr>
<td><div align='center'>10h</div></td>
<td><div align='center'>2</div></td>
<td>Размер дополнительногозаголовка PE-файла (PE optional header). Его размер обычно 224 байта.</td>
</tr>
<tr>
<td><div align='center'>12h</div></td>
<td><div align='center'>2</div></td>
<td>Информационные флаги:
<ul>
<li>0001h — информация о перемещении удалена из файла;
<li>0002h — файл представляет собой исполняемое отображение, то есть не имеет неразрешенных внешних ссылок;</li>
<li>0004h — информация о номерах строк удалена из файла;</li>
<li>0008h — локальные символы удалены из файла;</li>
<li>0080h — расположение байт в машинном слове обратное, то есть соответствует принципу “младший байт по младшему адресу”;</li>
<li>0100h — размер машинного слова 32 бита;</li>
<li>0200h — отладочная информация удалена из исполняемого файла в файл .dbg;</li>
<li>1000h — системный файл;</li>
<li>2000h —dll-библиотека;</li>
</ul>
и др. Полный перечень флагов приведен во включаемом файле winnt.h (Visual C++)</td>
</tr>
</table>

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

<table border='1' bgcolor='#FFFFB3'>
<caption align='right'><b>Структура дополнительногозаголовка файла формата PE</b></caption>
<tr>
<td width='17%'><div align='center'><strong>Смещение от начала доп. </strong></div></td>
<td width='15%'><div align='center'><strong>Размер, в </strong></div></td>
<td width='68%'><div align='center'><strong></strong></div></td>
</tr>
<tr>
<td>00h</td>
<td>2 </td>
<td> Сигнатура, определяющая состояние PE-файла. Возможные значения:
<ul>
<li>0107h — отображение постоянного запоминающего устройства;</li>
<li>010bh — обычный исполняемый </li>
</ul>
</td>
</tr>
<tr>
<td>02h </td>
<td>2</td>
<td>Версия компоновщика, создавшего исполняемый </td>
</tr>
<tr>
<td>04h </td>
<td>4</td>
<td>Размер секции кода (.text) в </td>
</tr>
<tr>
<td>08h</td>
<td>4</td>
<td>Размер секции инициализированых </td>
</tr>
<tr>
<td>0ch</td>
<td>4 </td>
<td>Размер секции неинициализировнных </td>
</tr>
<tr>
<td>10h </td>
<td>4</td>
<td>Адрес (ОАП), с которого начинается выполнение программы модуля. Он находится в секции .text</td>
</tr>
<tr>
<td>14h </td>
<td>4 </td>
<td>ОАП, с которого начинаются программные секции PE-файла. Если файл был создан компоновщиком Microsoft, то
программная секция начинается с адреса 1000h. Компоновщик Borland (Inprise) размещает секцию кода с ОАП 10000h</td>
</tr>
<tr>
<td>18h</td>
<td>4</td>
<td>ОАП, с которого начинаются секции данных PE-файла. Обычно они расположены за секциями кода. Все объекты PE-файла, в том числе секции кода и данных
выравниваются на кратную границу: компоновщик Microsoft выравнивает объекты на границу, кратную 4 Кбайт, компоновщик Borland — на границу 64 </td>
</tr>
<tr>
<td>1Сh</td>
<td>4 </td>
<td>Адрес оперативной памяти, куда предполагается загрузка файла. Этот адрес формирует компоновщик. Если файл действительно загружается по этому адресу, то загрузчику
не нужно делать больше никаких настроек, поэтому процесс загрузки происходит быстрее. Если загрузчик не может раз-местить файл по указанному адресу, то он вынужден
производить настройку </td>
</tr>
<tr>
<td>20h</td>
<td>4</td>
<td>Значение выравнивания для секции. Каждая секция в PE-файле выравнивается на границу, численное значение
которой кратно величине, указанной в данном поле (см. также описание поля 0018h)</td>
</tr>
<tr>
<td>24h </td>
<td>4</td>
<td>Значение кратности, в соответствии с которым выравниваются данные в PE-файле. Смысл этого поля аналогичен полю в NE-файле 0032h (см. табл. 3)</td>
</tr>
<tr>
<td>28h</td>
<td>4</td>
<td>Номер самой старой версии (модификации) операционной системы, в среде которой может работать данный файл (обычно 1.0)</td>
</tr>
<tr>
<td>2ch </td>
<td>4</td>
<td>Определяется пользователем с помощью ключа компонов-щика /VERSION:n.m (для link.exe (MASM)) или /Vn.m (для tlink32.exe (TASM)). Значения n и m заносятся в два слова этого поля</td>
</tr>
<tr>
<td>30h</td>
<td>4</td>
<td>Номера самой старой версии и (модификации) операционной системы Windows NT, в среде которой может работать данный файл (обычно 4.0)</td>
</tr>
<tr>
<td>34h </td>
<td>4</td>
<td>0</td>
</tr>
<tr>
<td>38h</td>
<td>4</td>
<td>Размер PE-файла, выровненный на ближайшую границу </td>
</tr>
<tr>
<td>3Сh</td>
<td>4</td>
<td> Общий размер всех заголовков в PE-файле, включая заголовок MS-DOS, PE-заголовок, дополнительный PE-заголовок и заголовки PE-</td>
</tr>
<tr>
<td>40h</td>
<td>4</td>
<td>Для исполняемых файлов поле равно 0. Для файлов dll-библиотек поле содержит контрольную сумму (crc)</td>
</tr>
<tr>
<td>44h</td>
<td>2</td>
<td>Тип пользовательскоо интерфейса, используемого PE-файлом:
<ul>
<li>0000h — неизвестная подсистема;</li>
<li>0001h — подсистема не требуется (драйвер устройства);</li>
<li>0002h — Windows GUI;</li>
<li>0003h — консольное приложение Windows;</li>
<li>0005h — OS/2;</li>
<li>0007h — Posix</li>
</ul>
</td>
</tr>
<tr>
<td>46h </td>
<td>2</td>
<td>0</td>
</tr>
<tr>
<td>48h</td>
<td>4</td>
<td>Потребный объем памяти для </td>
</tr>
<tr>
<td>4ch</td>
<td>4</td>
<td>Выделяемое количество памяти для </td>
</tr>
<tr>
<td>50h</td>
<td>4</td>
<td>Потребный объем памяти для локальной </td>
</tr>
<tr>
<td>54h</td>
<td>4</td>
<td>Выделяемое количество памяти для локальной </td>
</tr>
<tr>
<td>58h</td>
<td>4</td>
<td>0</td>
</tr>
<tr>
<td>5Сh </td>
<td>4</td>
<td>Количество элементов массива структур, описывающих местоположение и размер некоторых значимых таблиц и областей исполняемого файла. Значение обычно равно 10h</td>
</tr>
<tr>
<td>60h</td>
<td>10h*2*4</td>
<td>Массив структур, каждая из которых состоит из двух полей (размерность каждого поля dword): ОАП расположения данных в PE-файле; размер данных.
Реальное наполнение имеют первые 12 структур в данном массиве. Их перечень можно посмотреть во включаемом файле winnt.h (Visual C++). Они описывают расположение следующих данных в PE-файле:
<ul>
<li>0 — таблица экспортируемых функций;</li>
<li>1 — таблица импортируемых функций;</li>
<li>2 — таблица ресурсов;</li>
<li>3 — таблица исключений;</li>
<li>4 — таблица безопасности;</li>
<li>5 — таблица настройки;</li>
<li>6 — таблица отладки;</li>
<li>7 — строки описания;</li>
<li>8 — характеристика скорости компьютера, измеряемая в MIPS (million of instructions per second — миллионов инструкций в секунду);</li>
<li>9 — область TLS (Thread Local Storage, локальная память цепочки);</li>
<li>10 — область таблицы конфигурации;</li>
<li>11 — таблица адресов импорта (Bound Import Directory in headers)</li>
</ul>
</td>
</tr>
</table>

Таблица секций PE-файла
В PE-файле в виде секции оформляется любой объект, а не только данные или код. Информация о всех секциях PE-файла хранится в таблице секций. Таблица секций располагается сразу после заголовков PE-файла. Количество секций определяется по значению поля в начале основного заголовка 2h. Таблица секций состоит из структур размером по 40 байт каждая. Структуры детально описывают соответствующие секции. Поля, составляющие структуру таблицы секций, представлены в таблице.

<table border='1' bgcolor='#FFFFB3'>
<caption align='right'><b>Содержимое структуры в таблице </b></caption>
<tr>
<td width='17%'><div align='center'><strong></strong></div></td>
<td width='15%'><div align='center'><strong>Размер, в </strong></div></td>
<td width='68%'><div align='center'><strong></strong></div></td>
</tr>
<tr>
<td>00h</td>
<td>8 </td>
<td>Имя секции (если имя меньше 8 байт, то оно дополнено
справа нулевыми байтами)</td>
</tr>
<tr>
<td>08h</td>
<td>4 </td>
<td>Размер секции (потребное количество памяти)</td>
</tr>
<tr>
<td>0Ch</td>
<td>4 </td>
<td>ОАП, по которому загрузчик должен загрузить секцию (см. также поле +14h)</td>
</tr>
<tr>
<td>10h</td>
<td>4 </td>
<td>Размер секции, выровненный на ближайшую (в большую сторону) границу, в соответствии с размером выравнивания (см. поля +20h и +24h )</td>
</tr>
<tr>
<td>14h</td>
<td>4 </td>
<td>ОАП в PE-файле, где находятся данные для секции. Это поле совместно с полем +0ch необходимо для того, что-бы позволить программисту самому управлять загрузкой PE-</td>
</tr>
<tr>
<td>18h</td>
<td>12 </td>
<td>0</td>
</tr>
<tr>
<td>24h</td>
<td>4 </td>
<td>Флаги, характеризующие атрибуты секции </td>
</tr>
</table>
<p>В следующей таблице представлены значения флагов в описании секции.</p>
<table border='1' bgcolor='#FFFFB3'>
<caption align='right'><b>Значения флагов в описании </b></caption>
<tr>
<td width='17%'><div align='center'><strong></strong></div></td>
<td width='15%'><div align='center'><strong>Значение (если бит установлен)</strong></div></td>
</tr>
<tr>
<td>00000020h </td>
<td>Секция содержит программный </td>
</tr>
<tr>
<td>00000040h </td>
<td>Секция содержит инициализированые </td>
</tr>
<tr>
<td>00000080h</td>
<td> Секция содержит неинициализировнные </td>
</tr>
<tr>
<td>00000200h</td>
<td> Используется компиля</td>
</tr>
<tr>
<td>00000800h </td>
<td>Используется компиля</td>
</tr>
<tr>
<td>04000000h</td>
<td> Секция не может кэшироваться</td>
</tr>
<tr>
<td>08000000h</td>
<td> Секция не страничной </td>
</tr>
<tr>
<td>20000000h</td>
<td> Секция является исполняемой (см. флаг 00000020h)</td>
</tr>
<tr>
<td>40000000h</td>
<td> Секция только для чтения</td>
</tr>
<tr>
<td>80000000h</td>
<td> Секция может использоваться для </td>
</tr>
</table>


продолжение следует.......


Комментарии доступны только авторизованным пользователям, авторизуйтесь или зарегистрируйтесь на сайте здесь

© OSRC.info, 2004-2010.
Авторские права на любые материалы, авторы которых явно указаны, принадлежат их авторам. По вопросам публикации таких материалов обращайтесь к авторам.
Авторские права на любые другие материалы принадлежат OSRC.info.
Сайт является помещением библиотеки. Копирование, сохранение на жестком диске или иной способ сохранения произведений осуществляются пользователями на свой риск.
При использовании материалов сайта ссылка на OSRC.info обязательна.