potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C++&Win32 API モジュールハンドル(HMODULE)は実行可能ファイルのメモリマップトファイルアドレス

公式ドキュメントは確認していませんが、Windows NT系列ではモジュールハンドルHMODULEは実行可能ファイルのメモリマップトファイルアドレスらしいです。なので、GetModuleHandleLoadLibraryで取得したモジュールハンドルをchar型文字列にキャストすると最初の2文字はMZIMAGE_DOS_HEADERの最初のメンバー変数)で、PSAPIGetMappedFileName関数で実行ファイル名を取得できます。

#include <bit>
#include <string>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <Psapi.h>

constexpr std::wstring unpack_chars2_to_wstring_le(uint16_t x)
{
    return {
        static_cast<wchar_t>(x & 0xff),
        static_cast<wchar_t>((x >> 8) & 0xff)
    };
}

constexpr std::wstring unpack_chars4_to_wstring_le(uint32_t x)
{
    return {
        static_cast<wchar_t>(x & 0xff),
        static_cast<wchar_t>((x >> 8) & 0xff),
        static_cast<wchar_t>((x >> 16) & 0xff),
        static_cast<wchar_t>((x >> 24) & 0xff)
    };
}

#include <iostream>

int main()
{
    for (auto handle : {GetModuleHandleW(nullptr), LoadLibraryW(L"user32.dll")})
    {
        auto base{std::bit_cast<const PBYTE>(handle)};
        auto pimg_dos_hdr{std::bit_cast<const PIMAGE_DOS_HEADER>(base)};
        auto pimg_nt_hdrs_magic{std::bit_cast<const PDWORD>(base + pimg_dos_hdr->e_lfanew)};
        std::wcout << unpack_chars2_to_wstring_le(pimg_dos_hdr->e_magic).data() << std::endl; // MZ (IMAGE_DOS_SIGNATURE)
        std::wcout << unpack_chars4_to_wstring_le(*pimg_nt_hdrs_magic).data() << std::endl;   // PE\0\0 (IMAGE_NT_SIGNATURE)

        std::wstring sz(MAX_PATH - 1, '\0');
        ::GetMappedFileNameW(GetCurrentProcess(), handle, sz.data(), MAX_PATH);
        std::wcout << sz << std::endl;

        std::wcout << std::endl;
    }
}

constexprstd::bit_castを使わないコード

#include <string>
#include <iostream>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <Psapi.h>

inline auto conv_uint16_into_chars(uint16_t x) {
    return std::string(reinterpret_cast<const char* const>(&x), sizeof x);
}

inline auto conv_uint32_into_chars(uint32_t x) {
    return std::string(reinterpret_cast<const char* const>(&x), sizeof x);
}

int main()
{
    for (auto handle : { ::GetModuleHandleW(nullptr), ::LoadLibraryW(L"user32.dll") })
    {
        auto base = reinterpret_cast<const PBYTE>(handle);

        auto pimg_dos_hdr = reinterpret_cast<PIMAGE_DOS_HEADER>(base);
        auto pimg_nt_hdrs_magic = reinterpret_cast<PDWORD>(base + pimg_dos_hdr->e_lfanew);

        std::cout.setf(std::ios_base::boolalpha);
        std::cout << conv_uint16_into_chars(pimg_dos_hdr->e_magic) << std::endl; // MZ (IMAGE_DOS_SIGNATURE)
        std::cout << conv_uint32_into_chars(*pimg_nt_hdrs_magic) << std::endl;   // PE\0\0 (IMAGE_NT_SIGNATURE)

        std::wstring sz(MAX_PATH - 1, '\0');
        ::GetMappedFileNameW(GetCurrentProcess(), handle, sz.data(), MAX_PATH);
        std::wcout << sz << std::endl;

        std::wcout << std::endl;
    }
}

出力例(システムディレクトリと実行ファイルProject1.exeがHarddiskVolume2にある場合)

MZ
PE
\Device\HarddiskVolume2\...\Project1.exe

MZ
PE
\Device\HarddiskVolume2\Windows\System32\user32.dll

参考