Часть IV. Отладка, анализ кода программ, драйверы
Вопросы, затронутые в данной части, относятся к категории сложных. Отладка и анализ кода программ невозможен без хорошего знания ассемблера. Однако если Вы дошли до этого места книги, значит Вам по плечу и такой материал.
Глава 1. Структура исполняемых модулей
Исполняемым форматом в Windows является формат PE. Сокращение PE означает
Portable Executable, т.е. переносимый исполняемый формат. Этот формат имеют как ЕХЕ-файлы, так и
динамические библиотеки. Важно, что сейчас фирма Microsoft ввела "новый" формат и для
объектных модулей - это COFF-формат (COFF - Common Object File Format),
который, однако, на поверку оказался, в сущности, все тем же PE-форматом. Заметим в этой связи,
что фирма Borland по-прежнему работает с объектными файлами, имеющими структуру OMF
(Object Module Format). Старый NE-формат (NE - New Executable), используемый старой
операционной системой Windows и рассчитанный на сегментную структуру памяти, ушел в небытие. Кроме
того, есть еще формат VXD-драйверов - LE-формат (Linear Executable, т.е. линейный исполняемый). Этого формата мы коснемся, когда будем говорить о драйверах в операционной системе Windows. Таким образом, данная глава будет посвящена разбору структуры исполняемых РЕ-модулей. Поскольку в состав исполняемого РЕ-модуля входит и DOS-программа (STUB), мы начнем наше рассмотрение со структуры DOS-программ. Наше рассмотрение будет кратким, и мы воспользуемся таблицей из книги [1].
Структура ЕХЕ-программ для MS DOS
Смещение | Длина | Название | Комментарий |
---|---|---|---|
+0 | 2 | MZ | подпись, признак ЕХЕ-программы |
+2 | 2 | PartPag | длина неполной последней страницы |
+4 | 2 | PageCnt | длина в страницах (512 б), включая заголовок и последнюю страницу |
+6 | 2 | ReloCnt | число элементов в таблице перемещения |
+8 | 2 | HdrSize | длина заголовка в параграфах |
+0AН | 2 | MinMem | минимум требуемой памяти за концом программы |
+0CH | 2 | MaxMem | максимум требуемой памяти за концом программы |
+0EН | 2 | ReloSS | сегментный адрес стека |
+10H | 2 | EXESp | значение регистра SP |
+12Н | 2 | ChkSum | контрольная сумма |
+14Н | 2 | ExeIP | значение регистра IP |
+16H | 2 | ReloCS | сегментный адрес кодового сегмента |
+18H | 2 | TablOff | смещение в файле первого элемента таблицы перемещения |
+1АН | 2 | Overlay | номер оверлея, 0 для главного модуля |
* Конец форматированной порции заголовка ** +1СН | |||
** Начало таблицы перемещения (возможно с 1СН) ** +? 4*? смещ. сегмент ... смещ. сегмент |
Рис. 4.1.1. Структура ЕХЕ-программы для MS DOS.
Более подробно разбор заголовка DOS-программы можно найти в [1]. Добавлю только, что сразу за таблицей перемещения начинается исполняемая часть модуля. Таблица же перемещения используется для того, чтобы при загрузке настроить адреса. Но это лишь в том случае, если в программе используются адреса сегментов. В противном случае таблица перемещения не содержит элементов, и исполняемый код начинается сразу за форматированной частью заголовка. Перейдем теперь к общей структуре РЕ-модуля.
I
Общая структура РЕ-модуля. Начало заголовка ЕХЕ-файлов в WIN32 представляет собой небольшую DOS-программу, основное предназначение которой заключается в том, чтобы при запуске в операционной системе MS DOS сделать сообщение о том, что данный модуль не предназначен для работы в MS DOS. Программа LINK.EXE (TLINK32.EXE) устанавливает свой вариант DOS-программы. Однако при желании Вы всегда можете поставить свою программу-заглушку (stub в переводе заглушка).
Рассмотрим общую структуру РЕ-заголовка.
Смещение | Комментарий |
---|---|
00H | Обычный DOS-заголовок. |
1CH | Четыре байта до выравнивания до 20Н байт, т.е. выравнивание до двух параграфов. |
20H | Информация о программе, обычно отсутствующая. |
3CH | Смещение 32-битного РЕ-заголовка. |
40H | Таблица перемещения для программы-заглушки. У стандартных заглушек таблица, разумеется, пуста. Не смотря на это TablOff должен показывать именно сюда. |
40H+?? | Здесь начинается тело самой заглушки, которая начинается за таблицей перемещения. Естественно, в стандартных заглушках нет ничего, кроме сообщения о невозможности запуска программы. Однако заглушка может иметь и весьма разрушительные свойства. |
?? | Здесь начинается собственно PE-заголовок. Сюда показывает содержимое четырех байт по адресу 3CH. Начало должно быть выровнено по 8-байтной границе. |
?? | Таблица описаний секций файлов (Object Table). |
?? | Остальная информация: coff-символы, отладочная информация, таблица импорта и таблица экспорта, ресурсы и т.д. Данный раздел называется Image Pages, т.е. страницы образов. |
Рис. 4.1.2. Общая структура РЕ-заголовка.
00000: 4D 5A 0A 00 02 00 00 00 | 04 00 0F 00 FF FF 00 00 MZ 00010: C0 00 00 00 00 00 00 00 | 40 00 00 00 00 00 00 00 00020: 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00030: 00 00 00 00 00 00 00 00 | 00 00 00 00 80 00 00 00 00040: B4 09 BA 10 00 OE IF CD | 21 B8 01 4C CD 21 90 90 00050: 54 68 69 73 20 69 73 20 | 61 20 57 69 6E 33 32 20 00060: 70 72 6F 67 72 61 6D 2E | 0D OA 24 00 00 00 00 00 00070: 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00080: 50 45 00 00 4C 01 03 00 | 39 30 00 00 00 00 00 00 PE 00090: 00 00 00 00 E0 00 OE 03 | 0B 01 02 34 00 30 00 00 000A0: 00 10 00 00 00 60 00 00 | 30 96 00 00 00 70 00 00 000B0: 00 A0 00 00 00 00 40 00 | 00 10 00 00 00 02 00 00
Рис. 4.1.3. Фрагмент РЕ-заголовка.
На рис. 4.1.3 показан фрагмент PE-заголовка. Обратите внимание, что по смещению 3CH действительно находится адрес начала основного заголовка (символы PE).
II
В таблице, представленной ниже мы даем описание заголовка РЕ.
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Signature Bytes | Сигнатура. Первые два байта "PE" 4550Н. Еще два байта обязательно должны быть равны нулю. |
04h | WORD | CPU Type | Данное поле указывает на процессор, который следует предпочесть при запуске программы. Вот
возможное значение этого поля: 0000h - неизвестный процессор. 014Ch - i386 014Dh - i486 014Eh - i586 0162h - MIPS Mark I (R2000, R3000) 0163h - MIPS Mark II (R6000) 0166h - MIPS Mark III (R4000) Чаще всего данное поле указывает на процессор 386. |
06h | WORD | Num of Objects | Поле указывает на число реальных входов в Object Table (см. таб. ниже). |
08h | DWORD | Time/Date Stamp | Дата и время, которые устанавливаются при компоновке программы. |
0Ch | DWORD | Pointer to COFF table | Дополнительный указатель, определяющий местонахождение отладочной COFF-таблицы в файлах. Это поле используется только в OBJ-файлах и РЕ-файлах, содержащих отладочную COFF-информацию. |
10h | DWORD | COFF table size | Количество символов в COFF-таблице. |
14h | WORD | NT Header Size | Размер заголовка РЕ-файла, начиная с поля Magic - таким образом, общий размер заголовка РЕ-файла составляет NT Header Size + 18h. |
16h | WORD | Flags | Указывает на предназначение программы. Значение флагов: 0000h - это программа; 0001h - файл не содержит перемещений и таблицы перемещаемых элементов; 0002h - образ в файле можно запускать. Если этот бит не установлен, то это обычно указывает на ошибку, обнаруженную на этапе линковки, или же на то, что код был инкрементально отлинкован (инкрементальная линковка - частичная линковка кода при изменении участка программы, а не тотальная перекомпиляция проекта); 0200h - загружать в память фиксированно. Указывает на то, что программу можно грузить только по адресу, записанному в Image Base, если это невозможно, то такой файл лучше вообще не запускать. 2000h - это библиотека. |
18h | WORD | Magic | Слово-сигнатура, определяющее состояние отображенного файла. Определены следующие значения: 107Н - отображение ПЗУ. 10BH - нормально исполняемое отображение. |
1Ah | BYTE | Link Major | Старший номер версии использовавшегося при создании модуля компоновщика. Десятичный вид. |
1Bh | BYTE | Link Minor | Младший номер версии использовавшегося при создании модуля компоновщика. Десятичный вид. |
1Ch | DWORD | Size of Code | Размер именно программного кода в файле. KERNEL использует это значение для фактического отведения памяти под загружаемую программу. Установка этого значения слишком маленьким приведет к выдаче сообщения о нехватке памяти. Обычно большинство модулей имеют только одну программную секцию .text. |
20h | DWORD | Size of Init Data | Размер секции инициализированных данных, очевидно, не используется в Windows 95, но используется в Windows NT. Назначение аналогично приведенному выше. |
24h | DWORD | Size of UnInit Data | Размер секции неинициализированных данных. Неинициализированные данные обычно содержатся в секции .bss. Данная секция не занимает на диске никакого места, но при загрузке модуля в память загрузчик отводит под нее память. |
28h | DWORD | Entry point RVA | Адрес относительно Image Base, no которому передается управление при запуске программы или адрес инициализации/завершения библиотеки. |
2Ch | DWORD | Base of Code | Адрес секции относительно базового адреса (40000Н), содержащей программный код. Этот адрес обычно равен 1000Н для компоновщика Microsoft и 10000H для компоновщика Borland. |
30h | DWORD | Base of Data | Адрес относительно базового (40000H), с которого начинаются секции данных файла. Секции данных обычно идут последними в памяти, после заголовка РЕ и программных секций. |
34h | DWORD | Image Base | При создании компоновщик помещает сюда адрес, куда будет отображен исполняемый файл в памяти. Если загрузчик отобразит файл именно по этому адресу, то дополнительной настройки не потребуется. |
38h | DWORD | Object align | Выравнивание программных секций. После отображения в память каждая секция будет обязательно начинаться с виртуального адреса, кратного данной величине. |
3Ch | DWORD | File align | В случае РЕ-файла исходные данные, которые входят в состав каждой секции, будут обязательно начинаться с адреса, кратного данной величине. Значение по умолчанию составляет 200Н. |
40h | WORD | OS Major | Старший номер версии операционной системы, необходимый для запуска программы. |
42h | WORD | OS Minor | Младший номер версии операционной системы. |
44h | WORD | USER Major | Пользовательский номер версии, задается пользователем при линковке программы. Старшая часть. |
46h | WORD | USER Minor | Пользовательский номер версии, младшая часть. |
48h | WORD | SubSys Major | Старший номер версии подсистемы. |
4Ah | WORD | SubSys Minor | Младший номер версии подсистемы. Типичное значение версии 4.0, что означает Windows 95. |
4Ch | DWORD | Reserved | Зарезервировано. |
50h | DWORD | Image Size | Представляет общий размер всех частей отображения, находящихся под контролем загрузчика. Эта величина равна размеру области памяти, начиная с базового адреса отображения и заканчивая адресом конца последней секции. Адрес конца секции выровнен на ближайшую верхнюю границу секции. |
54h | DWORD | Header Size | Общий размер всех заголовков: DOS Stub + РЕ Header + Object Table |
58h | DWORD | File CheckSum | Контрольная сумма всего файла. Как и в операционной системе MS DOS, ее никто не контролирует, а программа редактирования связей устанавливает ее в 0. Предполагалось ее рассчитывать как инверсию суммы всех байтов файла. |
5Ch | WORD | Subsystem | Операционная подсистема, необходимая для запуска данного файла. Вот значения этого поля: 1 - подсистема не требуется (NATIVE). 2 - запускается в подсистеме Windows GUI. 3 - запускается в подсистеме Windows character (терминальное или консольное приложение). 5 - запускается в подсистеме OS/2. 7 - запускается в подсистеме Posix. |
5Eh | WORD | DLL Flags | Указывает на специальные потребности при загрузке, начиная с операционной системы NT 3.5. Устарел и не используется. |
60h | DWORD | Stack Reserve Size | Память, требуемая для стека приложения. Память резервируется, но выделяется только Stack Commit Size байтов. Следующая страница является охранной. Когда приложение достигает этой страницы, то она становится доступной, а следующая страница - охранной, и так до достижения нижней границы, после чего Windows 95 убивает программу. |
64h | DWORD | Stack Commit Size | Объем памяти, отводимой для стека немедленно после загрузки. |
68h | DWORD | Heap Reserve Size | Максимально возможный размер локальной кучи. |
6Ch | DWORD | Heap Comit Size | Отводимый размер кучи при загрузке. |
70h | DWORD | Loader Flags | Начиная с Windows NT 3.5 объявлено неиспользуемым, назначение неясно, но в целом связано с поддержкой отладки. |
74h | DWORD | Num of RVA and Sizes | Указывает размер массива VA/Size, который следует ниже, данное поле зарезервирована под будущие расширения формата. В данный момент его значение всегда равно 10h. |
78h | DWORD | Export Table RVA | Относительный адрес (относительно базового адреса) таблицы экспорта. |
7Ch | DWORD | Export Data Size | Размер таблицы экспорта. |
80h | DWORD | Import Table RVA | Относительный адрес (относительно базового адреса) таблицы импорта. |
84h | DWORD | Import Data Size | Размер таблицы импорта. |
88h | DWORD | Resource Table RVA | Относительный адрес (относительно базового адреса) таблицы ресурсов. |
8Ch | DWORD | Resource Data Size | Размер таблицы ресурсов. |
90h | DWORD | Exception Table RVA | Относительный адрес таблицы исключений. |
94h | DWORD | Exception Data Size | Размер таблицы исключений. |
98h | DWORD | Security Table RVA | Адрес таблицы безопасности. По-видимому, не используется. |
9Ch | DWORD | Security Data Size | Размер таблицы безопасности. |
A0h | DWORD | Fix Up's Table RVA | Относительный адрес таблицы настроек. |
A4h | DWORD | Fix Up's Data Size | Размер таблицы настроек. |
A8h | DWORD | Debug Table RVA | Относительный адрес таблицы отладочной информации. |
ACh | DWORD | Debug Data Size | Размер таблицы отладочной информации. |
B0h | DWORD | Image Description RVA | Относительный адрес строки описания модуля. |
B4h | DWORD | Description Data Size | Размер строки описания модуля. |
B8h | DWORD | Machine Specific RVA | Адрес таблицы значений, специфичных для микропроцессора. |
BCh | DWORD | Machine Data Size | Размер таблицы значений, специфичных для микропроцессора. |
C0h | DWORD | TLS RVA | Указатель на локальную область данных цепочек. |
C4h | DWORD | TLS Data Size | Размер области данных цепочек. |
C8h | DWORD | Load Config RVA | Предназначение неизвестно. |
CCh | DWORD | Load Config Data Size | Предназначение неизвестно. |
D0h | 08h | Reserved | Зарезервировано. |
D8h | DWORD | IAT RVA | Используется в NT. В Windows 95, судя по всему, нет. |
DCh | DWORD | IAT Data Size | Размер описанного поля. |
E0h | 08h | Reserved | Зарезервировано. |
E8h | 08h | Reserved | Зарезервировано. |
F0h | 08h | Reserved | Зарезервировано. |
Между заголовком РЕ и данными для секций расположена таблица секций. Вот элемент этой таблицы.
Элемент таблицы секций содержит полную базу данных об одной секции.
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | 08h | Object Name | Имя объекта, остаток заполнен нулями. Если имя объекта имеет длину 8 символов, то
заключительного 0 нет. Вот несколько возможных имен: .text - исполняемый код общего назначения. CODE - исполняемый код, помещаемый компоновщиками фирмы BORLAND. .icode - переходники (jump'ы), помещаемые сюда старой версией TLINK32. .data - инициализированные данные, помещаются компоновщиком фирмы Microsoft. DATA - инициализированные данные, помещаемые сюда компоновщиком TLINK32. .bss - неинициализированные глобальные и статические переменные. .CRT - еще одна секция для хранения инициализированных данных. .rsrc - секция для хранения ресурсов. .idata - секция импорта. .edata - секция экспорта. .reloc - секция настроек. Данная информация может понадобиться загрузчику, если он не сможет загрузить модуль по базовому адресу. .tls - данные для запуска цепочек. .rdata - данная секция в основном содержит отладочную информацию. .debug$s и .debug$t - данные секции есть только в COFF-объектных файлах. Они содержат информацию о символах Code View и их типах. .drective - в данной секции содержится текст программ для компоновки. Данная секция есть только в объектных файлах. Секции, содержащие символ $. Такие секции обрабатываются особым образом. Компоновщик объединяет все секции, имеющие одинаковые символы в имени до символа $. Именем получившейся секции считается то, что стоит перед указанным символом. |
08h | DWORD | Virtual Size | Виртуальный размер секции - именно столько памяти будет отведено под секцию. Если Virtual Size превышает Physical Size, то разница заполняется нулями, так определяются секции неинициализированных данных (Physical Size = 0). |
0Ch | DWORD | Section RVA | Размещение секции в памяти, ее виртуальный адрес относительно Image Base. Позиция каждой секции выровнена на границу Object align (степень 2 от 512 до 256М включительно, по умолчанию 64К), секции упакованы вплотную друг к другу, впрочем, можно это не соблюдать. Для объектных файлов поле не имеет смысла. |
10h | DWORD | Physical Size | Размер секции (ее инициализированной части) в файле кратно полю File align в заголовке РЕ Header, должно быть меньше или равно Virtual Size. Для объектных файлов это поле содержит точный размер секции, сгенерированный компилятором или ассемблером. Другими словами, для объектных файлов оно эквивалентно полю Virtual Size. |
14h | DWORD | Physical Offset | Физическое смещение относительно начала ЕХЕ-файла, выровнено на границу File align поля заголовка РЕ Header. Смещение используется загрузчиком для поиска. |
18h | DWORD | Pointer to Linenumber | Файловое смещение таблицы номеров строк. Используется для объектных файлов. |
1Ch | WORD | Number of Relocations | Количество перемещений в таблице поправок. Используется только для объектных файлов. |
1Eh | WORD | Number of Linenumbers | Количество номеров строк в таблице номеров строк для данной секции. Используется для объектных файлов. |
20h | 08h | Reserved | Зарезервировано для объектных файлов. |
28h | DWORD | Object Flags | Битовые флаги секции: 00000004h - используется для кода с 16-битными смещениями. 00000020h - секция кода. 00000040h - секция инициализированных данных. 00000080h - секция неинициализированных данных. 00000200h - комментарии или любой другой тип информации. 00000400h - оверлейная секция. 00000800h - не будет являться частью образа программы. 00001000h - общие данные. 00500000h - выравнивание по умолчанию, если не указано иное. 02000000h - может быть выгружен из памяти. 04000000h - не кэшируется. 08000000h - не подвергается страничному преобразованию. 10000000h - разделяемый. 20000000h - выполнимый. 40000000h - можно читать. 80000000h - можно писать. |
Страницы образов секций. Здесь мы изучим некоторые секции.
Секция экспорта (.edata). Общая структура
1 | Таблица собственно экспорта | Export Directory Table |
2 | Адресная таблица | Export Address Table |
3 | Таблица указателей на имена | Export Name Table Pointers |
4 | Таблица номеров | Export Ordinal Table |
5 | Таблица самих имен | Export Name Table |
1. Таблица экспорта
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Flags | Зарезервировано, должно быть равно нулю. |
04h | DWORD | Time/Date Stamp | Время и дата создания экспортных данных. |
08h | WORD | Major Version | Старший номер версии таблицы экспорта. Не используется. |
0Ah | DWORD | Minor Version | Младший номер версии таблицы экспорта, также не используется. |
0Ch | DWORD | Name RVA | Относительный адрес строки, указывающей на имя нашей библиотеки. |
10h | DWORD | Ordinal Base | Начальный номер экспорта, для функций, экспортируемых данным модулем. |
14h | DWORD | Num of Functions | Количество функций экспортируемых данным модулем, является числом элементов массива Address Table (см.ниже). |
18h | DWORD | Num of Name Pointers | Число указателей на имена, обычно равно числу функций, но это не так, если у нас есть функции, экспортируемые только по номеру. |
1Ch | DWORD | Address Table RVA | Указатель на таблицу относительных адресов экспортируемых функций. |
20h | DWORD | Name Pointers RVA | Указатель на таблицу указателей на имена экспортируемых функций данного модуля. |
24h | DWORD | Ordinal Table RVA | Указатель на таблицу номеров экспорта, данный массив по индексам параллелен Name Pointers, элементами являются слова. |
2. Таблица адресов экспорта. Эта структура данных содержит адреса экспортируемых функций (их точки входа) в формате DWORD (по 4 байта на элемент). Для доступа к данным используется номер функции с коррекцией на базу номеров (Ordinal Base).
3. Таблица указателей на имена. Данная структура содержит указатели на имена экспортируемых функций, указатели отсортированы в лексическом порядке для обеспечения возможности бинарного поиска. Каждый указатель занимает 4 байта. Имена функций обычно лежат в секции экспорта.
4. Таблица номеров. Данная структура совместно с Name Table Pointers формирует два параллельных массива, разделенных для облегчения к ним доступа индексированием на родные для процессора данные (слова, двойные слова, но не сложные структуры). Данный массив содержит номера экспорта, которые в общем случае являются индексами в Address Table экспорта (за вычетом базы Ordinal Base). Элементами данного массива являются слова (2 байта).
5. Таблица имен экспорта. Эта таблица содержит необязательные (по мнению Microsoft) имена экспортируемых функций. Данный массив используется совместно с Name Table Pointers и Ordinal Table для обеспечения связывания загрузчиком импорта/экспорта по имени. Механизм описывался выше. Каждый элемент являет собой ASCIIZ строку с именем экспортируемой функции. Никто не говорит, что они должны в файле идти друг за другом последовательно, хотя так построено большинство файлов. Надо отметить, что имена экспорта чувствительны к регистру. Отметим особенность загрузчика - при связывании, если адрес функции находится в секции экспорта, на самом деле по указанному адресу лежит строка, переадресующая к другой библиотеке, экспортирующей данную функцию (с указанием библиотеки и самой функции). Это называется - передача экспорта.
Секция импорта (.idata)
Рис. 4.1.4. Вызов импортируемой функции.
Схема вызова импортируемых функций из РЕ-модуля изображена на Рис. 4.1.4, который с некоторыми изменениями взят из книги [2]. Смысл данного рисунка заключается в следующем. При компоновке все вызовы API-функций преобразуются к вызову типа CALL Адрес1. При этом адрес, также как и вызов, находится в секции кода (.text). По адресу же стоит команда JMP DWORD PTR [Адрес2]. [Адрес2] находится в секции .idata (импорта) и содержит двойное слово — адрес функции в динамической библиотеке. Современные компиляторы содержат директивы, позволяющие вместо двух вызовов (CALL и JMP) генерировать один CALL [Адрес2].
Таблица директория импорта
Каталог импорта | Import Directory Table |
Таблица ссылок на имена | LookUp Table |
Таблица имен | Hint-Name Table |
Таблица адресов импорта | Import Address Table |
Формат входа в каталог импорта
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Import LookUp | Содержит ссылку на таблицу относительных адресов (относительно базового адреса), указывающих на соответствующие имена импортируемой функции, или непосредственно номер импортируемого входа. |
04h | DWORD | Time/Date Stamp | Отметка о времени создания, часто содержит ноль. |
08h | DWORD | Forward Chain | Связано с возможностью передачи экспорта в другие библиотеки. Обычно равно 0FFFFFFFFh. |
0Ch | DWORD | Name RVA | Ссылка на библиотеку импорта в виде ASCII строки с нулем на конце. Например, KERNEL32.DLL или USER32.DLL. |
10h | DWORD | Addres Table RVA | Ссылка на таблицу адресов импорта, заполняется системой при связывании. |
Таблица просмотра импорта или таблица имен сервисов. Ссылка из поля Import LookUp на массив, содержащий ссылки на таблицу просмотра импорта. При импортировании по номеру старший бит элемента массива равен 1.
Тип | Содержимое |
---|---|
Word | Номер функции |
Hint | ASCII имя функции |
Таблица адресов импорта. Данная таблица принимает в себя информацию после связывания загрузчиком импорта из внешних библиотек, она завершается нулевым элементом.
Локальная область данных цепочек (потоков)
Локальная область данных цепочек, это специальный, протяженный блок данных. Каждая цепочка получит собственный блок при создании.
Таблица разделов цепочек | TLS Directory Table |
Данные цепочек | TLS Data |
Индексные переменные | Index Variables |
Адреса обратных вызовов | CallBack |
Таблица разделов потоков
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Start Data Block VA | Виртуальный адрес начала блока данных цепочки. |
04h | DWORD | End Data Block VA | Виртуальный адрес конца блока данных цепочки. |
08h | DWORD | Index VA | Виртуальный адрес индексной переменной, используемой для доступа к локальному блоку данных цепочки. |
0Ch | DWORD | CallBack Table VA | Виртуальный адрес таблицы обратных вызовов. Локальные обратные вызовы - массив виртуальных адресов функций, которые будут вызваны загрузчиком после создания цепочки (нити) и после ее завершения. Последний вход имеет нулевое значение и указывает на конец таблицы. |
Секция ресурсов (.rdata)
Ресурсы представляют собой многоуровневое двоичное дерево. Их структура позволяет содержать до 2^31 уровней, однако реально используется только 3: самый верхний есть Type, затем Nam и затем Language (тип, имя, язык). Перемещения по иерархии каталогов ресурсов похожи на перемещения по каталогам жесткого диска. Типичное представление ресурсного участка в файлах:
Каталог ресурсов | Resources Directory Table |
Данные ресурсов | Resources Data |
Каталог ресурсов (Resource Directory Table)
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Flags | Пока не используются, должны быть сброшены в ноль. |
04h | DWORD | Time/Date Stamp | Дата и время создания ресурсов от ресурсного компилятора. |
08h | WORD | Major Version | Старшая часть версии ресурсов. Обычно равно нулю. |
0Ah | WORD | Minor Version | Младшая часть версии ресурсов. Обычно равно нулю. |
0Ch | WORD | Name Entry | Количество входов в таблицу имен (элементов массива) ресурсов. Таблица располагается в самом начале массива входов и содержит строковые имена, ассоциируемые с ресурсами. |
0Eh | WORD | ID_Num Entry | Количество элементов массива, использующих целые ID. |
За каталогом ресурсов сразу следует массив переменной длины, содержащий ресурсные входы. Name Entry содержит число ресурсных входов, имеющих имена (связанные с каждым входом). Имена нечувствительны к регистру и расположены в порядке возрастания. ID_Num Entry определяет число входов имеющих в качестве имени 32-битовый идентификатор. Эти входы так же отсортированы по возрастанию. Данная структура позволяет получать быстрый доступ к ресурсам по имени или по идентификатору, но для отдельно взятого ресурса поддерживается только одна из форм поиска. Что согласуется с синтаксисом .RC и .RES файлов. Каждый вход в таблицу ресурсов имеет следующий формат.
Вход в таблицу ресурсов (Resource Entry Item)
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Name RVA or Res ID | Поле содержит либо идентификатор ресурса, либо указатель на его имя в таблице имен ресурсов. |
04h | DWORD | Data Entry RVA or SubDirectory RVA | Указывает либо на данные, либо на еще одну таблицу входов ресурсов. Старший бит поля, сброшенный в ноль, говорит, что поле указывает на данные. |
Каждый пункт данных (Resource Entry Item) имеет следующий формат:
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Data RVA | Указатель на реально расположенные данные относительно Image Base. |
04h | DWORD | Size | Размер ресурсных данных. |
08h | DWORD | CodePage | Кодовая страница. |
0Ch | DWORD | Reserved | He используется и устанавливается в ноль. |
Таблица настроек адресов
Если исполняемый файл не может быть отображен по адресу, который указал компоновщик, то загрузчик производит настройку модуля, используя данные из секции .reloc. Поправки сводятся к перечню тех мест в отображенном файле, где нужно прибавить некоторую величину.
Формирование данных базовых поправок выглядит следующим образом. Поправки упаковываются сериями смежных кусков различной длины. Каждый кусок описывает поправки для одной четырехбайтовой страницы отображения и начинается со следующей структуры:
Смещение | Длина поля | Название поля | Описание поля |
---|---|---|---|
00h | DWORD | Page RVA | Относительный адрес страницы применения. |
04h | DWORD | Block Size | Размер блока настроек (с заголовком). Эта величина используется для вычисления количества настроек. |
08h | WORD | TypeOffset Record | Массив записей настроек, их переменное количество. |
Для наложения настройки необходимо вычислить 32-битную разницу ("Дельта") между желаемой базой загрузки и действительной. Если образ программы загружен в требуемое место, то эта разница равна нулю и никакой настройки не требуется. Каждый блок настроек должен начинаться на DWORD-границе, для выравнивания блока можно пользоваться нулями. При настройке необходимую позицию в блоке вычисляют как сумму относительного адреса страницы и базового адреса загруженной программы.
Структура элемента массива настроек