IMAGE_NT_HEADERS
IMAGE_DOS_HEADERの後に配置されている構造体がこの「IMAGE_NT_HEADERS」となります。
上記のIMAGE_DOS_HEADERのe_lfanewメンバを使用してアクセスが可能です。
ちなみにImageNtHeader()という関数で参照することも可能ですが、今回はあえて低レベルな方法でアクセスしていきます。
IMAGE_NT_HEADERS& tNT = (*(IMAGE_NT_HEADERS*)&(pFile[tDOS.e_lfanew]));
こちらの構造体は具体的には以下の様な定義をされています。
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
メンバ | |
---|---|
Signature | 固定の値「PE\0\0」が指定されている。IMAGE_NT_SIGNATUREとして定義。 |
FileHeader | COFFファイル(.objファイル)のヘッダ形式。実行環境等が確認できる。 |
IMAGE_OPTIONAL_HEADER | データ部分へのオフセットなどが登録されている構造体。 |
このIMAGE_NT_HEADERSですが、実は32bitと64bitでサイズが異なります。
通常はマクロで隠蔽されてしまっていますので意識しなくても良いのですが、今回は対象としているファイル側の環境に合わせる必要がありますので、チェックして対応してやる必要があります。
また今回はWindowsの実行ファイルの解析を目的としますので、この段階で対象のアーキテクチャなどを確認して絞り込みを行っておきます。
ちなみにIMAGE_FILE_HEADERまでは構造体のサイズは同じですので、最初はネイティブの構造体で読み込んでアーキテクチャを確認したところで32bitと64bitの処理を分岐させます。
以下は単純化したサンプルコードです。
IMAGE_NT_HEADERS& tNT = (*(IMAGE_NT_HEADERS*)&(pFile[tDOS.e_lfanew]));
if( tNT.FileHeader.Machine == IMAGE_FILE_MACHINE_I386 )
{
IMAGE_NT_HEADERS32& tNT32 = (*(IMAGE_NT_HEADERS32*)&(pFile[tDOS.e_lfanew]));
// 32bitバイナリ用の処理
}
else if( tNT.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 )
{
IMAGE_NT_HEADERS64& tNT64 = (*(IMAGE_NT_HEADERS64*)&(pFile[tDOS.e_lfanew]));
// 64bitバイナリ用の処理
}
else
{
return false;
}
次はIMAGE_OPTIONAL_HEADERの解析を行います。