Реферат: Жесткое внедрение DLL в Windows-программы

На суд читателяпредставляется статья о внедрении собственного исполняемого кода в Windowsпрограммы.

В статье использованыразличные технические термины, относящиеся к программированию под ОС Windows, вчастности с применением Windows API. Тексты программ, приведенные в качествепримеров, тестировались в среде Borland C++ Builder 6.0. Работа приложенияпроверялась в среде Windows 2000, среда Windows 9x в силу моральногоустаревания не рассматривалась.

Введение в специальность

Внедрение своегокода в чужую программу может понадобится для множества задач, например, дляотладки и анализа работы приложений, для установки различного рода программныхзащит, для «шпионских» целей.  На сегодняшний день существуетдостаточно много методов внедрить свой код в чужую программу. Достаточноподробно они описаны в статье автора Tanaka «Программы-невидимки»,Однако все описанные методы являются внешними по отношению к целевой программе,т.е. для внедрения кода каждый раз необходим запуск постороннего приложения,так называемого «загрузчика», осуществляющего внедрение. Предлагаемыйспособ отличается тем, что осуществляет разовую, достаточно простую модификациювнутренних структур .exe файла, не модифицирует исполняемый код программы, неувеличивает размер файла, не требует внешнего загрузчика, практически незаметендля пользователя. Метод позволяет модифицировать большинство .exe файлов.

Как это работает

Принцип работыоснован на следующем: практически любая Windows-программа используетдинамические библиотеки (DLL). В них могут храниться различные функции (в томчисле системные — в USER32.DLL, GDI.DLL и т.д.), ресурсы типа диалогов, иконок,картинок, указателей мыши. Достаточно сложно найти программу, которая не использовалабы DLL вообще. Соответственно, программа, использующая DLL-библиотеки, содержитв своем .exe файле информацию о том, какие именно библиотеки ей нужны, и какиефункции из этих библиотек она использует (импортирует). При запуске любойпрограммы системный загрузчик Windows считывает список используемых этойпрограммой DLL-библиотек и загружает (отображает) их в адресное пространствопрограммы. После этого для каждой импортируемой программой функции загрузчикопределяет адрес вызова.

 Каждая DLL-библиотекасодержит функцию с именем DllMain следующего вида:

BOOLWINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad);

 Назначение её — сугубо информационное. Вызывая эту функцию,загрузчик сообщает библиотеке о том, что она будет подключена к какому-топроцессу, либо в контексте процесса происходит создание потока. Загрузка любойпрограммы включает в себя последовательный вызов функций DllMain всехиспользуемых DLL. Аналогично данный вызов осуществляется при отключении ивыгрузке библиотеки. Думаю, что суть метода вам уже ясна: достаточно добавить ксписку используемых программой DLL-библиотек свою, у которой функция DllMainсодержит необходимый вам код. Весь код в рамках этой ф-ции будет выполнятся сприоритетом «заряженной» программы.

 В меру скромноговоображения приведу несколько примеров использования данной методики длярешения практических задач. Первое, что приходит в голову — это система«навесной» защиты, которую можно установить на любое готовоеприложение. Метод проверки допуска может быть любым — от простейшего пароля, дообращения к внешнему устройству, содержащему private-key для декодированиячасти исполняемого кода программы (например, USB-ключ). Далее — как былосказано в предисловии — любые виды троянов/вирусов.

Рецепт

Что же, теперь намнеобходимо изменить .exe файл таким образом, что бы в списке используемыхпрограммой DLL библиотек появилась наша библиотека. На первый взгляд даннаязадача представляется как «темный лес» — где этот список взять, чегов нем искать, как чего менять? Но всё не так печально! К нашему с вами счастью,формат .exe файла Windows достаточно строго стандартизирован и подробно описанв документации. Желающим подробно поковыряться во внутренностях могупосоветовать ознакомиться с вот этим документом:

 Peering Inside the PE: A Tour of the Win32Portable Executable File Format,

