2. Сигнатура PE-файла Сигнатура, иначе - подпись, означающая, что этот файл является исполнительным файлом для WIndows. Представляет собой строку

PE\0\0

и располагается в файле по смещению, указанному в IMAGE_DOS_HEADER->e_lfanew.

 3. Заголовок IMAGE_NT_HEADERS Находится сразу же за сигнатурой PE, и представляет собой структуру из двух заголовков:

IMAGE_FILE_HEADER IMAGE_OPTIONAL_HEADER

 Данные именно из этих структур определяют, как будет выглядеть изображение файла в памяти. В самом конце структуры IMAGE_OPTIONAL_HEADER располагается массив записей, имеющий тип IMAGE_DATA_DIRECTORY и называемый DataDirectory. Начальные элементы массива содержат стартовый RVA* и размеры важных частей исполняемого файла. В настоящее время некоторые элементы в конце массива в стандарте не используются. Первый элемент массива - это всегда адрес и размер экспортированной таблицы функций (если она присутствует). Второй элемент массива - адрес и размер импортированной таблицы функций (она то нас и интересует).

 * RVA - Relative virtuall address - относительный виртуальный адрес. RVA - это просто смещение данного элемента по отношению к адресу, с которого начинается отображение файла в памяти. Пусть, к примеру, загрузчик Windows отобразил РЕ-файл в память, начиная с адреса 0х400000 в виртуальном адресном пространстве. Если некая таблица в отображении начинается с адреса 0х401464, то RVA данной таблицы 0х1464.

Вот практически все, что нам нужно знать о формате файла! Резюмируя , выпишем логическую цепочку доступа к таблице импорте:

IMAGE_DOS_HEADER->e_lfanew -> IMAGE_NT_HEADERS-> IMAGE_OPTIONAL_HEADER-> DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]

Теперь рассмотрим структуру самой таблицы импорта. Данная таблица находится в секции импорта (что такое секции в .exe-фале - см описание формата) и содержит всю информацию, необходимую загрузчику для подключения всех DLL и определения адресов вызываемых программой функций. Однозначно определить расположение таблицы импорта по имени секции не представляется возможным, т.к. в зависимости от компилятора данные имена значительно отличаются. Например, компилятор Borland C++ 5.5 (bcc32.exe) именует секцию импорта как ".idata"; компилятор от Microsoft хранит таблицу импорта в секции с именем ".text".*

  

 * Строго говоря, компилятор совсем не обязан выделять данные об импортируемых функциях в отдельную секцию. Например, компилятор от Microsoft хранит данные импорта в одной секции с исполняемым кодом.

 Рассмотрим подробнее, что представляет собой таблица импорта. Как и следовало ожидать, это массив записей определенного типа (IMAGE_IMPORT_DESCRIPTOR). Количество записей в массиве нигде в заголовках файла не хранится, а признаком конца массива является запись со всеми полями, установленными в NULL. Каждой используемой программой DLL библиотеке соответствует одна запись в таблице импорта следующего вида:

рис. 2 Структура таблицы импорта.

 Поля структуры IMAGE_IMPORT_DESCRIPTOR: 1. DWORD Characteristics Указатель на таблицу указателей (HintName Array) типа PIMAGE_IMPORT_BY_NAME. В данной таблице содержатся адреса структур, cодержащих информацию об импортируемых из данной библиотеки функциях. Формат структуры описан в winnt.h как IMAGE_IMPORT_BY_NAME, и включает в себя 2 поля: Hint - число, помогающее загрузчику найти адрес функции в самой библиотеке. Используется опционально, и не обязательно должно содержать верное значение.

