この記事の目的
Windowsの実行ファイル形式であるPEファイル(Portable Executable、EXE、DLL等)を直接解析、エクスポート関数、インポート関数、バージョン番号を取り出すことを目的とします。
PEファイルとは
PE(Portable Executable)ファイルとは、Windowsの実行ファイルで採用されているファイル構造。
Windowsで有名ではあるが、構造自体はOSには非依存のためLinuxカーネル等でも使用されています。
参考:Wikipedia「Portable Executable」
基礎知識
以下に解析していく上で最低限把握しておくべき基礎知識を解説しておきます。
相対仮想アドレス(RVA、Relative Virtual Address)
PEファイル内で各情報へアクセスする際、その位置を示す為にアドレス値を使用します。
このアドレスは「PEファイルが実行ファイルとしてメモリ上に読み込まれた先頭位置からの相対的なアドレス」を示していて、これを相対仮想アドレス(RVA、Relative Virtual Address)と呼びます。
長いので以後この値に関しては「RVA」もしくは「アドレス」と呼称します。
ファイルポインタ
今回はPEファイルを実行ファイルとしてメモリ上に読み込む(LoadLibrary等)のではなく、ファイルをBYTE単位のバイナリ情報として直接読み込んで解析していきます。
以後このバイナリ情報としての位置に関しては「ファイルポインタ」もしくは「ポインタ」と呼称します。
Memory Mapped File
ファイルをバイナリとして解析する際、seek等で読み込み位置を移動させてからメモリ上に読み込んだりすると微妙に手間がかかります。
一旦メモリ上に全て読み込むとそう言う手間は省けるのですが、こう言う時にはあたかもファイルをメモリの様に扱える「Memory Mapped File」という手法が便利です。
使い方は比較的簡単ですので、以下にサンプルコードを載せておきます。
CFile hFile;
hFile.Open( szFile , CFile::modeRead | CFile::typeBinary );
HANDLE hMapping = CreateFileMapping( hFile , NULL, PAGE_READONLY , 0 , 0 , 0 );
BYTE* pFile = (BYTE*)MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0);
//途中の処理
CloseHandle(hMapping);
これでpFile[]の添え字をファイルポインタとしてファイルの中身にアクセス出来る様になります。
次からは実際のファイルの解析に入っていきます。