Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Ответ
 
Опции темы
Старый 18.06.2018, 20:59   #1
Человек_Борща
Модератор
Заслуженный модератор
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Адрес: Республика Беларусь, г. Минск
Сообщений: 11,471
Репутация: 2769
Вопрос Формат PE. Как преобразовать RVA/VA в File Offset?

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

Столкнулся с проблемой чтения тел секций файла (таблица импорта, экспорта, ресурсы, релоки и т.д.), потому как все они после заголовка DOS/NT/Таблицы секций, обозначены относительными смещениями уже в виртуальном пространстве, а мне нужно получить смещение в файле на диске.

Пытаюсь прочитать таблицу экспорта из dll вот так:
(Код Lazarus, описание типов можно найти в winnt.h по их имени справа)
Код:

  TImageDOSHeader = IMAGE_DOS_HEADER;
  TImageDataDirectory = IMAGE_DATA_DIRECTORY;
  TImageExportDirectory = IMAGE_EXPORT_DIRECTORY;
  TImageSectionHeader = IMAGE_SECTION_HEADER;
  TImageFileHeader = IMAGE_FILE_HEADER;
  TImageOptionalHeader32 = IMAGE_OPTIONAL_HEADER32;
  TImageOptionalHeader64 = IMAGE_OPTIONAL_HEADER64;
  TImageNTHeaders64 = IMAGE_NT_HEADERS64;
  TImageNTHeaders32 = IMAGE_NT_HEADERS32;

function TWinLibReader.LoadFile(const sFile: string): boolean;
var
  Stream: TMemoryStream;
  DOSHeader: TImageDOSHeader;
  PEHeader32: TImageNTHeaders32;
  PEHeader64: TImageNTHeaders64;
  Magic: word;
  bMode64: boolean;
  iSectionsCount: integer;
  iNTOffset: longint;
  Sections: TImageSectionHeaders;
  Section, ExpertsSect: TImageSectionHeader;
  iExportsOffset: DWORD;
  PEExportsDir: TImageDataDirectory;
  PEExports: TImageExportDirectory;

  i, iReaded: integer;
  iExpoortsSec: word;

  function GetSectionWithinRVA(Sections: TImageSectionHeaders; iSectionCount: word; RVA: DWORD; var Section: word): DWORD;
  var
    i: integer;
    Sec: TImageSectionHeader;
    NewRVA: DWORD;
  begin
    Result := 0;
    NewRVA := 0;
    for i := 0 to iSectionCount - 1 do
    begin
      Sec := Sections[i];
      if ((RVA >= Sec.VirtualAddress) and (RVA < (Sec.VirtualAddress + Sec.SizeOfRawData))) then
      begin
        NewRVA := RVA - Sec.VirtualAddress;
        NewRVA := NewRVA + Sec.PointerToRawData;
        Result := NewRVA;
        Section := i;
        Break;
      end;
    end;

  end;