Второй параметр - Name - строка, содержащая имя функции. 2. DWORD TimeDateStamp Дата и время создания файла. 3. DWORD Forwarder Chain Данное поле служит для реализации механизма "ссылочности" между DLL библиотеками. Например, одна библиотека часть своих экспортируемых функций представляет как экспортируемые функции другой библиотеки. К примеру, NTDLL.DLL перенаправляет вызовы частьи своих функций в KERNEL32.DLL. К сожалению, механизм передачи вызовов такого рода не описан, а программы, реализующие эту возможность, достаточно сложно найти. 3. DWORD Name Это RVA указатель на нуль-терминированную ASCII строку, содержащую имя файла DLL библиотеки. 4. PIMAGE_THUNK_DATA FirstThunk Указатель на вторую таблицу указателей, идентичную таблице HintName Array. До начала загрузки DLL библиотек в адресное пространство процесса эти указатели содержат адреса структур IMAGE_IMPORT_BY_NAME. В процессе загрузки программы этот массив заполняется адресами соответствующих функций.

 Это практически всё, что нам нужно знать о формате .exe файла для решения поставленной задачи.

 После таблицы импорта (последняя запись, содержащая во всех полях NULL) в файле как правило идут данные импорта (массивы HintName, строки, с именами библиотек и т.д.). Следовательно, добавление еще одной записи о нашей DLL в существующую таблицу представляется достаточно громоздким и труднореализуемым - потому как в случае "сдвига" данных, идущих после таблицы импорта необходимо будет пересчитать все указатели на эти данные. Выход из данной ситуации - создание новой таблицы импорта, содержащей всю существующую информацию + информация о нашей DLL. Чтобы где-то расположить новую таблицу импорта, необходимо наличие свободного места в файле. И тут как нельзя кстати обнаруживается такая замечательная особенность PE-файлов, как "страничность", или, иначе говоря, выравнивание данных в файле на определенные адреса. Размеры этих страниц определяются параметром

IMAGE_OPTIONAL_HEADER->FileAlignment.

 Рассмотрим, как используется этот параметр. Допустим, что его величина равна 0x200h (стандартное значение), а исходный размер данных для какой-либо секции равен 0x500h (до создания компилятором файла). Так вот, после выравнивания на величину FileAlignment размер секции будет равен 0x600h, т.е. будет кратен величине FileAlignment. И хотя последние 0х100h байт нулей добавленные компилятором в секцию нигде не используются, они исправно отображаются на адресное пространство процесса. Соответственно все, что мы туда запишем, будет присутствовать в образе файла в памяти. Размер свободного места в секции зависит от конкретного файла, но, как правило, его достаточно для размещения новой таблицы импорта. В том случае, если ни в одной из секций файла нет свободного пространства, возможен вариант создания дополнительной секции либо увеличения длины самой последней из секций (в приводимой для примера программе не реализовано). Резюмируя, разбиваем процесс внедрения на следующие стадии:

 Открытие файла

Анализ файла на возможность модификации (проверка наличия свободного места в файле для новой таблицы импорта)

Формирование новой таблицы импорта, соответствующих массивов HintName (ссылки FirstThunk и Characteristics), имени библиотеки (ссылка Name).

Расчёт RVA всех структур, заносимых нами в файл (обоих массивов HintName, строки с именем DLL, нового адреса таблицы импорта).

Запись в файл новой таблицы импорта и всех новых структур.

Установка нового указателя на таблицу импорта в заголовке (второй элемент массива в IMAGE_OPTIONAL_HEADER->DataDirectory[]).

 В том случае, если планируется добавление новой секции либо увеличение размера существующей, необходима дополнительная модификация таблицы секций.

Реализация

Думаю, теории достаточно, приступаем к практике. Целиком проект можете загрузить тут. Разберем пошагово каждую операцию: 1. Открываем .exe файл, отображаем его для удобства работы на своё адресное пространство.

IMAGE_DOS_HEADER *mz_head;

IMAGE_FILE_HEADER *pe_head;

IMAGE_OPTIONAL_HEADER *pe_opt_head;

IMAGE_SECTION_HEADER *sect;

char pe[] = "PE\0\0";

HANDLE f = NULL;

//Открываем файл

