More than 1 year has passed since last update.

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_HEADER 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)