1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PEヘッダの静的解析

Posted at

PEヘッダを書き換える必要があって、初めてPEを静的に読みました。
LoadLibraryなんかで読み込んだPEヘッダをたぐるのと勝手が全然違ったのでメモメモします。

RVAを作成するときにセクションのVirtualAddressやデータディレクトリのVirtualAddressを足したり引いたりするところは数字が合うようにPEviewを見ながら書いたので何でこうなるのかさっぱり分かりません。どこかに資料が落ちてるといいんですが、ファイルのままのPEを詳しく解説したものは見つかりませんでした・・。

エラー処理は全て省いてあり、コマンドラインに適切なPE形式(PE or PE+)のファイルのフルパスが渡される前提です。エクスポートされている関数の名前を列挙します。

# include <cstdint>
# include <fstream>
# include <iostream>
# include <string>
# include <vector>

# include <Windows.h>

struct module
{
  union
  {
    std::uintptr_t base_addr;
    PIMAGE_DOS_HEADER pIDH;
    void* pointer;
  };
  module( std::uintptr_t base_addr ) : base_addr( base_addr ) {}
  module( void* pointer ) : pointer( pointer ) {}
  template < class Ty > // convert RelativeVirtualAddress to AbsoluteRealAddress
  Ty to_ara( DWORD rva ) const { return reinterpret_cast < Ty >( rva + base_addr ); }
};

int main( int argc, char** argv )
{
  std::cout << std::hex;

  std::ifstream fileDll( argv[1], std::ios::in | std::ios::binary );
  std::vector < char > binaryDll;

  for( ;;)
  { // load file into buffer
    char buffer;
    fileDll.read( &buffer, sizeof( buffer ) * 1 );
    if( fileDll.eof() ) { break; } // eof
    binaryDll.push_back( buffer );
  }
  module moduleDll( binaryDll.data() );
  PIMAGE_NT_HEADERS pINH = moduleDll.to_ara < PIMAGE_NT_HEADERS >( moduleDll.pIDH->e_lfanew );
  PIMAGE_OPTIONAL_HEADER pIOH = &pINH->OptionalHeader;
  PIMAGE_DATA_DIRECTORY pIDD = &pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
  //
  // PIMAGE_EXPORT_DIRECTORY pIED = moduleDll.to_ara < PIMAGE_EXPORT_DIRECTORY >( pIDD->VirtualAddress );
  // 通常はこれでエクスポート情報が利用できるが、これは
  // LoadLibrary等で読み込み、ローダがごにょごにょしてくれないと使えない
  //

  // セクションヘッダを列挙し、エクスポート情報(IMAGE_EXPORT_DIRECTORY)を探す
  PIMAGE_FILE_HEADER pIFH = &pINH->FileHeader;
  // セクションヘッダはNTヘッダのお尻についている
  PIMAGE_SECTION_HEADER pISH = reinterpret_cast < PIMAGE_SECTION_HEADER > ( pINH + 1 );
  PIMAGE_EXPORT_DIRECTORY pIED = nullptr;
  std::uintptr_t rva_to_ied = 0;

  // ここからよく分からない
  for( int i = 0; i < pIFH->NumberOfSections; ++i )
  {
    if( pISH[i].VirtualAddress + pISH[i].SizeOfRawData > pIDD->VirtualAddress )
    { // IEDが含まれたセクションを発見
      std::cout << "SECTION: " << pISH[i].Name << std::endl;
      // IEDへのRVAを作る
      rva_to_ied = pIDD->VirtualAddress - pISH[i].VirtualAddress + pISH[i].PointerToRawData;
      pIED = moduleDll.to_ara < PIMAGE_EXPORT_DIRECTORY >( rva_to_ied );
      break;
    }
  }
  // rva to name pointer table
  std::uintptr_t rva_to_npt = rva_to_ied + pIED->AddressOfNames - pIDD->VirtualAddress;
  DWORD* table_names = moduleDll.to_ara < DWORD* >( rva_to_npt );

  std::cout << std::endl << "** enum export functions **" << std::endl;
  for( DWORD i = 0; i < pIED->NumberOfNames; ++i )
  {
    std::uintptr_t rva_to_name = table_names[i];
    char* name = moduleDll.to_ara < char* >( rva_to_name - pIDD->VirtualAddress + rva_to_ied );
    std::cout << "NAME: " << name << std::endl;
  }
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?