2009-10-15 5 views
3

Я пишу маленький читатель PE, поэтому я запускаю dumpbin рядом с моим тестовым приложением, чтобы подтвердить, что значения читаются правильно. Все, что он работает до сих пор, за исключением таблицы экспорта.Как dumpbin может читать таблицу экспорта, когда она появляется при смещении файла больше, чем сам файл?

Файл, который я тестирую, это DLL. Мое приложение читает файл в виде массива байтов, который передается в мой класс чтения PE. Значения выравниваются с данными, выводимыми с помощью dumpbin, включая RVA и размер каталога данных экспорта.

 E000 [  362] RVA [size] of Export Directory 

Проблема состоит в том, что размер массива байтов составляет всего лишь 42 496. Как вы можете себе представить, когда мой читатель PE пытается прочитать на E000 (57 344), я получаю IndexOutOfRangeException. dumpbin, однако, не имеет такой проблемы и отлично читает каталог экспорта. И да, весь файл действительно считывается в массив байтов.

Как это возможно?

ответ

5

PE-файл содержит «разделы», а разделы имеют независимые базовые адреса. PE не является непрерывным изображением памяти. Каждый раздел представляет собой непрерывный образ памяти.

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

В качестве альтернативы рассмотрим OllyDbg, который является бесплатным отладчиком и дизассемблером с открытым исходным кодом для Windows. Это, возможно, поможет вам протестировать ваше собственное программное обеспечение и, возможно, сервер будет самой целью, которую вы пытаетесь заполнить, «сворачивая свою собственную».

Пример из dumpbin /all выхода:

 
SECTION HEADER #1 
    .text name 
    BC14 virtual size 
    1000 virtual address (00401000 to 0040CC13) 
    BE00 size of raw data 
    400 file pointer to raw data (00000400 to 0000C1FF) 
     0 file pointer to relocation table 
     0 file pointer to line numbers 
     0 number of relocations 
     0 number of line numbers 
60000020 flags 
     Code 
     Execute Read 

В этом случае мой .text раздел начинается на RVA 1000 и продолжается до RVA CE00. Указатель файла для этого раздела - 400. Я могу преобразовать в файл-указатель любые RVAs в диапазоне 1000-CDFF работой вычитания 600. (Все числовые значения шестнадцатеричные.)

Всякий раз, когда вы сталкиваетесь с «RVA »(Относительный виртуальный адрес), вы разрешаете его на смещение файла (или индекс в массив байтов), используя этот метод:

  1. Определите, к какому разделу принадлежит RVA. Каждый раздел содержит RVAs от своего виртуального адреса по его размеру. Разделы не перекрываются.
  2. Вычтите виртуальный адрес раздела из RVA - это дает смещение относительно раздела.
  3. Добавьте указатель PointerToRawData этого раздела в смещение, которое вы получите на шаге (2). Это смещение файла, соответствующее RVA.

Другой подход, который можно использовать, чтобы позвонить MapViewOfFileEx() с флагом FILE_MAP_EXECUTE набора в dwDesiredAccess аргумента. Этот API будет анализировать заголовки разделов из файла PE и читать содержимое разделов в их местоположениях относительно «базы модулей».

Основание модуля - это базовый адрес, на который будет загружен PE-заголовок. При загрузке DLL с использованием функций LoadLibrary() это можно получить через GetModuleInformation() function MODULEINFO member lpBaseOfDll.

При использовании MapViewOfFileEx() основание модуля представляет собой просто возвращаемое значение от MapViewOfFileEx().

В настройках загрузки модуля в этих способах, решении RVA к нормальному значению указателя является вопросом:

  1. Храните модуль базового адреса в char *
  2. Добавьте RVA к char *
  3. Передайте char * фактическому типу данных и разыгрывайте их.

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

+0

Извинения, поскольку я учусь, когда я иду ... До сих пор я добавил логический параметр, который сообщает читателю PE, если данные переданы в память (которые я установил в false при чтении из файла) , Если он не сопоставлен с памятью, я читаю каталог экспорта по адресу, указанному PointerToRawData в разделе .edata. Однако на этот раз AddressOfFunctions указывает на E000. Какую информацию мне нужно перевести на смещение файла? Или я что-то пропустил? –

+0

Вы используете карту памяти MapViewOfFileEx() и передаете FILE_MAP_EXECUTE? Или вы загрузили его с помощью LoadLibraryEx() и LOAD_LIBRARY_AS_IMAGE_RESOURCE? –

+0

Ничего. Я просто читаю байты из файла на диске. Я хотел бы поддерживать оба PE-изображения на диске и загружаться в память, поэтому я добавил параметр boolean, чтобы указать, какой тип изображения он есть. Если 'MemoryMapped' является ложным, я знаю, что изображение было прочитано с диска, и я могу соответствующим образом перевести адреса экспорта. Я просто не знаю, какую информацию мне нужно сделать для перевода. –