f = CreateFile(openF->FileName.c_str(), GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_WRITE, NULL,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (f == INVALID_HANDLE_VALUE)

{

Log->Lines->Add("Ошибка при открытии файла: ");

parse_error();

return;

}

//Создаем отображение файла

HANDLE fMap = CreateFileMapping( f, NULL,

PAGE_READWRITE,

0, 0, NULL);

CloseHandle(f);

if (fMap == NULL)

{

Log->Lines->Add("Ошибка при вызове CreateFileMapping(): ");

parse_error();

return;

}

int size = sizeof( IMAGE_DOS_HEADER );

//Отображаем начало файла в память

LPVOID fBeg = MapViewOfFile( fMap, FILE_MAP_WRITE, 0, 0, size);

if (fBeg == NULL)

{

Log->Lines->Add("Ошибка при вызове MapViewOfFile(): ");

parse_error();

return;

}

2. Проверяем, является ли файл PE-executable:

//Определяем смещение РЕ-заголовка.

mz_head = (IMAGE_DOS_HEADER *)fBeg;

DWORD peOffset = mz_head->e_lfanew;

UnmapViewOfFile(fBeg);

//Отображаем в память с учетом смещения до РЕ-заголовка

size = peOffset + sizeof( DWORD ) + sizeof( IMAGE_FILE_HEADER )

+ sizeof( IMAGE_OPTIONAL_HEADER );

fBeg = MapViewOfFile( fMap, FILE_MAP_READ, 0, 0, size);

if (fBeg == NULL)

{

Log->Lines->Add("Ошибка при вызове MapViewOfFile(): ");

parse_error();

CloseHandle(fMap);return;

}

mz_head = (IMAGE_DOS_HEADER *)fBeg;

(DWORD)pe_head = (DWORD)fBeg + peOffset;

//Проверяем, PE или не PE файл

if ( strcmp(pe,(const char *)pe_head) != 0)

{

Log->Lines->Add("Этот файл не является Portable Executable - файлом.");

UnmapViewOfFile(fBeg);CloseHandle(fMap);

return;

}

UnmapViewOfFile(fBeg);

//По новой отображаем файл в память полностью

fBeg = MapViewOfFile( fMap, FILE_MAP_WRITE, 0, 0, 0);

if (fBeg == NULL)

{

Log->Lines->Add("Ошибка при вызове MapViewOfFile(): ");

parse_error();

CloseHandle(fMap); return;

}


Информация о работе «Жесткое внедрение DLL в Windows-программы»
Раздел: Информатика, программирование
Количество знаков с пробелами: 22271
Количество таблиц: 0
Количество изображений: 2

Похожие работы

Скачать
135709
1
0

... ) ФАКУЛЬТЕТ ЭЛЕКТРОНИКИ И ПРИБОРОСТРОЕНИЯ КАФЕДРА КЭС группа Э-92 ДАТА ЗАЩИТЫ  апреля 1997 г. Отзыв на дипломную работу студента гр.Э-92 Сорокина Ю.В. “Разработка программы контроллера автоматически связываемых объектов для управления конструкторской документацией в среде Windows 95/NT”. Широкое использование вычислительной техники в народном хозяйстве требует увеличения производства и ...

Скачать
28445
0
0

... всего пароля. Кроме того, в каждом случае используется свой запрос сервера. Поэтому на определение паролей по Sniff-файлу потребуется значительно больше времени. Первой программой, выполняющей восстановление паролей Windows NT, была L0phtCrack (сегодняшнее название - LC5). Авторами L0phtCrack являются Peiter Mudge Zatko и Chris Wysopal из фирмы L0pht Heavy Industries, Inc. (сейчас @stake, Inc.). ...

Скачать
130194
3
17

... технология Single Worldwide Binary) — можно вводить текст на любом языке и запускать версию приложений Win32 для любого языка, используя соответствующую версию операционной системы Windows XP. + + Многоязычный пользовательский интерфейс — можно менять язык пользовательского интерфейса, чтобы работать с локализованными диалоговыми окнами, меню, файлами справки, словарями, средствами проверки ...

Скачать
139808
40
0

... от традиционных локальных сетей к сочетанию сетей интранет и экстранет с Интернетом, в результате чего особенно актуальной стала задача повышения безопасности систем. Для обеспечения безопасности вычислительной среды операционная система Windows Server 2003 предоставляет множество новых средств, а также совершенствует средства, впервые появившиеся в операционной системе Windows 2000 Server. ...

0 комментариев


Наверх