概要
32ビット形式のPEファイルを生データとして解析してIMAGE_COR20_HEADER構造体を取得するサンプルコードです。実際にはIMAGE_COR20_HEADER構造体のメインであろうメタデータは今後の拡張に備えてフォーマット非公開なのでCLSID_CorMetaDataDispenserで公開されるクラスを使うべきだと思いますが、PEファイルを自力で解析するコードのメモとして。
コード
#define STRICT #include <Windows.h> #include <CorHdr.h> // PEファイルのRVAを含むセクションのIMAGE_SECTION_HEADERを返します。 const PIMAGE_SECTION_HEADER ImageSectionHeaderContainingRVA(LPCVOID Base, const IMAGE_NT_HEADERS32* NTHeaders, DWORD RVA) { // IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTORを含むセクションの探索 const PIMAGE_SECTION_HEADER SectionHeaders = IMAGE_FIRST_SECTION(NTHeaders); for (UINT i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++) { if (SectionHeaders[i].VirtualAddress <= RVA && RVA <= (SectionHeaders[i].VirtualAddress + SectionHeaders[i].SizeOfRawData)) { return SectionHeaders + i; } } return nullptr; } // PEファイルのRVAをVAに変換します。 LPCVOID ImageRVAToVA32(LPCVOID Base, const IMAGE_NT_HEADERS32* NTHeaders, DWORD RVA) { const PIMAGE_SECTION_HEADER SectionHeader = ImageSectionHeaderContainingRVA( Base, NTHeaders, RVA); if (SectionHeader == nullptr) return nullptr; return ((LPCBYTE)Base) + SectionHeader->PointerToRawData + (RVA - SectionHeader->VirtualAddress); } // ファイルが32ビットPE形式であればIMAGE_NT_HEADERS32のポインタを返します。 const PIMAGE_NT_HEADERS32 ImageCheckPE32(LPCVOID Base) { const PIMAGE_DOS_HEADER DOSHeader = (const PIMAGE_DOS_HEADER)Base; if (DOSHeader->e_magic != IMAGE_DOS_SIGNATURE) { return nullptr; } const PDWORD Signature = (const PDWORD)((LPCBYTE)Base + DOSHeader->e_lfanew); if (*Signature != IMAGE_NT_SIGNATURE) { return nullptr; } const PIMAGE_FILE_HEADER FileHeader = (const PIMAGE_FILE_HEADER)(Signature + 1); if (FileHeader->SizeOfOptionalHeader != sizeof IMAGE_OPTIONAL_HEADER32) { return nullptr; } const PIMAGE_OPTIONAL_HEADER32 OptionalHeader = (const PIMAGE_OPTIONAL_HEADER32)(FileHeader + 1); if (OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { return nullptr; } return (const PIMAGE_NT_HEADERS32)Signature; } #include <iostream> #include <iomanip> // 32ビットPEファイルのCLIヘッダー情報を表示します。 void main() { std::wcout.imbue(std::locale("ja")); // CLIヘッダーを確認する実行ファイルの場所 LPCWSTR path = <ファイル名を指定して下さい>; HANDLE FileHandle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (FileHandle == INVALID_HANDLE_VALUE) { std::wcout << L"ファイルハンドルが開けませんでした。" << std::endl; return; } HANDLE FileMapHandle = CreateFileMappingW(FileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr); if (FileMapHandle == nullptr) { std::wcout << L"ファイルマッピングオブジェクトが作成できませんでした。" << std::endl; return; } LPCBYTE Base = (LPCBYTE)MapViewOfFile(FileMapHandle, FILE_MAP_READ, 0, 0, 0); if (Base == nullptr) { std::wcout << L"ファイルマッピングオブジェクトのビューが作成できませんでした。" << std::endl; return; } const PIMAGE_NT_HEADERS32 NTHeaders = ImageCheckPE32(Base); if (ImageCheckPE32 == nullptr) { std::wcout << L"ファイルは32ビットPE形式ではありません。" << std::endl; return; } // IMAGE_COR2_HEADERはIMAGE_DIRECTORY_ENTRY_COM_DESCRIPTORに配置されます const PIMAGE_DATA_DIRECTORY ComDescDir = &NTHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; const PIMAGE_COR20_HEADER CorHeader = (const PIMAGE_COR20_HEADER)( ImageRVAToVA32(Base, NTHeaders, ComDescDir->VirtualAddress)); if (CorHeader == nullptr) { std::wcout << L"ファイルはCLIヘッダーを含みません。" << std::endl; return; } // CLIヘッダー情報の出力 std::wcout << L"IMAGE_COR20_HEADER" << std::endl; std::wcout << L"ランタイムのバージョン: " << CorHeader->MajorRuntimeVersion << L"." << CorHeader->MinorRuntimeVersion << std::endl; std::wcout << L"メタデータのサイズ: " << CorHeader->MetaData.Size << std::endl; std::wcout << L"フラグ: 0x" << std::hex << std::setfill(L'0') << std::setw(8) << CorHeader->Flags << std::endl; std::wcout << L"エントリーポイント: 0x" << std::hex << std::setfill(L'0') << std::setw(8) << CorHeader->EntryPointRVA << L" (" << (CorHeader->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT ? L"Native" : L"Managed") << L")" << std::endl; UnmapViewOfFile(Base); CloseHandle(FileMapHandle); CloseHandle(FileHandle); }
出力例
IMAGE_COR20_HEADER ランタイムのバージョン: 2.5 メタデータのサイズ: 4,772 フラグ: 0x00000001 エントリーポイント: 0x00000000 (Managed)