Вопрос 4. Формат исполняемого РЕ файла ОС Windows . Приведите фрагмент программы, читающей из РЕ файла список импортируемых программой функций ОС.
Добавил: | DMT |
Дата создания: | 30 декабря 2007, 18:56 |
Дата обновления: | 30 декабря 2007, 18:56 |
Просмотров: | 11868 последний сегодня, 14:34 |
Комментариев: | 2 |
Вопрос 4. Формат исполняемого РЕ файла ОС Windows . Приведите фрагмент программы, читающей из РЕ файла список импортируемых программой функций ОС. |

Комментарии для "Вопрос 4. Формат исполняемого РЕ файла ОС Windows . Приведите фрагмент программы, читающей из РЕ файла список импортируемых программой функций ОС. "
Пользователь: ruslan Сообщений: 23 Статус: Незримый Зарегистрирован: 5 января 2008, 2:42 Был:29 января 2008, 21:23 ![]() ![]() ![]() | Дата: 5 января 2008, 3:47 Сообщение № 1 |
Формат исполняемого файла операционной системы в значительной степени отражает встроенные в операционную систему предположения и режимы поведения. Динамическая компоновка, поведение загрузчика и управление памятью – это только три примера специфических свойств операционной системы, которые можно понять по мере изучения формата исполняемых файлов. Исполняемый файл на диске и модуль, получаемый после загрузки, очень похожи. Загрузчик попросту использует отображенные в память файлы Win32, чтобы загрузить соответствующие части РЕ-файла в адресное пространство программы. Так же просто загружается и DLL. После того как ЕХЕ или .DLL модуль загружены, Windows обращается с ними так же, как и с другими отображенными в память файлами. В Win32, напротив, память, используемая под программы, данные, ресурсы, таблицы ввода, таблицы вывода и другие элементы, представляет собой один сплошной линейный массив адресного пространства. Все, что достаточно знать в этом случае, – это адрес, в который загрузчик отобразил в памяти исполняемый файл. Тогда для того, чтобы найти лю¬бой элемент модуля, достаточно следовать указателям, которые хранятся как часть отображения. Заголовок MS-DOS ![]() Заголовок MS-DOS занимает первые 64 байта PE файла. Структура, представляющая содержание MS-DOS-заголовка следующая: typedef struct _IMAGE_DOS_HEADER { //DOS .EXE заголовок USHORT e_magic; //MZ USHORT e_cblp; //Байты на последней //странице файла USHORT e_cp; //Страницы в файле USHORT e_crlc; //Настройки USHORT e_cparhdr; //Размер заголовка в //параграфах USHORT e_minalloc; //Минимальная выделенная память USHORT e_maxalloc; //Максимальная выделенная память USHORT e_ss; //Начальное (относительное) //значение SS USHORT e_sp; //Начальное значение SP USHORT e_csum; //Контрольная сумма USHORT e_ip; //Начальное значение IP USHORT e_cs; //Начальное (относительное) //значение CS USHORT e_lfarlc; //адрес Файла таблицы настройки USHORT e_ovno; //Оверлейный номер USHORT e_res [4]; //Зарезервированные слова USHORT e_oemid; //OEM идентификатор (для //e_oeminfo) USHORT e_oeminfo; //OEM информация; e_oemid //специфический USHORT e_res2 [10]; //Зарезервированные слова LONG e_lfanew; //адрес смещения PE-заголовка } IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER; Основной заголовок РЕ-файла представляет структуру типа IMAGE_NT_НEADERS, определенную в файле WINNT.H. Структура IMAGE_NT_HEADERS в памяти – это то, что Windows использует в качестве своей базы данных модуля в памяти. Каждый загруженный ЕХЕ-файл или DLL представлены в Windows структурой IMAGE_NT_HEADERS. Эта структура состоит из двойного слова и двух подструктур, как показано ниже: DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; PE File Signature Поле Signature (сигнатура – подпись), представленное как ASCII код, – это РЕ\0\0 (два нулевых байта после РЕ). Если поле e_lfanew в заголовке DOS указало вместо обозначения РЕ обозначение NE в этом месте, значит, вы работаете с файлом Win16 NE. Аналогично, если указано обозначение LE в поле Signature, то это файл VxD (VirtualDeviceDriver – драйвер виртуального устройства). Обозначение LX указывает на файл старой соперницы Windows 95 – OS/2. PE File Header За двойным словом – сигнатурой РЕ, в заголовке РЕ-файла следует структура типа IMAGE_FILE_HEADER. Поля этой структуры содержат только самую общую информацию о файле. Далее приводятся поля IMAGE_FILE_HEADER: typedef struct _IMAGE_FILE_HEADER { USHORT Machine; USHORT NumberOfSections; ULONG TimeDateStamp; ULONG PointerToSymbolTable; ULONG NumberOfSymbols; USHORT SizeOfOptionalHeader; USHORT Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER Machine – это центральный процессор, для которого предназначен файл. Определены следующие идентификаторы процессоров: Intel I386 0xl4C Intel I860 0xl4D MIPS R3000 0х162 MIPS R4000 0х166 DEC Alpha AXP 0х184 Power PC 0x1F0 (little endian) Motorola 68000 0х268 PA RISC 0х290 (Precision Architecture) NumberOfSections – количество секций в ЕХЕ- или OBJ-файле. TimeDateStamp – время, когда файл был создан компоновщиком (или компилятором, если это OBJ-файл). В этом поле указано количество секунд, истекших с 16:00 31.12.1969 PointerToSymbolTable – файловое смещение COFF-таблицы символов. Это поле используется только в OBJ- и РЕ-файлах с информацией COFF-отладчика. РЕ-файлы поддерживают разнообразные отладочные форматы, так что отладчики должны ссылаться ко входу IMAGE_DIRECTORY_ENTRY_DEBUG в каталоге данных. NumberOfSymbols – количество символов в COFF-таблицс символов. SizeOfOplionalHeader – размер необязательного заголовка, который может следован, за этой структурой. В исполняемых файлах – это размер структуры IMAGE_OPTIONAL_HEADER, которая следует за этой структурой. Characteristics – флаги, содержащие информацию о файле. Здесь описываются некоторые важные поля. 0х0001 – файл не содержит перемещений 0х0002 – файл представляет исполняемое отображение (т.е. это не OBJ- или LIB-файл) 0х2000 – файл является библиотекой динамической компоновки (DLL), а не программой PE File Optional Header Третьим компонентом заголовка РЕ-файла является структура типа IMAGE_OPTIONAL_HEADER. Для РЕ-файлов эта часть является обязательной. Наиболее важными полями являются поля ImageBase и Subsystem. ImageBase – когда компоновщик создает исполняемый файл, он предполагает, что файл будет отображен в определенное место в памяти, именно этот адрес и хранится в этом поле. Subsystem – тип подсистемы, которую данный исполняемый файл использует для своего пользовательского интерфейса. WINNT.H определяет следующие значения: NATIVE = 1 – подсистема не требуется (например, для драйвера устройства) WINDOWS_GUI = 2 – запускается в подсистеме Windows GUI WINDOWS_GUI = 3 – запускается в подсистеме Windows character (терминальное приложение) OS2_GUI = 5 – запускается в подсистеме OS/2 (только приложения OS/2 IJC) POSIX_GUI = 7 – запускается в подсистеме Posix Таблица секций Сразу после заголовка РЕ-файла в памяти следует массив из 1MAGE_SECT10N_HEADER. Эта таблица. содержит информацию о каждой секции отображения. Количество элементов этого массива задается в заголовке РЕ-файла (поле IMAGE_NT_HEADER.FileHeader.NumberOfSections). Секции в отображении упорядочены по их стартовому адресу, а не в алфавитном порядке. Каждый IMAGE_SECTION_HEADER представляет собой полную базу данных об одной секции файла ЕХЕ или OBJ \ и имеет следующий формат. #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { UCHAR Name[IMAGE_SIZEOF_SHORT_NAME]; union { ULONG PhysicalAddress; ULONG VirtualSize; } Misc; ULONG VirtualAddress; ULONG SizeOfRawData; ULONG PointerToRawData; ULONG PointerToRelocations; ULONG PointerToLinenumbers; USHORT NumberOfRelocations; USHORT NumberOfLinenumbers; ULONG Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; Name[IMAGE_SIZEOE_SHORT_NAME] – 8-байтовое имя в стандарте ANSI (не Unicode), которое именует секцию. Misc – это поле имеет различные назначения в зависимости от того, встречается ли оно в ЕХЕ- или OBJ-файле. В ЕХЕ-файле оно содержит виртуальный размер секции программного кода или данных. В случае OBJ-файлов это поле указывает физический адрес секции. VirtualAddress – в случае ЕХЕ-файлов это поле содержит RVA, куда загрузчик должен отобразить секцию. Средства Microsoft устанавливают по умолчанию RVA первой секции равным 0х101. Для объектных файлов это поле устанавливается в 0. SizeOfRawData – в ЕХЕ-файлах это поле содержит размер секции, выровненный па ближайшую верхнюю границу размера файла. PointerToRawData – файловое смещение участка, где находятся исходные данные для секции. Если пользователь сам отображает в мять РЕ- или COFF-файл (вместо того, чтобы доверить загрузку операционной системе), это поле важнее, чем в VirtualAddress. PointerToRelocations – в объектных файлах это файловое смещение информации о поправках, которая следует за исходными данными для данной секции. В ЕХЕ-файлах это поле устанавливается в 0. PointerToLinenumhers – файловое смещение таблицы номеров строк. Таблица номеров строк ставит в соответствие номера строк исходного файла адресам, по которым можно найти код, сгенерированный для данной строки. Обычно только секции с программным кодом (например, .text или CODE) имеют номера строк. В ЕХЕ-файлах номера строк собраны в конце файла после исходных данных для секций. В объектных файлах таблица номеров строк для секции следует за исходными данными секции и таблицей перемещений для этой секции. NumberOfRelocations – количество перемещений в таблице поправок для данной секции (используется только в объектных файлах). NumberOfLinenumbers – количество номеров строк в таблице номеров строк для данной секции. Characteristics – набор флагов, которые указывают на атрибуты секции (программа/данные, предназначен для чтения, предназначен для записи и т.н.). Часто встречающиеся секции Секция .text (или CODE, если PE-файл создан Borland C++) В этой секции собран весь программный код общего назначения, генерируемый компилятором или ассемблером. Компоновщик объединяет все секции .text из различных объектных файлов в одну большую секцию .text в ЕХЕ-файле. Секция .data (или DATA, если PE-файл создан Borland C++) Инициализированные данные попадают в секцию .data. Инициализированные данные состоят из тех глобальных и статических переменных, которые были проинициализированы во время компиляции. Они также включают строковые литералы (например, строку "Hello World" в программе C/C++). Компоновщик объединяет все секции .data из разных объектных и LIB-файлов в одну секцию .data в ЕХЕ-файле. Локальные переменные расположены в стеке цепочки и не занимают места в секциях .data и .bss. Секция .bss В секции .bss хранятся неинициализированные статические и глобальные переменные. Компоновщик объединяет все сек¬ции .bss из разных объектных и LIB-файлов в одну секцию .bss в ЕХЕ-файле. Секция .CRT Еще одна секция для инициализированных данных, используемая библиотеками поддержки выполнения программы Microsoft C/C++. Данные из этой секции используются для таких це¬лей, как вызов конструкторов статических классов C++ перед вызовом main или WinMain. Секция .rsrc Секция .rsrc содержит ресурсы модуля. Секция .idata Секция .idata (или таблица импорта) содержит информацию о функциях (и данных), которые модуль импортирует из других DLL. Таблица импорта начинается с массива, состоящего из IMAGE_IMPORT_DESCRIPTOR. Каждый элемент (IMAGE_IMPORT_DESCRIPTOR) соответствует одной из DLL, с кото¬рой неявно связан данный РЕ-файл. Количество элементов в массиве нигде не учитывается. Вместо этого последняя структу¬ра массива IMAGE_IMPORT_DESCRIPTOR имеет поля, содержащие NULL. Структура IMAGE_IMPORT_DESCRIPTOR имеет следующий формат typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; }; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DWORD FirstThunk; } IMAGE_IMPORT_DESCRIPTOR Characteristics/OriginalFirstThunk – в этом поле содержится смещение (RVA) массива двойных слов. Каждое из этих двойных слов в действительности является объединением IMAGE_THUNK_DATA. Каждое двойное слово IMAGE_THUNK_DATA соответствует одной функции, импортируемой данным ЕХЕ-файлом или DLL. TimeDateStamp – отметка о времени и дате, указывающая, когда был создан данный файл. ForwarderChain – это поле имеет отношение к передаче, когда одна DLL передает ссылку на какую-то свою функцию другой DLL. Name – это RVA строки символов ASCII, оканчивающейся нулем и содержащей имена импортируемых DLL. FirstThunk – RVA-смещение массива двойных слов IMAGE_THUNK_DATA. В большинстве случаев двойное слово рассматривает¬ся как указатель на структуру IMAGE_IMPORT_BY_NAME. Это структура выглядит следующим образом: typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; BYTE Name[1]; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; Hint – номер экспорта у функции импорта. Name – Строка ASCIIZ с именем импортируемой функции. Фрагмент программы читающей из РЕ файла список импортируемых программой функций ОС. Приведенный ниже фрагмент программы зарисывает в файл FunctionList.txt список библиотек с импортируемыми программой функциями.
P.S. Это фрагмент реально работающей проги (сам писал и сам проверял) ![]() |
Пользователь: DMT Сообщений: 123 Статус: Программист Зарегистрирован: 18 октября 2007, 2:35 Был:13 ноября 2017, 4:54 ![]() ![]() ![]() | Дата: 9 января 2008, 23:32 Сообщение № 2 |
Спасибо lilo за предоставленные ответы по ОС
|