diff --git a/Dalamud.Boot/hooks.cpp b/Dalamud.Boot/hooks.cpp index 2619ffa72..7cf489195 100644 --- a/Dalamud.Boot/hooks.cpp +++ b/Dalamud.Boot/hooks.cpp @@ -103,8 +103,23 @@ void hooks::getprocaddress_singleton_import_hook::initialize() { LdrRegisterDllNotification(0, [](ULONG notiReason, const LDR_DLL_NOTIFICATION_DATA* pData, void* context) { if (notiReason == LDR_DLL_NOTIFICATION_REASON_LOADED) { const auto dllName = unicode::convert(pData->Loaded.FullDllName->Buffer); - logging::I(R"({} "{}" has been loaded at 0x{:X} ~ 0x{:X} (0x{:X}); finding import table items to hook.)", - LogTag, dllName, + + utils::loaded_module mod(pData->Loaded.DllBase); + std::wstring version, description; + try { + version = utils::format_file_version(mod.get_file_version()); + } catch (...) { + version = L""; + } + + try { + description = mod.get_description(); + } catch (...) { + description = L""; + } + + logging::I(R"({} "{}" ("{}" ver {}) has been loaded at 0x{:X} ~ 0x{:X} (0x{:X}); finding import table items to hook.)", + LogTag, dllName, description, version, reinterpret_cast(pData->Loaded.DllBase), reinterpret_cast(pData->Loaded.DllBase) + pData->Loaded.SizeOfImage, pData->Loaded.SizeOfImage); diff --git a/Dalamud.Boot/utils.cpp b/Dalamud.Boot/utils.cpp index b487f398b..62b436aa2 100644 --- a/Dalamud.Boot/utils.cpp +++ b/Dalamud.Boot/utils.cpp @@ -143,6 +143,69 @@ void* utils::loaded_module::get_imported_function_pointer(const char* pcszDllNam throw std::runtime_error(std::format("Failed to find import for {}!{} ({}).", pcszDllName, pcszFunctionName ? pcszFunctionName : "", hintOrOrdinal)); } +std::unique_ptr, decltype(&FreeResource)> utils::loaded_module::get_resource(LPCWSTR lpName, LPCWSTR lpType) const { + const auto hres = FindResourceW(m_hModule, lpName, lpType); + if (!hres) + throw std::runtime_error("No such resource"); + + const auto hRes = LoadResource(m_hModule, hres); + if (!hRes) + throw std::runtime_error("LoadResource failure"); + + return {hRes, &FreeResource}; +} + +std::wstring utils::loaded_module::get_description() const { + const auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + const auto pBlock = LockResource(rsrc.get()); + + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + } * lpTranslate; + UINT cbTranslate; + if (!VerQueryValueW(pBlock, + TEXT("\\VarFileInfo\\Translation"), + reinterpret_cast(&lpTranslate), + &cbTranslate)) { + throw std::runtime_error("Invalid version information (1)"); + } + + for (size_t i = 0; i < (cbTranslate / sizeof(LANGANDCODEPAGE)); i++) { + wchar_t* buf = nullptr; + UINT size = 0; + if (!VerQueryValueW(pBlock, + std::format(L"\\StringFileInfo\\{:04x}{:04x}\\FileDescription", + lpTranslate[i].wLanguage, + lpTranslate[i].wCodePage).c_str(), + reinterpret_cast(&buf), + &size)) { + continue; + } + auto currName = std::wstring_view(buf, size); + while (!currName.empty() && currName.back() == L'\0') + currName = currName.substr(0, currName.size() - 1); + if (currName.empty()) + continue; + return std::wstring(currName); + } + + throw std::runtime_error("Invalid version information (2)"); +} + +VS_FIXEDFILEINFO utils::loaded_module::get_file_version() const { + const auto rsrc = get_resource(MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + const auto pBlock = LockResource(rsrc.get()); + UINT size = 0; + LPVOID lpBuffer = nullptr; + if (!VerQueryValueW(pBlock, L"\\", &lpBuffer, &size)) + throw std::runtime_error("Failed to query version information."); + const VS_FIXEDFILEINFO& versionInfo = *static_cast(lpBuffer); + if (versionInfo.dwSignature != 0xfeef04bd) + throw std::runtime_error("Invalid version info found."); + return versionInfo; +} + utils::loaded_module utils::loaded_module::current_process() { return { GetModuleHandleW(nullptr) }; } @@ -163,6 +226,26 @@ std::vector utils::loaded_module::all_modules() { return modules; } +std::wstring utils::format_file_version(const VS_FIXEDFILEINFO& v) { + if (v.dwFileVersionMS == v.dwProductVersionMS && v.dwFileVersionLS == v.dwProductVersionLS) { + return std::format(L"{}.{}.{}.{}", + (v.dwProductVersionMS >> 16) & 0xFFFF, + (v.dwProductVersionMS >> 0) & 0xFFFF, + (v.dwProductVersionLS >> 16) & 0xFFFF, + (v.dwProductVersionLS >> 0) & 0xFFFF); + } else { + return std::format(L"file={}.{}.{}.{} prod={}.{}.{}.{}", + (v.dwFileVersionMS >> 16) & 0xFFFF, + (v.dwFileVersionMS >> 0) & 0xFFFF, + (v.dwFileVersionLS >> 16) & 0xFFFF, + (v.dwFileVersionLS >> 0) & 0xFFFF, + (v.dwProductVersionMS >> 16) & 0xFFFF, + (v.dwProductVersionMS >> 0) & 0xFFFF, + (v.dwProductVersionLS >> 16) & 0xFFFF, + (v.dwProductVersionLS >> 0) & 0xFFFF); + } +} + utils::signature_finder& utils::signature_finder::look_in(const void* pFirst, size_t length) { if (length) m_ranges.emplace_back(std::span(reinterpret_cast(pFirst), length)); diff --git a/Dalamud.Boot/utils.h b/Dalamud.Boot/utils.h index ca350674a..1e29493b7 100644 --- a/Dalamud.Boot/utils.h +++ b/Dalamud.Boot/utils.h @@ -58,10 +58,16 @@ namespace utils { void* get_imported_function_pointer(const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal) const; template TFn** get_imported_function_pointer(const char* pcszDllName, const char* pcszFunctionName, uint32_t hintOrOrdinal) { return reinterpret_cast(get_imported_function_pointer(pcszDllName, pcszFunctionName, hintOrOrdinal)); } + [[nodiscard]] std::unique_ptr, decltype(&FreeResource)> get_resource(LPCWSTR lpName, LPCWSTR lpType) const; + [[nodiscard]] std::wstring get_description() const; + [[nodiscard]] VS_FIXEDFILEINFO get_file_version() const; + static loaded_module current_process(); static std::vector all_modules(); }; + std::wstring format_file_version(const VS_FIXEDFILEINFO& v); + class signature_finder { std::vector> m_ranges; std::vector m_patterns; diff --git a/Dalamud.Boot/xivfixes.cpp b/Dalamud.Boot/xivfixes.cpp index 338938fc1..c5cde28d3 100644 --- a/Dalamud.Boot/xivfixes.cpp +++ b/Dalamud.Boot/xivfixes.cpp @@ -26,7 +26,20 @@ void xivfixes::unhook_dll(bool bApply) { std::filesystem::path path; try { path = mod.path(); - logging::I("{} [{}/{}] Module 0x{:X} ~ 0x{:X} (0x{:X}): \"{}\"", LogTagW, i + 1, mods.size(), mod.address_int(), mod.address_int() + mod.image_size(), mod.image_size(), path.wstring()); + std::wstring version, description; + try { + version = utils::format_file_version(mod.get_file_version()); + } catch (...) { + version = L""; + } + + try { + description = mod.get_description(); + } catch (...) { + description = L""; + } + + logging::I(R"({} [{}/{}] Module 0x{:X} ~ 0x{:X} (0x{:X}): "{}" ("{}" ver {}))", LogTagW, i + 1, mods.size(), mod.address_int(), mod.address_int() + mod.image_size(), mod.image_size(), path.wstring(), description, version); } catch (const std::exception& e) { logging::W("{} [{}/{}] Module 0x{:X}: Failed to resolve path: {}", LogTag, i + 1, mods.size(), mod.address_int(), e.what()); return;