begin
  Result := False;
  bMode64 := False;
  try
    if not FileExists(sFile) then
    begin
      SetErrorStr('Input file "' + sFile + '" not found');
      exit;
    end;
    Stream := TMemoryStream.Create();
    try
      Stream.LoadFromFile(sFile);
      if (Stream.Size = 0) then
      begin
        SetErrorStr('Input file "' + sFile + '" have ZERO (0) size in bytes. Nothing to read.');
        exit;
      end;
      FillChar(DOSHeader, SizeOf(TImageDOSHeader), #0);
      FillChar(PEHeader32, SizeOf(TImageNTHeaders32), #0);
      FillChar(PEHeader64, SizeOf(TImageNTHeaders64), #0);
      FillChar(PEExportsDir, SizeOf(TImageDataDirectory), #0);
      FillChar(PEExports, SizeOf(TImageExportDirectory), #0);


      Stream.Seek(0, soFromBeginning);

      Stream.Read(DOSHeader, SizeOf(TImageDOSHeader));
      Magic := DOSHeader.e_magic;

      if (Magic <> IMAGE_DOS_SIGNATURE) and (Magic <> IMAGE_NT_SIGNATURE) then
      begin
        SetErrorStr('Uknown signature "0x' + IntToHex(Magic, 4) + '" in header. File not supported.');
        exit;
      end;
      //If we in a DOS header, need relocate to DOSHeader.e_lfanew & read some of TImageNTHeaders
      iNTOffset := 0;
      if (Magic = IMAGE_DOS_SIGNATURE) then
      begin
        iNTOffset := DOSHeader.e_lfanew;
        Stream.Seek(iNTOffset, soFromBeginning);
        iReaded := Stream.Read(PEHeader32, SizeOf(TImageNTHeaders32));
      end;
      if (Magic = IMAGE_NT_SIGNATURE) then
      begin
        Stream.Seek(iNTOffset, soFromBeginning);
        iReaded := Stream.Read(PEHeader32, SizeOf(TImageNTHeaders32));
      end;

      Magic := PEHeader32.Signature;
      if (Magic <> IMAGE_NT_SIGNATURE) then
      begin
        SetErrorStr('NT header has a wrong Signature "0x' + IntToHex(Magic, 4) + '", expected "0x' + IntToHex(IMAGE_NT_SIGNATURE, 4) + '. Abort."');
        exit;
      end;
      Magic := PEHeader32.FileHeader.Machine;
      if (Magic <> IMAGE_FILE_MACHINE_I386) and (Magic <> IMAGE_FILE_MACHINE_AMD64) and (Magic <> IMAGE_FILE_MACHINE_IA64) then
      begin
        SetErrorStr('File not supported via machine type "0x' + IntToHex(Magic, 4) + '", expected one of "' +
          IntToHex(IMAGE_FILE_MACHINE_I386, 4) + '"(i386),"' + IntToHex(IMAGE_FILE_MACHINE_AMD64, 4) + '" (AMD64),"' +
          IntToHex(IMAGE_FILE_MACHINE_IA64, 4) + '"(IA64)');
        exit;
      end;

      //Need read TImageNTHeaders64
      bMode64 := (Magic <> IMAGE_FILE_MACHINE_I386);
      if bMode64 then
      begin
        Stream.Seek(iNTOffset, soFromBeginning);
        FillChar(PEHeader64, SizeOf(TImageNTHeaders64), #0);
        FillChar(PEHeader32, SizeOf(TImageNTHeaders32), #0);  //garbage
        iReaded := Stream.Read(PEHeader64, SizeOf(TImageNTHeaders64));
      end;

      if bMode64 then
        iSectionsCount := PEHeader64.FileHeader.NumberOfSections
      else
        iSectionsCount := PEHeader32.FileHeader.NumberOfSections;

      if (iSectionsCount < 1) then
      begin
        SetErrorStr('File do not have any sections.');
        exit;
      end;

      SetLength(Sections, iSectionsCount);

      for i := 0 to iSectionsCount - 1 do
      begin
        FillChar(Sections[i], SizeOf(TImageSectionHeader), #0);
        Stream.Read(Sections[i], SizeOf(TImageSectionHeader));
      end;

      if bMode64 then
        PEExportsDir := PEHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
      else
        PEExportsDir := PEHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

      if (PEExportsDir.VirtualAddress = 0) then
      begin
        SetErrorStr('File has no export section(VirtualAddress = 0)');
        exit;
      end;
      iExportsOffset := 0;
      iExportsOffset := GetSectionWithinRVA(Sections, iSectionsCount, PEExportsDir.VirtualAddress, iExpoortsSec);

      ExpertsSect := Sections[iExpoortsSec];
      if (iExportsOffset = 0) then
      begin
        SetErrorStr('RVAToOffset return -1. Abort.');
        exit;
      end;
      Stream.Seek(iExportsOffset, soBeginning);
      //Stream.Read(PEExports, SizeOf(TImageExportDirectory));


      //Exports it is first section in the file by default (can it me in other order?)
      //Mb in packers/protectors, not sure
      //so I'm interested in the normal libraries
      //Stream.Read(PEExports, SizeOf(TImageSectionHeader));





      Result := True;
    finally
      FreeAndNil(Stream);
    end;
  except
    on E: Exception do
    begin
      SetErrorStr('An exception occured while loading file "' + sFile + '".' + #13#10 + 'Message: ' + E.Message);
    end;
  end;
end;

Собственно я нахожу секцию в которой находится VirtualAddress каталога экспорта (IMAGE_DIRECTORY_ENTRY_EXPORT), но это ни разу не смещение в файле, а смещение в памяти.

Как RVA/VA конвертировать в File Offset?

ImageHlp, PsAPI и прочие JvPeImage и PE Image library for DElphi/Lazarus - не предлагать, по той простой причине, что код должен работать в Linux, а все указанное привязано к винде так или иначе, в т.ч. копипаста паскалевской функции ListDLLFunctions из интернетов.

Последний раз редактировалось Человек_Борща; 18.06.2018 в 21:04.
Человек_Борща вне форума   Ответить с цитированием
Старый 19.06.2018, 00:08   #2
waleri
Профессионал
 
Регистрация: 13.07.2012
Адрес: Нижний Новгород
Сообщений: 5,530
Репутация: 1728
По умолчанию

http://www.sunshine2k.de/reversing/tuts/tut_rvait.htm
waleri вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Преобразовать в общий формат amadeus017 Microsoft Office Excel 4 09.06.2017 10:05
Как преобразовать формат времени в числовой формат solnce60 Microsoft Office Excel 1 28.04.2013 11:16
Преобразовать формат String Ma4balaka Общие вопросы Delphi 2 21.11.2010 18:33
Как преобразовать в формат времени SergeyK Microsoft Office Excel 2 10.11.2010 15:14
БД аксесс преобразовать в формат SQL Ane4ka SQL, базы данных 2 26.05.2008 07:50


03:33.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru