カテゴリ:リバースエンジニアリングバイブル
5章
PEヘッダについて 【基本】 .hをコンパイルすると.obj(機械語コード)が作られる。 .hをリンクさせると.exeファイルが作られる。 .exeは.objにPEヘッダとフッタがついたもの。 実行ファイルはメモリにロードされるときに、PEに含まれている情報を基にDLLをロードし、メモリ空間割り当てを行う。 PEはいくつかの構造体で構成されているが、その中で重要なものは以下の9個 IMAGE_DOS_HEADER IMAGE_NT_HEADER IMAGE_FILE_HEADER IMAGE_OPTIONAL_HEADER IMAGE_SECTION_HEADER IMAGE_IMPORT_DESCRIPTOR IMAGE_EXPORT_DIRECTORY IMAGE_IMPORT_BY_NAME IMAGE_THUNK_DATA32 以下で、上の5つのみ説明する。 【IMAGE_DOS_HEADER】 実行ファイルをBZとかで開いた時に見える最初の部分。 構造体のメンバが多いが、実際に使うのはe_magicとe_lfanewの2つだけ。 4D 5AはMZヘッダのマジックナンバー。これでMS-DOSのヘッダ開始位置やPEファイルであることを知ることが出来る。 e_lfanewはIMAGE_NT_HEADER構造体の位置を知るために使用される値。 【IMAGE_NT_HEADER】 SignatureというDWORD変数は、「PE\0\0」(50 45 00 00)を表示する4バイトの値である。 PEファイルであることを表示する以外に何もない。 昔はここに違う値が入っていてもexeが実行されたが、最近は実行されないようになっている。 【IMAGE_FILE_HEADER】 ファイル実行のための構造体 以下に重要なフィールドの説明を示す。 ・Machine このファイルがどのCPUで実行できるかを示す。 ・NumberOfSections セクションの数を示す。セクションとは.deta、.rsrcなどのコードセクションやデータセクションなどのこと。 ・TimeDateStamp このファイルをビルドした日付を示す。 Delphiでは常に1992年が表示される。 ・SizeOfOptionalHeader IMAGE_OPTIONAL_HEADER32の構造体の大きさを示す。 OSごとにサイズが異なる場合があるので先に大きさを確認しておく。 ・Characteristics ファイルの形式を示す。 【IMAGE_OPTIONAL_HEADER】 重要な値を多く持っている構造体 重要な値の説明を以下に示す。 ・Magic 目印みたいなもの。32bitは0x10B、64bitは0x20B ・SizeOfCode コード全体のサイズを示す。 ・MajorLinkerVersion、MinorLinkerVersion どのVerのコンパイラでビルドしたかを示す。 ・ImageBase ファイルが実行される際、実際の仮想メモリにロードされるアドレスを示す。 exeの場合はほとんど0x400000になる。dllは0x10000000 ・AddressOfEntryPoint 実行ファイルがメモリ上で実行を開始するアドレス(エントリポイント)。 ・BaseOfCode 実際のコードが実行されるアドレス。 ・SectionAlignment、FileAlignment 各セクションを整列するための保存単位。 ・SizeOfImage exe/dllがメモリにロードされた時の全体サイズ。 ・SizeOfHeaders PEヘッダのサイズを示す。 ・Subsystem このプログラムがGUI用かCUI用かを示す。 0x1:ドライバモジュール 0x2:Windows GUI 0x3:CUI ・DataDirectory IMAGE_DATA_DIRECTORYの構造体。VirtualAddressとSizeというフィールドを含む。 エクスポートディレクトリやIATなどの仮想アドレスとサイズが分かる。 【IMAGE_SECTION_HEADER】 各セクションの名前、開始アドレスやサイズなどの情報を管理する構造体 コードフッキングやAPIフッキングをするにはコードセクションの変更が必要。 通常、コードセクションはREAD属性だが、パックする場合はWRITE属性になる。 【エクスポートテーブル】 構造体の名前がエクスポートになっただけでインポートとほぼ同じ。 【PEとAPI呼び出しの仕組み】 dllがWin APIを呼び出す仕組みについて説明。 ・直接呼び出す場合 call命令直後のオペランドアドレスを利用してAPIの位置を呼び出す。 これは、OSごとに呼び出されるdllのアドレスが異なっていたりして、呼び出しアドレスを全て書き換えたりする必要があるので現実的でない。 ・IAT(Import Address Table)を使う dllの関数ポインタを集めたテーブル(IAT)を参照するようにする。 これにより、APIを何回呼び出しても全て同じテーブルを参照するので、APIを呼び出す場所に応じてコードセクションが変更されることはない。 お気に入りの記事を「いいね!」で応援しよう
最終更新日
2014.11.02 14:30:28
[リバースエンジニアリングバイブル] カテゴリの最新記事
|