Исполняемые файлы(PE–файлы/Portable Executable File/) ОБМЕН ДАННЫМИ МЕЖДУ ПРОЦЕССАМИ (продолжение) Исполняемые файлы (.exe,.dll,.ocx и т.д.) - файлы образа задачи (image file) компонуются из объектных файлов (.obj) - COFF (Common Object File Format) – файлов. Отображение исполняемого файла на адресное пространство – загрузка исполняемого модуля, происходит по базовому адресу (если возможно, то по базовому адресу по умолчанию). Объектный код содержит относительные адреса – смещения по отношению к базовому адресу. При компоновке относительные адреса заменяются на абсолютные адреса с использованием базового адреса по умолчанию.
Стандартные поля Оконно-зависимые поля Каталоги данных Заголовок PE-файла Таблица разделов Разделы Заглушка MS-DOS …………………… Заголовок COFF-файла Необязательный заголовок Текст (исполняемый код) Данные Ресурсы Экспорт Импорт ………………………….. Computer Type NumberOfSection TimeDateStamp ………………… Characteristics Таблица экспорта Таблица импорта Таблица ресурсов ………………….. Таблица базовой переадресации Таблица TLS Заголовок раздела 1 Заголовок раздела 2 …………………….. Name VirtualSize VirtualAddress ……………… Заголовок раздела Структура PE-файла
Раздел текста: исполняемый код данного файла, обозначается.text Разделы данных:.bss содержит неинициализированные данные,.rdata – данные только для чтения (символьные строки, константы),.data содержит все остальные переменные. Раздел ресурсов: содержит информацию о ресурсах, обозначается.rsrc. Раздел перемещения: хранит таблицу адресных записей с адресными привязками к реальному адресу загрузки, обозначается.reloc. Раздел экспорта: содержит информацию об экспортируемых функциях и глобальных переменных, обозначается.edata. Раздел импорта: содержит информацию об импортируемых функциях, обозначается.idata. Разделы
#include int main(int argc, char* argv[]){ LOADED_IMAGE LoadedImage; PUCHAR BaseAddress; DWORD RVAExpDir, VAExpAddress; IMAGE_EXPORT_DIRECTORY* ExpTable; char* sName; DWORD nNames; char* pName; char** pNames; DWORD i; Получение информации о PE-файле
//Загружаем PE-файл if(!MapAndLoad(argv[1], NULL, &LoadedImage, TRUE,TRUE)){ printf("Something's wrong!\n"); exit(1); } //Считываем базовый адрес загрузочного модуля BaseAddress=LoadedImage.MappedAddress; printf("0x%lx - Base Address\n",BaseAddress); //Определяем относительный виртуальный адрес - RVA, таблицы экспорта RVAExpDir= LoadedImage.FileHeader-> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; printf("0x%lx -RVA\n", RVAExpDir);
BOOL MapAndLoad( PSTR ImageName, PSTR DllPath, PLOADED_IMAGE LoadedImage, BOOL DotDll, BOOL ReadOnly ); typedef struct _LOADED_IMAGE { PSTR ModuleName; HANDLE hFile; PUCHAR MappedAddress; PIMAGE_NT_HEADERS32 FileHeader; ULONG NumberOfSections; PIMAGE_SECTION_HEADER Sections; ULONG SizeOfImage; } LOADED_IMAGE, *PLOADED_IMAGE;
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; LoadedImage.FileHeader
typedef struct _IMAGE_OPTIONAL_HEADER { ………………………………………………………………… BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; …………………………………………………………………… DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; FileHeader->OptionalHeader
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 ………………………………………………………………. #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 ………………………………………………………….. Индексы массива точек входа таблиц данных (Directory entries): RVAExpDir= LoadedImage.FileHeader-> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
//Определяем виртуальный адрес массива строк по его RVA VAExpAddress= (DWORD)ImageRvaToVa(LoadedImage.FileHeader, BaseAddress, RVAExpDir,NULL); printf("0x%lx -VA\n",VAExpAddress); ExpTable=(IMAGE_EXPORT_DIRECTORY*)VAExpAddress; //Определяем виртуальный адрес строки - имени PE-файла, //по его RVA sName=(char*)ImageRvaToVa(LoadedImage.FileHeader, BaseAddress, ExpTable->Name,NULL); printf("Name of PEF: %s\n",sName);
PVOID ImageRvaToVa( PIMAGE_NT_HEADERS NtHeaders, PVOID Base, ULONG Rva, PIMAGE_SECTION_HEADER* LastRvaSection ); VAExpAddress=(DWORD)ImageRvaToVa( LoadedImage.FileHeader,BaseAddress, RVAExpDir,NULL);
typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; DWORD AddressOfNames; DWORD AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; ExpTable=(IMAGE_EXPORT_DIRECTORY*)VAExpAddress
//Определяем виртуальный адрес массива строк по его RVA pNames=(char**)ImageRvaToVa(LoadedImage.FileHeader, BaseAddress, ExpTable->AddressOfNames,NULL); //Считываем количество экспортируемых имен из таблицы //экспорта nNames=ExpTable->NumberOfNames; printf("Exported data:\n",pName); for(i=0;i
КОМПИЛЯЦИЯ > cl 1.c imagehlp.lib OUTPUT > 1 td1.dll 0x Base Address 0x9a50 -RVA 0x29a50 -VA Name of PEF: td1.dll Exported data: a f g Упражнение 1: получите список экспортируемых функций библиотеки kernel32.dll; получите список экспортируемых функций модулей процесса notepad.exe.
Вторая тема РГЗ
#include #pragma data_seg(".M_SH") int d=89; #pragma data_seg() __declspec(dllexport) void setData(int n){ d=n; } __declspec(dllexport) int getData(){ return d; } /*BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ return TRUE; }*/ >cl /c d1.c >link /DLL /SECTION:.M_SH,RWS d1.obj
#include __declspec(dllimport) void setData(int); __declspec(dllimport) int getData(); int main(){ printf("%i\n",getData()); setData(13); printf("%i\n",getData()); getchar(); return 0; } >cl 1.c d1.lib
#include __declspec(dllimport) void setData(int); __declspec(dllimport) int getData(); int main(){ printf("%i\n",getData()); return 0; } >cl 2.c d1.lib
#include #pragma data_seg(".M_SH") extern __declspec(dllexport) int d[10]={1}; extern __declspec(dllexport) int n=10; #pragma data_seg() #pragma comment(linker, "/SECTION:.M_SH,RWS" ) d2.c >cl /c d2.c >link /DLL d2.obj
#include extern __declspec(dllimport) int d[10]; extern __declspec(dllimport) int n; int main(){ int i; for(i=0;icl 1.c d2.lib
#include extern __declspec(dllimport) int d[10]; extern __declspec(dllimport) int n; int main(){ int i; for(i=0;icl 2.c d2.lib
Упражнение 2: создайте библиотеку с переменной общего доступа целого типа, инициализируя ее нулем; пусть два процесса независимо и одновременно увеличивают каждые 10 миллисекунд значение этой переменной на 1 в течение 5-10 секунд ; определите окончательное значение переменной общего доступа, равно ли оно сумме изменений, вносимых процессами, попытайтесь объяснить результат.