для остальных япостараюсь привести здесь минимум информации, необходимый для реализациипрограммы, «заряжающей» нашим кодом почти любой .exe файл.(Относительно ограничений метода — см. гл. Выводы)   Приступам к пациенту.Формат файла программы, так же называемый «переносимымисполнительным» (PE — portable executable), определяет поведениеоперационной системы на всех этапах работы — начиная от отображения файла наадресное пространство процесса, загрузки необходимых библиотек, инициализацииресурсов, до собственно выгрузки программы. Самое важное из того, что следуетзнать о РЕ-файлах, это то, что исполняемый файл на диске и модуль, получаемыйпосле загрузки, очень похожи. Причиной этого является то, что загрузчик Windowsдолжен создать из дискового файла исполняемый процесс без больших усилий.Точнее говоря, загрузчик попросту использует механизмы отображения файлов впамять, чтобы загрузить соответствующие части РЕ-файла в адресное пространствопрограммы.* Так же просто загружается и DLL. После того как ЕХЕ или .DLL модулизагружены, Windows обращается с ними так же, как и с другими отображенными впамять файлами.

 /> />

/> * См. справку по функция CreateFile, MapViewOfFile, CreateFileMapping.

 Так как структура исполнительного файла является довольногромоздкой, вникать подробно в описание каждого её элемента мы не будет, лишькратко остановимся на необходимых нам элементах.  Все файлы программ дляWindows имеют следующий формат (см. рис. 1):

/> 

рис. 1 Структураисполнительного файла.

   1. ЗаголовокMSDOS Начиная с нулевого смещения, в файле располагается заголовок MSDOS,имеющий формат IMAGE_DOS_HEADER (см. файл winnt.h). В этом заголовке насинтересует только одно поле:

IMAGE_DOS_HEADER->e_lfanew,

содержащеесмещение сигнатуры файла.

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

PE\0\0

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

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

IMAGE_FILE_HEADERIMAGE_OPTIONAL_HEADER

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

