RvaToRawおよびRawToRva関数の開発

記事の目的



この記事の目的は、RvaToRaw / RawToRva関数の開発におけるニュアンスを示すことです。これは、PE実行可能ファイルを操作するシステムユーティリティにとって重要です。



この記事の対象は誰ですか?







用語





RVA-これは英語の略語です。 相対仮想アドレスという語であり、モジュールの実際のロードアドレスまたは推定ロードアドレスの先頭からのバイト単位のオフセットを意味します。

RAW-ファイルの先頭からのファイルオフセット。 もう1つの良い名前は「ファイルオフセット」です。



開発



Googleで「rva to raw」または「rva to offset」というキーワードを検索すると、次のコードに出くわすことがあります。

DWORD RVAToOffset(IMAGE_NT_HEADERS32* pNtHdr, DWORD dwRVA) { int i; WORD wSections; PIMAGE_SECTION_HEADER pSectionHdr; /* Map first section */ pSectionHdr = IMAGE_FIRST_SECTION(pNtHdr); wSections = pNtHdr->FileHeader.NumberOfSections; for (i = 0; i < wSections; i++) { if (pSectionHdr->VirtualAddress <= dwRVA) if ((pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize) > dwRVA) { dwRVA -= pSectionHdr->VirtualAddress; dwRVA += pSectionHdr->PointerToRawData; return (dwRVA); } pSectionHdr++; } return (-1); }
      
      







コードにはいくつかの重大なエラーがあり、非常に人気があります。



それは考慮されません:





著者の観点からのより正しいコード:



オフセットオフセットクラスと住所コード
 inline uint32_t alignDown(uint32_t value_, uint32_t factor) { return value_ & ~(factor-1); } inline uint32_t alignUp(uint32_t value_, uint32_t factor) { return alignDown(value_ - 1, factor) + factor; } class Aligner { public: const uint32_t FORCED_FILE_ALIGNMENT = 0x200; const uint32_t MIN_SECTION_ALIGNMENT = 0x1000; public: Aligner(uint32_t fileAlignment_, uint32_t sectionAlignement_) : fileAlignment(fileAlignment_) , sectionAlignement(sectionAlignement_) { } uint32_t getVirtualSize(uint32_t size) { return needAlign(sectionAlignement) ? alignUp(size, sectionAlignement) : size; } uint32_t getVirtualAddress(uint32_t address) { return needAlign(sectionAlignement) ? alignDown(address, sectionAlignement) : address; } uint32_t getFileOffset(uint32_t offset) { return needAlign(sectionAlignement) ? alignDown(offset, FORCED_FILE_ALIGNMENT) : offset; } uint32_t getSectionSize(const ImgSectionHeader& header) { uint32_t fileSize = header.SizeOfRawData; uint32_t virtualSize = header.Misc.VirtualSize; if (needAlign(sectionAlignement)) { fileSize = alignUp(fileSize, fileAlignment); virtualSize = alignUp(virtualSize, sectionAlignement); } return std::min(fileSize, virtualSize); } private: uint32_t fileAlignment; uint32_t sectionAlignement; bool needAlign(uint32_t sectionAlignement) { return sectionAlignement >= MIN_SECTION_ALIGNMENT; } };
      
      









RvaをRawに変換するメソッドコード
 const uint32_t numInvalidRaw = (uint32_t)( -1 ); uint32_t PeUtils::RvaToRaw( const PeImage& peImage, uint32_t rva ) { uint32_t result = INVALID_RAW; const auto& optionalHeader = peImage.NtHeaders.OptionalHeader; if (rva < optionalHeader.SizeOfHeaders) return rva; Aligner aligner(optionalHeader.FileAlignment, optionalHeader.SectionAlignment); if (peImage.NtHeaders.FileHeader.NumberOfSections > 0) { for (const auto& section : peImage.Sections) { if (section.PointerToRawData == 0) continue; auto sectionStart = aligner.getVirtualAddress(section.VirtualAddress); auto sectionSize = aligner.getSectionSize(section); auto sectionEnd = sectionStart + sectionSize; if (sectionStart <= rva && rva < sectionEnd) { auto sectionOffset = aligner.getFileOffset(section.PointerToRawData); sectionOffset += (rva - sectionStart); if (sectionOffset < peImage.SizeOfFileImage) result = sectionOffset; } } // for } else if (rva < aligner.getVirtualSize(optionalHeader.SizeOfImage)) { result = rva; } return result; }
      
      









改善点:





Nota bene:

実際、これでも最終バージョンではありませんが、システムローダーがそのようなファイルを理解する方法に近いです。



テスト中



実行可能ファイルのテストセットを作成し、RvaToRaw \ RawToRvaをこのセットに対して定期的にチェックします。このセットは、リファクタリングまたはバグ修正後に変更される可能性があります。



テストファイルを取得する方法:

  1. 標準以下のヘッダーを作成できる実行可能ファイルパッカーを適用します。 このようなパッカーの例はUpack.exeですが、他にもたくさんあります。
  2. MDLなど、悪意のあるファイルの新しいサンプルのコレクションを定期的に補充します(追加のソースを参照)




Nota bene:

リマインダーをおaびしますが、疑わしいファイルは、VMWareやVirtualBoxなどに基づくゲスト仮想マシンで実行するのが最適です。



Hiew、IDA Pro、またはデバッガを使用して、コードの正確性を確認することもできます。



追加のソース:



  1. #include <winnt.h>。 リーダーはMSVCに含まれているだけではありません。 このヘッダーは、このファイルのパーサーを作成する人のためのデスクトップ参照です。
  2. マット・ピトレック 「PEおよびCOFFオブジェクトファイルをフォーマットします。」 rsdn.ru/article/baseserv/pe_coff.xml
  3. マキシム・M・グメロフ。 「PEファイルローダー。」 rsdn.ru/article/baseserv/peloader.xml
  4. フォーラム>> IDA Pro >>#新しいPEローダーのバグと新しいcrack-me。 www.openrce.org/forums/posts/969
  5. MDL www.malwaredomainlist.com/mdl.php 疑わしいファイルのサンプルをダウンロードできるリソース




ポスト台本:




All Articles