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