/> * RVA — Relative virtualladdress — относительный виртуальный адрес. 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. DWORDCharacteristics Указатель на таблицу указателей (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;

      }

    intsize = 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;

      }

  3. Определяемрасположение таблицы импорта, выводим информацию об используемых DLL.

    mz_head = (IMAGE_DOS_HEADER *)fBeg;

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

   (DWORD)pe_opt_head = (DWORD)pe_head + sizeof(IMAGE_FILE_HEADER);

    //Определяем расположение таблицы импорта в секцииимпорта...

    DWORD ImportRVA = pe_opt_head->

 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    intsect_num = -1;

    //Ищем секцию с таблицей импорта...

    (DWORD)sect = (DWORD)pe_opt_head +sizeof(IMAGE_OPTIONAL_HEADER);

    inti;

    for( i=0; iNumberOfSections; i++)

       {

       if ( ImportRVA < sect->VirtualAddress )

               {

               sect--;

               sect_num=i-1;

               break;

               }

       sect++;

       }

    if(sect_num == -1)

       {

       Log->Lines->Add(“Данная программа не использует динамическиебиблиотеки!»);

        UnmapViewOfFile(fBeg);CloseHandle(fMap);

       return;

       }

   sect++;

   DWORD AfterImportSecBeg = (DWORD)fBeg + sect->PointerToRawData;

    sect--;

    //Получаемфайловый указатель на раздел c таблицей импорта.

    LPVOID ImportSecBeg;

   (DWORD)ImportSecBeg = (DWORD)fBeg + sect->PointerToRawData;

    //Вычисляем смещение таблицы импорта в секции 

    //импортаотносительно ее начала (секции).

    LPVOID ImportTable;

   (DWORD)ImportTable =  ImportRVA — sect->VirtualAddress;

   (DWORD)ImportTable = (DWORD)ImportSecBeg

                          + (DWORD)ImportTable;

   IMAGE_IMPORT_DESCRIPTOR *DLLInfo = (IMAGE_IMPORT_DESCRIPTOR *)ImportTable;

   LPVOID DLLName;

   DWORD DLLCounter = 0;

    //Выводим информацию об используемых DLL

    while (DLLInfo->Name != NULL)

      {

     DLLCounter++;

     (DWORD)DLLName = (DWORD)DLLInfo->Name — sect->VirtualAddress;

     (DWORD)DLLName = (DWORD)ImportSecBeg + (DWORD)DLLName;

     Log->Lines->Add(IntToStr(DLLCounter)+"->"+(LPSTR)DLLName);

     Application->ProcessMessages();

     DLLInfo++;

      }

   Log->Lines->Add(«Всего используется „+IntToStr(DLLCounter) + “ библиотек.»);

  4. Определяем, имеется ли в файле достаточно свободногоместа для размещения новой таблицы импорта.

    //Вычисляемразмер новой таблицы импорта:

    //Суммируемколичество уже используемых DLL + наша DLL + zero запись.

    DWORD NewImportTableSize =sizeof(IMAGE_IMPORT_DESCRIPTOR)*(DLLCounter+2);

   char dllName[] = «azx»;

   NewImportTableSize += strlen(dllName)+1;

    //Получаем файловый указатель на конец секции импорта.

    LPVOID pos;

   (DWORD)pos = AfterImportSecBeg-1;

   DWORD maxFree = 0;

   DWORD prevPtr;

   LPVOID FreePtr = NULL;

    //Ищем максимальный кусок свободного места в секции...

    while ( pos >= ImportSecBeg )

      {

     if ( *(BYTE *)pos == 0x00  )

        {

        prevPtr = (DWORD)pos;

        while (*(BYTE *)pos == 0x00)

           (DWORD)pos -= 1;

        if ( ((DWORD)prevPtr — (DWORD)pos) > maxFree )

           {

           maxFree = ((DWORD)prevPtr — (DWORD)pos);

           (DWORD)FreePtr = (DWORD)pos + 1;

           }

         }

      (DWORD)pos-= 1;

      }

   //Модифицируемполученный указатель на свободный блок, т.к.

   //он можетуказывать на завершающий нулевой DWORD

   //какой-либоструктуры 

   (LPDWORD)FreePtr +=1;

   maxFree -=4;

   //Проверяемобъем свободного места

   if ( maxFree < NewImportTableSize )

      {

     Log->Lines->Add(«Недостаточно свободного места в таблице импорта \

      для занесенияинформации об дополнительной библиотеке.»);

      UnmapViewOfFile(fBeg);

     CloseHandle(fMap);

      return;

      }

   else

     Log->Lines->Add(«Достаточно свободного \

      места длязанесения дополнительной информации.»);

  Application->ProcessMessages();

  5. Финальнаячасть: Создаем в файле новую таблицу импорта и структуру IMAGE_IMPORT_BY_NAME.Записываем в файл строки с именем нашей библиотеки и импортируемой функции.Вычисляем все необходимые адреса, заносим их в структуры IMAGE_IMPORT_DESCRIPTOR,IMAGE_IMPORT_BY_NAME. Заносим в заголовок новый адрес таблицы импорта.

   //1. Копируемстарую таблицу импорта в новое место

   memcpy(FreePtr, ImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR)*DLLCounter);

   //2.1 Сохраняем строку с именем нашей DLL в старой таблицеимпорта

   //(для экономииместа)

   memcpy(ImportTable, OUR_DLL_NAME,strlen(OUR_DLL_NAME));

  LPDWORD zeroPtr;

  (DWORD)zeroPtr = (DWORD)ImportTable + strlen(OUR_DLL_NAME);

   //2.2 Сохраняем структуру IMAGE_IMPORT_BY_NAME в старойтаблице импорта.

   //(так же дляэкономии места)

   IMAGE_IMPORT_BY_NAME myName;

  myName.Hint = 0x00;

  myName.Name[0] = 0x00;

   WORDHint = 0;

   charmyFuncName[] = OUR_FUNC_NAME;

  hackRec patch;

  patch.ZeroDword = NULL;

  patch.IAT = ImportRVA + strlen(OUR_DLL_NAME) + sizeof(hackRec);

  patch.IATEnd = NULL;

  DWORD IIBN_Table;

  memcpy(zeroPtr, &patch, sizeof(patch)); (DWORD)zeroPtr += sizeof(patch);

  memcpy(zeroPtr, &Hint, sizeof(WORD)); (DWORD)zeroPtr += sizeof(WORD);

  memcpy(zeroPtr, myFuncName, strlen(myFuncName)+1 );

  (DWORD)zeroPtr += strlen(myFuncName)+1;

  memcpy(zeroPtr, &myName, sizeof(IMAGE_IMPORT_BY_NAME) );

   //2.3. Заполняем структуру IMAGE_IMPORT_DESCRIPTOR даннымиоб нашей DLL

   IMAGE_IMPORT_DESCRIPTOR myDLL;

   //Вычисляем указатель на нашу структуруIMAGE_IMPORT_BY_NAME:

   //это адресначала старой таблицы импорта + длинна строки с именем

   //нашей DLL +нулевой DWORD

   IIBN_Table = ImportRVA + strlen( OUR_DLL_NAME )+ sizeof(DWORD);

   //Указатель на таблицу Characteristics

   myDLL.Characteristics = IIBN_Table;

  myDLL.TimeDateStamp = NULL;

  myDLL.ForwarderChain = NULL;                                  

   //Записываем адрес строки с именем файла нашей DLL

   myDLL.Name = ImportRVA;

   //Указатель на таблицу FirstThunk

   myDLL.FirstThunk = IIBN_Table;

   //Записываем в новую таблицу импорта запись о нашей DLL

   LPVOID OldFreePtr = FreePtr;

  (DWORD)FreePtr +=sizeof(IMAGE_IMPORT_DESCRIPTOR)*DLLCounter;

  memcpy(FreePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));

   //Создаем «финальную» нулевую запись со всемиполями равными нулю

   myDLL.Characteristics = NULL;

  myDLL.TimeDateStamp = NULL;

  myDLL.ForwarderChain = NULL;

  myDLL.Name = NULL;

  myDLL.FirstThunk = NULL;

  

   //И записываем её в конец новой таблицы импорта.

   (DWORD)FreePtr+=sizeof(IMAGE_IMPORT_DESCRIPTOR)*DLLCounter;

  memcpy(FreePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));

   //3. Устанавливаем указатель на нашу таблицу импорта.

   // ВычисляемRVA нашей таблицы

   DWORD NewImportTableRVA = (DWORD)OldFreePtr — (DWORD)ImportSecBeg +

                             sect->VirtualAddress;

   // Заносим его в DataDirectory

  pe_opt_head->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress =

                             NewImportTableRVA;

  pe_opt_head->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size =

           (DLLCounter + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);

  UnmapViewOfFile(fBeg);

  CloseHandle(fMap);

Вывод

Данная методикапозволяет внедрять свою DLL библиотеку в программы, имеющие достаточносвободного места в секции с таблицей импорта. Приведенная программа может бытьдоработана в следующих направлениях:

Создание таблицыимпорта в другой секции (если в секции с оригинальной таблицей не хватаетместа)

Создание новойсекции и хранение новой таблицы импорта в ней.

 Отдельное словостоит сказать об .exe файлах, входящих в стандартную поставку Windows(таких какcalc.exe, paint.exe, wordpad.exe, etc.). У них таблица импорта продублирована вначале файла, между MZ- и PE- заголовками, поэтому при модификации таких файловнеобходимо в соответсвующих записях в DataDirectory обнулить адреса на этитаблицы (подробнее см. файл winnt.h, раздел Directory Entries).

Список литературы

Для подготовкиданной работы были использованы материалы с сайта www.bugtraq.ru/

еще рефераты
Еще работы по информатике, программированию