какая секция pe файла обычно содержит код программы
4. PE-файлы: секции
4.1. Заголовки секций
Сразу после заголовка PE в файле располагается массив заголовков секций. Его размер задается полем NumberOfSections заголовка файла. Каждый заголовок секции состоит из 0x28 байт и имеет следующую структуру:
| Смещение (hex) | Размер | Тип | Название | Описание |
|---|---|---|---|---|
| 00 | 8 | CHAR[8] | Name | Название секции. |
| 08 | 4 | DWORD | Misc.VirtualSize | Размер секции в памяти. Если это значение больше SizeOfRawData, то секция дополняется в памяти нулевыми байтами. |
| 0C | 4 | DWORD | VirtualAddress | RVA секции в памяти. |
| 10 | 4 | DWORD | SizeOfRawData | Размер секции в файле. Всегда кратен FileAlignment из необязательного заголовка. Если секция содержит только неинициализированные данные, то это поле равно нулю. |
| 14 | 4 | DWORD | PointerToRawData | Смещение в файле до начала данных секций. Всегда кратно FileAlignment из необязательного заголовка. Если секция содержит только неинициализированные данные, то это поле равно нулю. |
| 18 | 4 | DWORD | PointerToRelocations | В исполняемых файлах это поле всегда равно нулю. |
| 1С | 4 | DWORD | PointerToLinenumbers | В исполняемых файлах это поле всегда равно нулю. |
| 20 | 2 | WORD | NumberOfRelocations | В исполняемых файлах это поле всегда равно нулю. |
| 22 | 2 | WORD | NumberOfLinenumbers | В исполняемых файлах это поле всегда равно нулю. |
| 24 | 4 | DWORD | Characteristics | Атрибуты секции. |
Прокомментируем некоторые поля.
Название секции
Название секции содержит от 0 до 8 ASCII-символов. Вместо константы 8 можно использовать определение IMAGE_SIZEOF_SHORT_NAME. Если длина названия меньше 8 символов, то оно дополняется нулевыми байтами. Если оно состоит ровно из 8 символов, то завершающего нулевого байта нет. Важно отметить, что название секции, вообще говоря, никак не соотносится с ее содержимым. Каждый компилятор использует свое собственное соглашение о именовании секций, поэтому полагаться на название секции при ее анализе нельзя. Единственно надежным способом определить, что содержит данная секция, является анализ ее атрибутов и содержащихся в ней каталогов данных.
Атрибуты секции
32-битовое поле Characteristics содержит набор флагов, описывающих содержимое данной секции. Секции исполняемого файла могут иметь следующие атрибуты:
| Название | Значение | Описание |
|---|---|---|
| IMAGE_SCN_CNT_CODE | 0x00000020 | Секция содержит исполняемый код. |
| IMAGE_SCN_CNT_INITIALIZED_DATA | 0x00000040 | Секция содержит инициализированные данные. |
| IMAGE_SCN_CNT_UNINITIALIZED_DATA | 0x00000080 | Секция содержит неинициализированные данные. |
| IMAGE_SCN_MEM_DISCARDABLE | 0x02000000 | Секция может быть удалена из памяти после создания процесса. |
| IMAGE_SCN_MEM_NOT_CACHED | 0x04000000 | Секция не может кэшироваться. |
| IMAGE_SCN_MEM_NOT_PAGED | 0x08000000 | Секция не может выгружаться в файл подкачки. |
| IMAGE_SCN_MEM_SHARED | 0x10000000 | Все копии данного файла могут иметь один общий экземпляр этой секции. По-видимому, используется только для секций данных динамических библиотек. |
| IMAGE_SCN_MEM_EXECUTE | 0x20000000 | Секцию можно исполнять как программный код. |
| IMAGE_SCN_MEM_READ | 0x40000000 | Секцию можно читать. |
| IMAGE_SCN_MEM_WRITE | 0x80000000 | В секцию можно писать. |
4.2. Содержимое секций
Сами секции располагаются в файле после всех заголовков секций. Каждая секция выравнена на границу FileAlignment из необязательного заголовка.
При анализе содержимого секций следует учитывать, что это содержимое может быть разнородным. Например, одна секция может содержать и исполняемый код, и таблицу импорта.
4.3. Доступ к секциям
Для получения указателя на заголовок первой секции можно использовать следующий макрос, определенный в WINNT.H:
где pHeader – указатель на заголовок PE, возвращаемый функцией GetHeader.
Для перебора всех заголовков секций удобно использовать такой цикл:
Теперь мы можем привести алгоритм, позволяющий пересчитать любой RVA в смещение относительно начала файла. Нам потребуются две функции. Первая ищет секцию, содержащую данный RVA, а вторая преобразует RVA в указатель на соответствующую ему позицию в файле.
В качестве примера приведем программу, которая печатает для каждого непустого каталога данных его RVA, размер и позицию в файле.
3. PE-файлы: заголовок PE
3.1. Структура заголовка
Заголовок PE (IMAGE_NT_HEADERS) всегда выравнен на границу 8 байт и состоит из трех частей:
Как уже было сказано, заголовок PE всегда начинается с 4-байтовой сигнатуры “PE\0\0” (IMAGE_NT_SIGNATURE). За ней следуют два заголовка: заголовок файла (IMAGE_FILE_HEADER) и необязательный заголовок (IMAGE_OPTIONAL_HEADER). Несмотря на свое название, IMAGE_OPTIONAL_HEADER присутствует в PE-файле всегда (необязательным он является с точки зрения общего формата COFF, поскольку не используется в объектных и библиотечных файлах).
3.2. Заголовок файла
Заголовок файла состоит из 0x14 байтов (определение IMAGE_SIZEOF_FILE_HEADER), размещается сразу после сигнатуры и содержит общее описание файла. Он состоит из следующих полей:
| Смещение (hex) | Размер | Тип | Название | Описание |
|---|---|---|---|---|
| 00 | 2 | WORD | Machine | Обозначение процессора. |
| 02 | 2 | WORD | NumberOfSections | Количество секций в файле. |
| 04 | 4 | DWORD | TimeDateStamp | Дата и время создания файла. |
| 08 | 4 | DWORD | PointerToSymbolTable | Смещение до таблицы символов или 0. |
| 0C | 4 | DWORD | NumberOfSymbols | Количество элементов в таблице символов. |
| 10 | 2 | WORD | SizeOfOptionalHeader | Размер необязательного заголовка. |
| 12 | 2 | WORD | Characteristics | Атрибуты файла. |
Опишем назначения полей.
Поле Machine
16-битовое число, которое задает архитектуру процессора, на которой может выполняться данная программа. Мне известны следующие коды процессоров (большинство из которых так никогда и не были поддержаны в Windows):
| Название | Значение | Процессор |
|---|---|---|
| IMAGE_FILE_MACHINE_UNKNOWN | 0 | неизвестный процессор |
| IMAGE_FILE_MACHINE_I386 | 0x014C | Intel 80386 или выше |
| – | 0x014D | Intel 80486 или выше |
| – | 0x014E | Intel Pentium или выше |
| – | 0x0160 | MIPS R3000, big-endian |
| IMAGE_FILE_MACHINE_R3000 | 0x0162 | MIPS R3000, little-endian |
| IMAGE_FILE_MACHINE_R4000 | 0x0166 | MIPS R4000 |
| IMAGE_FILE_MACHINE_R10000 | 0x0168 | MIPS R10000 |
| IMAGE_FILE_MACHINE_WCEMIPSV2 | 0x0169 | MIPS WCE v2 |
| IMAGE_FILE_MACHINE_ALPHA | 0x0184 | DEC/Compaq Alpha AXP |
| IMAGE_FILE_MACHINE_SH3 | 0x01A2 | Hitachi SH3 |
| IMAGE_FILE_MACHINE_SH3DSP | 0x01A3 | Hitachi SH3 DSP |
| IMAGE_FILE_MACHINE_SH3E | 0x01A4 | Hitachi SH3E |
| IMAGE_FILE_MACHINE_SH4 | 0x01A6 | Hitachi SH4 |
| IMAGE_FILE_MACHINE_SH5 | 0x01A8 | Hitachi SH5 |
| IMAGE_FILE_MACHINE_ARM | 0x01C0 | ARM |
| IMAGE_FILE_MACHINE_THUMB | 0x01C2 | ARM Thumb |
| IMAGE_FILE_MACHINE_AM33 | 0x01D3 | Panasonic AM33 |
| IMAGE_FILE_MACHINE_POWERPC | 0x01F0 | IBM PowerPC |
| IMAGE_FILE_MACHINE_POWERPCFP | 0x01F1 | IBM PowerPC FP |
| IMAGE_FILE_MACHINE_IA64 | 0x0200 | Intel IA-64 (Itanium) |
| IMAGE_FILE_MACHINE_MIPS16 | 0x0266 | MIPS16 |
| – | 0x0268 | Motorola 68000 |
| IMAGE_FILE_MACHINE_ALPHA64 | 0x0284 | DEC/Compaq Alpha AXP 64-bit |
| – | 0x0290 | HP PA-RISC |
| IMAGE_FILE_MACHINE_MIPSFPU | 0x0366 | MIPS with FPU |
| IMAGE_FILE_MACHINE_MIPSFPU16 | 0x0466 | MIPS16 with FPU |
| IMAGE_FILE_MACHINE_TRICORE | 0x0520 | Infineon TriCore |
| IMAGE_FILE_MACHINE_CEF | 0x0CEF | . |
| IMAGE_FILE_MACHINE_EBC | 0x0EBC | EFI Byte Code |
| IMAGE_FILE_MACHINE_AMD64 | 0x8664 | AMD 64 (K8) |
| IMAGE_FILE_MACHINE_M32R | 0x9041 | Renesas M32R |
| IMAGE_FILE_MACHINE_CEE | 0xC0EE | . |
Поле TimeDateStamp
32-битовое число, которое содержит дату и время создания данного файла. Формат этого поля недокументирован, однако сборщики Microsoft заносят сюда время как количество секунд от полуночи 01.01.1970 в UTC (т. е. используют юниксовский формат времени, возвращаемого функцией time языка C). Между прочим, это означает, что текущее состояние формата PE действительно только до 18.01.2038 г.
Поскольку формат этого поля недокументирован, некоторые сборщики третьих фирм сохраняют его значение в других форматах. Это может оказаться важным, т. к. данное поле используется при динамическом связывании импорта из DLL.
Поля PointerToSymbolTable и NumberOfSymbols
Согласно стандарту COFF, эти 4-байтовые поля должны обеспечивать доступ к отладочной информации в файле. Однако все известные мне сборщики заносят в них нули, а для доступа к отладочной информации используется иной способ (см. каталог отладочной информации).
Поле SizeOfOptionalHeader
16-битовое число, задающее размер необязательного заголовка. Оно равно 0xE0 для файлов PE32 (IMAGE_SIZEOF_NT_OPTIONAL32_HEADER) и 0xF0 для файлов PE32+ (IMAGE_SIZEOF_NT_OPTIONAL64_HEADER).
Поле Characteristics
16-битовое поле флагов, содержащее COFF-атрибуты файла. Перечислим только те флаги, которые относятся к исполняемым файлам.
3.3. Необязательный заголовок
Необязательный заголовок имеет два различных формата: для PE32 и для PE32+. Соответствующие структуры называются IMAGE_OPTIONAL_HEADER32 и IMAGE_OPTIONAL_HEADER64. Их поля сведены в следующей таблице:
| Смещение (hex, PE32/PE32+) | Размер (PE32/PE32+) | Тип (PE32/PE32+) | Название | Описание |
|---|---|---|---|---|
| 00 | 2 | WORD | Magic | Сигнатура заголовка. |
| 02 | 1 | BYTE | MajorLinkerVersion | Старшая цифра номера версии сборщика. Загрузчиком не используется. |
| 03 | 1 | BYTE | MinorLinkerVersion | Младшая цифра номера версии сборщика. Загрузчиком не используется. |
| 04 | 4 | DWORD | SizeOfCode | Сумма размеров всех секций, содержащих програмный код. |
| 08 | 4 | DWORD | SizeOfInitializedData | Сумма размеров всех секций, содержащих инициализированные данные. |
| 0C | 4 | DWORD | SizeOfUninitializedData | Сумма размеров всех секций, содержащих неинициализированные данные. |
| 10 | 4 | DWORD | AddressOfEntryPoint | RVA точки запуска программы. Для драйвера – это адрес DriverEntry, для DLL – адрес DllMain или нуль. |
| 14 | 4 | DWORD | BaseOfCode | RVA начала кода программы. |
| 18/– | 4/0 | DWORD | BaseOfData | RVA начала данных программы. Ненадежное поле, загрузчиком не используется. В PE32+ отсутствует! |
| 1С/18 | 4/8 | DWORD/ULONGLONG | ImageBase | Предпочтительный базовый адрес программы в памяти, кратный 64 Кб. По умолчанию равен 0x00400000 для EXE-файлов в Windows 9x/NT, 0x00010000 для EXE-файлов в Windows CE и 0x10000000 для DLL. Загрузка программы с этого адреса позволяет обойтись без настройки адресов. |
| 20 | 4 | DWORD | SectionAlignment | Выравнивание в байтах для секций при загрузке в память, большее или равное FileAlignment. По умолчанию равно размеру страницы виртуальной памяти для данного процессора. |
| 24 | 4 | DWORD | FileAlignment | Выравнивание в байтах для секций внутри файла. Должно быть степенью 2 от 512 до 64 Кб включительно. По умолчанию равно 512. Если SectionAlignment меньше размера страницы виртуальной памяти, то FileAlignment должно с ним совпадать. |
| 28 | 2 | WORD | MajorOperatingSystemVersion | Старшая цифра номера версии операционной системы. Загрузчиком не используется. |
| 2A | 2 | WORD | MinorOperatingSystemVersion | Младшая цифра номера версии операционной системы. Загрузчиком не используется. |
| 2C | 2 | WORD | MajorImageVersion | Старшая цифра номера версии данного файла. Загрузчиком не используется. |
| 2E | 2 | WORD | MinorImageVersion | Младшая цифра номера версии данного файла. Загрузчиком не используется. |
| 30 | 2 | WORD | MajorSubsystemVersion | Старшая цифра номера версии подсистемы. |
| 32 | 2 | WORD | MinorSubsystemVersion | Младшая цифра номера версии подсистемы. |
| 34 | 4 | DWORD | Win32VersionValue | Зарезервировано, всегда равно 0. |
| 38 | 4 | DWORD | SizeOfImage | Размер файла в памяти, включая все заголовки. Должен быть кратен SectionAlignment. |
| 3C | 4 | DWORD | SizeOfHeaders | Суммарный размер заголовка и заглушки DOS, заголовка PE и заголовков секций, выравненный на границу FileAlignment. Задает смещение от начала файла до данных первой секции. |
| 40 | 4 | DWORD | CheckSum | Контрольная сумма файла. |
| 44 | 2 | WORD | Subsystem | Исполняющая подсистема Windows для данного файла. |
| 46 | 2 | WORD | DllCharacteristics | Дополнительные атрибуты файла. |
| 48 | 4/8 | DWORD/ULONGLONG | SizeOfStackReserve | Размер стека стартового потока программы в байтах виртуальной памяти. При загрузке в физическую память отображается только SizeOfStackCommit байт, в дальнейшем отображается по одной странице виртуальной памяти. По умолчанию равен 1 Мб. |
| 4C/50 | 4/8 | DWORD/ULONGLONG | SizeOfStackCommit | Начальный размер стека программы в байтах. По умолчанию равен 4 Кб. |
| 50/58 | 4/8 | DWORD/ULONGLONG | SizeOfHeapReserve | Размер кучи программы в байтах. При загрузке в физическую память отображается только SizeOfHeapCommit байт, в дальнейшем отображается по одной странице виртуальной памяти. По умолчанию равен 1 Мб. Во всех 32-разрядных версиях Windows куча ограничена только размером виртуальной памяти и это поле, по-видимому, игнорируется. |
| 54/60 | 4/8 | DWORD/ULONGLONG | SizeOfHeapCommit | Начальный размер кучи программы в байтах. По умолчанию равен 4 Кб. |
| 58/68 | 4 | DWORD | LoaderFlags | Устаревшее поле, не используется. |
| 5C/6C | 4 | DWORD | NumberOfRvaAndSizes | Количество описателей каталогов данных. На текущий момент всегда равно 16. |
| 60/70 | 128 | IMAGE_DATA_DIRECTORY[16] | DataDirectory | Описатели каталогов данных. |
Поясним некоторые поля этой структуры.
Поле Magic
16-битовое поле, содержащее сигнатуру заголовка. Может принимать значения:
Поля MajorSubsystemVersion и MinorSubsystemVersion
16-битовые числа, указывающее ожидаемую версию Windows. В отличие от всех остальных полей с номерами версий это поле анализировалось при загрузке программ в NT 4.0 и 95. Если программа была графическим приложением и это поле не содержало версии 4.0, то считалось, что программа разработана для NT 3.51 и моделировалось поведение этой ОС (в частности, отсутствие трехмерных стилей диалогов и пр.). В настоящее время не используется и практически всегда равно 4.0.
Поле CheckSum
32-битовая контрольная сумма файла. Проверяется только в Windows NT при загрузке драйверов ядра и нескольких системных DLL. Алгоритм вычисления контрольной суммы недокументирован, но для ее вычисления можно использовать системную функцию CheckSumMappedFile из библиотеки IMAGEHLP.DLL.
Поле Subsystem
16-битовое число, указывающее в какой подсистеме Windows API должен исполняться данный файл. Его возможные значения:
| Название | Значение | Подсистема |
|---|---|---|
| IMAGE_SUBSYSTEM_UNKNOWN | 0 | Неизвестная подсистема. |
| IMAGE_SUBSYSTEM_NATIVE | 1 | Подсистема не требуется, используется драйверами и “родными” приложениями NT. |
| IMAGE_SUBSYSTEM_WINDOWS_GUI | 2 | Графическая подсистема Windows. |
| IMAGE_SUBSYSTEM_WINDOWS_CUI | 3 | Консольная подсистема Windows. |
| IMAGE_SUBSYSTEM_OS2_CUI | 5 | Консольная подсистема OS/2. |
| IMAGE_SUBSYSTEM_POSIX_CUI | 7 | Консольная подсистема POSIX. |
| IMAGE_SUBSYSTEM_NATIVE_WINDOWS | 8 | “Родной” драйвер Win 9x. |
| IMAGE_SUBSYSTEM_WINDOWS_CE_GUI | 9 | Графическая подсистема Windows CE. |
| IMAGE_SUBSYSTEM_EFI_APPLICATION | 10 | Программа EFI. |
| IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER | 11 | Драйвер EFI, обеспечивающий загрузочный сервис. |
| IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER | 12 | Драйвер EFI времени выполнения. |
| IMAGE_SUBSYSTEM_EFI_ROM | 13 | Прошивка ПЗУ для EFI. |
| IMAGE_SUBSYSTEM_XBOX | 14 | Подсистема Xbox. |
Поле DLLCharacteristics
16-битовое поле флагов, задающие дополнительные атрибуты файла. Возможные значения флагов:
| Название | Значение | Описание |
|---|---|---|
| IMAGE_DLLCHARACTERISTICS_NO_SEH | 0x0400 | Файл не использует структурную обработку исключений. |
| IMAGE_DLLCHARACTERISTICS_NO_BIND | 0x0800 | Запрещает статическое связывание этого файла. |
| IMAGE_DLLCHARACTERISTICS_WDM_DRIVER | 0x2000 | Файл является WDM-драйвером. |
| IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE | 0x8000 | Если этот флаг не установлен, то при загрузке программы терминальным сервером будет загружена вспомогательная DLL, обеспечивающая совместимость кода. |
Поля NumberOfRvaAndSizes и DataDirectory
В конце необязательного заголовка располагается 32-битовое число, в котором хранится количество описателей каталогов данных. За ним следует массив самих описателей, каждый из которых имеет такой вид:
В настоящее время поле NumberOfRvaAndSizes всегда содержит число 16 (символическое имя IMAGE_NUMBEROF_DIRECTORY_ENTRIES). Соответственно массив DataDirectory состоит также из 16 описателей. Каждый описатель содержит RVA и размер для одного каталога данных. Если какого-либо каталога в файле нет, то оба поля его описателя равны нулю.
Каждый из каталогов данных содержит определенную служебную информацию. Вид этой информации определяется номером каталога в массиве описателей. Поскольку каталоги данных, как правило, располагаются внутри секций, для доступа к их содержимому нам потребуется сначала изучить структуру секций.
Структура программных компонентов
Обзор структуры PE-файла
В секциях размещаются код и данные исполняемого файла, а также служебная информация, необходимая загрузчику (например, секция “. reloc ” на схеме содержит таблицу релокаций). Секции в оперативной памяти должны быть выровнены по границам страниц, поэтому загрузчик отображает каждую секцию, начиная с новой страницы адресного пространства процесса. Это приводит к тому, что в памяти секции, как правило, располагаются менее компактно, чем в файле (и это отражено на схеме).
Секции
Секция в PE-файле представляет либо код, либо некоторые данные (глобальные переменные, таблицы импорта и экспорта, ресурсы, таблица релокаций). Каждая секция имеет набор атрибутов, задающий ее свойства. Атрибуты секции определяют, доступна ли секция для чтения и записи, содержит ли она исполняемый код, должна ли она оставаться в памяти после загрузки исполняемого файла, могут ли различные процессы использовать один экземпляр этой секции и т.д.
Исполняемый файл всегда содержит, по крайней мере, одну секцию, в которой помещен исполняемый код. Кроме этого, как правило, в исполняемом файле содержится секция с данными, а динамические библиотеки обязательно включают отдельную секцию с таблицей релокаций.
Выбор базового адреса образа PE-файла в памяти
Импорт функций
В PE-файле существует специальная секция “.idata”, описывающая функции, который этот файл импортирует из динамических библиотек. Описание импортируемых функций в секции “.idata” приводит к тому, что библиотеки загружаются загрузчиком операционной системы еще до запуска программы. В принципе, необязательно описывать каждую импортируемую функцию в этой секции, так как динамические библиотеки можно загружать с помощью функции LoadLibrary из Win32 API прямо во время выполнения программы.
Экспорт функций
Информация об экспортируемых функциях хранится внутри PE-файла в специальной секции “.edata”. При этом каждой функции присваивается уникальный номер, и с этим номером связывается RVA тела функции, и, возможно, имя функции. Не всякая экспортируемая функция имеет имя, так как имена служат, главным образом, для удобства программистов.
Какая секция pe файла обычно содержит код программы
Вероятно, это одна из самых важных глав данного пособия. Прочитайте его!
Введение
Очень важно хорошо представлять себе структуру заголока PE-файла, чтобы писать наши виндовозные вирусы. В этой главе я перечислю все, что считаю наиболее важным, но здесь не вся информация о PE-файле, поэтому рекомендую взглянуть на документы, упомянутые в разделе “Что потребуется. “.
Давайте рассмотрим каждую из этих частей поподробнее. Вот диаграмма в стиле Micheal J. O’Leary.
Теперь, когда вы получили общее представление о заголовке PE, эта чудесная (но несколько усложненная) вещь станет нашей новой целью. Хорошо-хорошо, у вас есть уже общее представление, но вам нужно знать внутреннюю структуру заголовка PE. Приготовьтесь!
IMAGE_FILE_HEADER
Я дам краткое описание (резюме того, что сказал в своем прекрасном документе о формате PE-файла Мэтт Питрек) полей IMAGE_FILE_HEADER.
Это метка, которая есть у каждого PE-файла. Просто проверяйте ее существование при заражении файла. Если метки нет, то это не PE-файл, ок?
Так как компьютером, который мы используем может быть несовместим с PC (теоретически), а PE-файлы могут быть и на таких компьютерах, в этом поле указывается тип машины, для которой предназначается приложение. Это может быть одно из следующих значений:
Это поле играет важную роль при заражении. Оно сообщает, сколько секций в файле.
Содержит количество секунд, которое прошло с декабря 31-ого 1969 года с 4:00 до того момента, когда файл был слинкован.
¤ Указатель на таблицу символов
Не интересно, поскольку используется только в OBJ-файлах.
Не интересно, поскольку используется только в OBJ-файлах.
¤ Размер опционального заголовка:
Содержит количество байтов, которое занимает IMAGE_OPTIONAL_HEADER (смотри описание
Флаг дает нам еще кое-какую информацию о файле. Нам это не интересно.
IMAGE_OPTIONAL_HEADER
Так как это поле всегда равно 010Bh, похоже, что это какая-то сигнатура. Не интересно.
¤ Старшая и младшая версии линкера:
Версия линкера, который создал файл. Не интересно.
Количество байт (округленное) во всех секциях, содержащих исполняемый код.
¤ Размер инициализированных данных:
Предполагается, что здесь должен указываться общий размер всех секций с инициализированными данными.
¤ Размер неинициализированных данных:
Неинициализированные данные не занимают места на винте, но когда система загружает файл, она выделяет ему некоторое количество памяти (виртуальную память).
Где загрузчик начнет выполнение кода. Это RVA относительно базы образа, когда система загружает файл. Очень интересно.
RVA, откуда начинаются секции файла с кодом. Секции с кодом обычно идут до секций с данными и после PE-заголовка. Для файлов, произведенных с помощью микрософтовских линкеров, этот RVA обычно равен 0x1000. TLINK32, похоже, добавляет к этому RVA базу образа и сохраняет результат в данном поле.
RVA, откуда начинаются секции с данными. Они обычно идут последними после PE-заголовка и секций с кодом.
Когда линкер создает экзешник, он предполагает, что файл будет промэппирован в определенное место в памяти. Этот адрес и хранится в данном поле, делая возможным определенную оптимизацию со стороны линкера. Если файл действительно промэппирован по этому адресу, код не нуждается в каком-либо патчении перед запуском. В экзешниках, компилируемых для Windows NT, база образа по умолчанию равна 0x10000, а для DLL он по умолчанию равен 0x400000. В Win9x адрес 0x10000 не может использоваться при загрузке 32-х битных EXE, так как он находится внутри региона, разделяемого всеми процессами. Из-за этого Микрософт изменил адрес базы по умолчанию на 0x400000.
При мэппировании секции выравниваются таким образом, чтобы они начинались с виртуального адреса, кратного данному значению. Выравнивание секций по умолчанию равно 0x1000.
В PE-файле raw-данные, представляющие каждую из секций, начинаются со значения, кратного данному параметру. По умолчанию он равен 0x200, вероятно, потому что тогда секции будут начинаться с начала сектора диска (который также равен 0x200 байтам). Это поле эквивалентно размеру выравнивания сегментов/ресурсов в NE-файлах. В отличии от NE-файлов, PE-файлы не имеют сотен секций, поэтому на файловое выравнивание уходит очень мало место.
¤ Старшая и младшая версии операционной системы:
Минимальная версия операционной системы, которая требуется для использования данной программы. Назначение данного поля не совсем ясно, так как поля подсистемы служат, похоже, той же самой цели. Это поле по умолчанию равно 1.0.
¤ Младшая и старшая версии образа:
Задаваемое пользователем поле. Оно позволяет вам иметь разные версии EXE или DLL. Вы можете установить значения этих полей с помощью опции линкера /VERSION. Например “LINK /VERSION:2.0 myobj.obj”.
¤ Старшая и младшая версии подсистемы:
Похоже, что оно всегда равно 0 (идеально для метки заражения).
Похоже, что это полный размер всех частей образа, о которых должен позаботиться загрузчик. Это размер региона, начинающегося от базы образа до конца последней секции, который округляется до ближайшего числа, кратного выравниванию секций.
Размер PE-заголовка и таблицы секций (объектов). Raw-данные секций начинаются непосредственно после всех компонентов заголовка.
Предположительно CRC файла. Как и в других микрософтовских форматах исполняемых файлов, это поле игнорируется и устанавливается в 0. Есть одно исключение из этого правила: в доверенных (trusted) сервисах и EXE это поле должно содержать верную чексумму.
Тип подсистемы, используемой приложением для пользовательского интерфейса.
Набор флагов, задающий при каких условиях будет вызываться функция инициализации DLL (например DLLMain). Похоже, что это значение всегда равно 0, тем не менее операционная система вызывает инициализацию DLL для всех 4-х событий.
¤ Размер зарезервированного стека:
Количество виртуальной памяти, резервируемой для начального стека треда. Тем не менее, не вся эта память выделяется (смотри следующее поле). Это поле по умолчанию равно 0x100000. Если вы укажете 0 в качестве размера стека при создании треда функцией CreateThread, именно столько будет занимать стек нового треда.
¤ Размер выделенного стека:
Количество памяти, выделяемой для начального стека треда. Это поле по умолчанию равно 0x1000 (1 страница) у Microsoft Linker, в то время как TLINK32 делает это поле равным двум страницам.
¤ Размер зарезервированной кучи:
Количество виртуальной памяти, которое необходимо зарезервировать для начальной кучи процесса. Этот хэндл кучи можно получить, вызывав GetProcessHeap. Нет вся эта память выделяется (смотри следующее поле).
¤ Размер выделенной кучи:
Согласно WINNT.H эти поля относятся к поддержке отладки. Я никогда не видел экзешника с установленными битами этого поля, да и как заставить линкер их установить не совсем понятно.
1. Вызвать инструкцию точки прерывания перед запуском процесса 2. Вызвать отладчик после того, как процесс будет загружен в память
¤ Number Of Rva And Sizes:
Количество элементов в массиве DataDirectory (ниже). Современные компиляторы всегда устанавливает это поле равным 16.
IMAGE_SECTION_HEADER
Это 8-ми байтовое имя в формате ANSI (UNICODE), которая задает имя секции. Большая часть имен секций начинается с “.” (например “.text”), но это не обязательное требование как утверждают некоторые руководства по формату PE. Вы можете назвать вашу секцию как хотите с помощью специальной директивы ассемблера или с помощью “#pragma data_seg” и “#pragma code_seg” в Microsoft C/C++ компиляторе. Важно учитывать, что если имя секции занимает 8 байт, то в конце не будет NULL-байта. Вы можете использовать %.8s с функцией printf, чтобы скопировать строку в другой буфер и добавить NULL в конце.
Значение этого файла отличается в EXE и OBJ. В EXE он содержит реальный размер код или данных. Это размер до округления до ближайшего числа, кратного файловому выравниванию. Поле SizeOfRawData ‘размер raw-данных’ (похоже, названное не совсем верно) содержит округленное значение. Линкер Borland’а меняет значения этих двух полей и похоже, что он прав. Для OBJ файлов этой поле означает физический адрес секции. Первая секция начинается с адреса 0. Чтобы найти физический адрес следующей секции в OBJ-файле, добавьте значение SizeOfRawData к физическому адресу текущих секции.
В EXE это поле содержит RVA на то место, куда загрузчику следует промэппировать секцию. Чтобы посчитать реальный стартовый адрес данной секции в памяти и добавьте базовый адрес образа к виртуальному адресу (поле VirtualAddress). Микрософтовские инструменты по умолчанию указывают на RVA 0x1000. В OBJ’ах это поле не имеет значения и установленно в 0.
В EXE это поле содержит округленный до кратного файловому выравниванию числа размер секции. Например, предположим, что файловое выравнивание равно 0x200. Если поле VirtualSize содержит значение 0x35A, в этом поле будет находиться 0x400. В OBJ’ах это поле содержит точный размер секции, созданной компилятором или ассемблером. Другими словами для OBJ это поле играет ту же роль, что и виртуальный размер в EXE.
¤ Указатель на raw-данные:
¤ Указатель на релокейшены:
В OBJ’ах это смещение на информацию о релокейшенах данной секции. Информация о релокейшенах каждой секции OBJ следует непосредственно за raw-данными этой секции. В EXE это поле не имеет значения (как и следующее поле) и установлено в ноль. Когда линкер создает EXE, он устанавливает большую часть адресных записей (fixups), и только релокейшены адреса базы и импортируемых функций устанавливаются во время загрузки. Информация о релокейшенах базы и импортируемых функций находится в специальных секциях, поэтому в EXE нет необходимости держать информацию о релокейшенах после каждой секции raw-данных.
¤ Указатель на номера строк:
¤ Количество номеров строк:
Количество номеров строк в соответствующей таблице для данной секции.
То, что большинство программистов называет флагами, формат COFF/PE называет характеристиками. Это поле является множеством флагов, которые задают аттрибуты секции (такие как код/данные, доступно ли для чтения или для записи). Чтобы получить полный список всех возможных аттрибутов секций, смотрите IMAGE_SCN_XXX_XXX #defin’ы в WINNT.H. Некоторые из важных флагов приведены ниже:
0x00000020 Эта секция содержит код. Обычно устанавливается вместе с флагом выполняемого кода (0x80000000).
0x00000800 Содержимое этой секции не должно помещаться в конечный EXE-файл. Эти секции используются компилятором/ассемблером, чтобы передать информацию линкеру.
0x10000000 Эта секция является разделяемой. Если используется вместе с DLL, данные в этой секции будут разделяться всеми процессами, ее использующими. По умолчанию секции данных являются неразделяемыми, и это означает, что каждый процесс, использующий DLL получает свою собственную копию этой секции данныи. Если использовать техническую терминологию, флаг разделяемости говорит менеджеру загрузки, чтобы тот установил мэппинги страниц таким образом, чтобы все процессы, использующие DL ссылались на одну и ту же физическую страницу в памяти. Чтобы сделать секцию разделямой, используйте аттрибут SHARED во время линковки. Например:
говорит линкеру, что секция под названием MYDATA должна быть доступной для чтения и записи, а также быть разделяемой.
0x20000000 Эта секция является исполняемой. Этот флаг обычно устанавливается везде, где установлен флаг кода (0x00000020).
0x40000000 Эта секция доступня для чтения. Этот флаг установлен почти для всех секций EXE-файла.
Необходимые изменения
Хорошо, здесь я объясню вам изменения, которые необходимо выполнить при заражении PE. Я предполагаю, что вы делаете вирус, который увеличивает размер последней секции PE-файла. Эта техника получила наибольшее распространение среди нас, да и она, между прочим, гораздо проще, чем добавление другой секции. Давайте посмотрим, как вирус может изменить заговок исполняемого файла. Для этого мы используем программу INFO-PE Lord’а Julus’а [SLAM].





