From b38ea463aad8d8fc10a4a8dedd7f3abb66982445 Mon Sep 17 00:00:00 2001 From: bicarus <202771338+bicarus-dev@users.noreply.github.com> Date: Fri, 27 Mar 2026 02:34:56 -0700 Subject: [PATCH] utils: print out DLL metadata (#596) ## Link to GitHub Issue or related Pull Request, if one exists #592 ## Description of change * when custom DLLs are detected (`d3d9.dll`) print out some basic data from the PE header * for our own NVIDIA DLL stubs, add manifest files to identify ourselves * as a bonus, when DLL hooks are loaded from `-k`, print DLL info there as well This is mainly to detect when DXVK is in use. --- src/spice2x/CMakeLists.txt | 13 ++-- src/spice2x/launcher/launcher.cpp | 1 + src/spice2x/stubs/manifest.rc | 20 ++++++ src/spice2x/util/libutils.cpp | 107 +++++++++++++++++++++++++++++- src/spice2x/util/libutils.h | 2 + 5 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 src/spice2x/stubs/manifest.rc diff --git a/src/spice2x/CMakeLists.txt b/src/spice2x/CMakeLists.txt index 7f504b0..a2d7835 100644 --- a/src/spice2x/CMakeLists.txt +++ b/src/spice2x/CMakeLists.txt @@ -266,6 +266,7 @@ set_source_files_properties(cfg/manifest.rc PROPERTIES LANGUAGE RC) set_source_files_properties(cfg/icon.rc PROPERTIES LANGUAGE RC) set_source_files_properties(cfg/Win32D.rc PROPERTIES LANGUAGE RC) set_source_files_properties(build/manifest64.rc PROPERTIES LANGUAGE RC) +set_source_files_properties(stubs/manifest.rc PROPERTIES LANGUAGE RC) # sources ######### @@ -813,7 +814,8 @@ endif() # nvcuda.dll set(SOURCE_FILES stubs/nvcuda.cpp) -add_library(spicetools_stubs_nvcuda SHARED ${SOURCE_FILES} stubs/nvcuda.def) +set(RESOURCE_FILES stubs/manifest.rc) +add_library(spicetools_stubs_nvcuda SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/nvcuda.def) set_target_properties(spicetools_stubs_nvcuda PROPERTIES PREFIX "") set_target_properties(spicetools_stubs_nvcuda PROPERTIES OUTPUT_NAME "nvcuda") @@ -823,7 +825,8 @@ endif() # nvcuvid.dll set(SOURCE_FILES stubs/nvcuvid.cpp) -add_library(spicetools_stubs_nvcuvid SHARED ${SOURCE_FILES} stubs/nvcuvid.def) +set(RESOURCE_FILES stubs/manifest.rc) +add_library(spicetools_stubs_nvcuvid SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/nvcuvid.def) set_target_properties(spicetools_stubs_nvcuvid PROPERTIES PREFIX "") set_target_properties(spicetools_stubs_nvcuvid PROPERTIES OUTPUT_NAME "nvcuvid") @@ -833,7 +836,8 @@ endif() # nvEncodeAPI64.dll set(SOURCE_FILES stubs/nvEncodeAPI64.cpp) -add_library(spicetools_stubs_nvEncodeAPI64 SHARED ${SOURCE_FILES} stubs/nvEncodeAPI64.def) +set(RESOURCE_FILES stubs/manifest.rc) +add_library(spicetools_stubs_nvEncodeAPI64 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/nvEncodeAPI64.def) set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES PREFIX "") set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES OUTPUT_NAME "nvEncodeAPI64") @@ -843,7 +847,8 @@ endif() # cpusbxpkm.dll (32 bit) set(SOURCE_FILES stubs/cpusbxpkm.cpp) -add_library(spicetools_stubs_cpusbxpkm SHARED ${SOURCE_FILES} stubs/cpusbxpkm.def) +set(RESOURCE_FILES stubs/manifest.rc) +add_library(spicetools_stubs_cpusbxpkm SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/cpusbxpkm.def) set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES PREFIX "") set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES OUTPUT_NAME "cpusbxpkm") diff --git a/src/spice2x/launcher/launcher.cpp b/src/spice2x/launcher/launcher.cpp index 7842ce4..8fcd96b 100644 --- a/src/spice2x/launcher/launcher.cpp +++ b/src/spice2x/launcher/launcher.cpp @@ -2307,6 +2307,7 @@ int main_implementation(int argc, char *argv[]) { // load hooks for (auto &hook : game_hooks) { log_info("launcher", "loading hook DLL {}", hook); + libutils::print_dll_info(hook); HMODULE module; if (!(module = libutils::try_library(hook))) { log_warning("launcher", "failed to load hook {}: {}", hook, get_last_error_string()); diff --git a/src/spice2x/stubs/manifest.rc b/src/spice2x/stubs/manifest.rc new file mode 100644 index 0000000..8fddfaf --- /dev/null +++ b/src/spice2x/stubs/manifest.rc @@ -0,0 +1,20 @@ +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "SpiceTools" + VALUE "FileDescription", "SpiceTools DLL Stub" + VALUE "FileVersion", "1.0.0.0" + VALUE "ProductName", "SpiceTools DLL Stub" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/src/spice2x/util/libutils.cpp b/src/spice2x/util/libutils.cpp index fd31fe2..a8f66bf 100644 --- a/src/spice2x/util/libutils.cpp +++ b/src/spice2x/util/libutils.cpp @@ -9,6 +9,16 @@ #include "peb.h" #include "util/fileutils.h" #include "util/dependencies.h" +#include "util/unique_plain_ptr.h" + +#define DEBUG_VERBOSE 0 + +#if DEBUG_VERBOSE +#define log_debug(module, format_str, ...) logger::push( \ + LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY) +#else +#define log_debug(module, format_str, ...) +#endif std::filesystem::path libutils::module_file_name(HMODULE module) { std::wstring buf; @@ -361,11 +371,106 @@ void libutils::check_duplicate_dlls() { void libutils::warn_if_dll_exists(const std::string &file_name) { if (fileutils::file_exists(MODULE_PATH / file_name)) { log_info("libutils", "found user-supplied {} in modules directory", file_name); + libutils::print_dll_info(MODULE_PATH / file_name); return; } const auto &spice_bin_path = libutils::module_file_name(nullptr).parent_path(); if (fileutils::file_exists(spice_bin_path / file_name)) { log_info("libutils", "found user-supplied {} next to spice executable path", file_name); + libutils::print_dll_info(spice_bin_path / file_name); return; } -} \ No newline at end of file +} + +void libutils::print_dll_info(std::filesystem::path filename) { + DWORD handle; + const auto size = GetFileVersionInfoSizeA(filename.string().c_str(), &handle); + if (size == 0) { + log_debug( + "libutils", + "GetFileVersionInfoSizeA failed for {}: {}", + filename.filename().string(), + get_last_error_string()); + return; + } + + auto data = util::make_unique_plain(size); + if (!GetFileVersionInfoA(filename.string().c_str(), handle, size, data.get())) { + log_debug( + "libutils", + "GetFileVersionInfoA failed for {}: {}", + filename.filename().string(), + get_last_error_string()); + return; + } + + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + } *lpTranslate = nullptr; + + UINT cbTranslate = 0; + if (!VerQueryValueA(data.get(), "\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate)) { + log_debug( + "libutils", + "VerQueryValueA failed for {}: {}", + filename.filename().string(), + get_last_error_string()); + return; + } + if (cbTranslate == 0 || lpTranslate == nullptr) { + log_debug( + "libutils", + "VerQueryValueA returned invalid results for {}", + filename.filename().string()); + return; + } + + // pick language - prefer English + WORD lang = 0, codepage = 0; + for (UINT i = 0; i < cbTranslate / sizeof(*lpTranslate); i++) { + if (lpTranslate[i].wLanguage == 0x0409) { // en-us + lang = lpTranslate[i].wLanguage; + codepage = lpTranslate[i].wCodePage; + break; + } + } + if (lang == 0) { + lang = lpTranslate[0].wLanguage; + codepage = lpTranslate[0].wCodePage; + } + + // StringFileInfo helper + auto query_string = [&](const char* key) -> std::string { + std::string subBlock = fmt::format( + "\\StringFileInfo\\{:04x}{:04x}\\{}", + lang, codepage, key + ); + + char* value = nullptr; + UINT size_out = 0; + + if (VerQueryValueA(data.get(), subBlock.c_str(), (LPVOID*)&value, &size_out) && value) { + return value; + } + log_debug( + "libutils", + "VerQueryValueA({}) failed for {}: {}", + subBlock, + filename.filename().string(), + get_last_error_string()); + return ""; + }; + + const auto company_name = query_string("CompanyName"); + const auto product_name = query_string("ProductName"); + const auto version_str = query_string("FileVersion"); + + log_info( + "libutils", + "DLL info for {}: CompanyName = {}, ProductName = {}, Version = {}", + filename.filename().string(), + company_name.empty() ? "?" : company_name, + product_name.empty() ? "?" : product_name, + version_str.empty() ? "?" : version_str); +} diff --git a/src/spice2x/util/libutils.h b/src/spice2x/util/libutils.h index 305a603..0140756 100644 --- a/src/spice2x/util/libutils.h +++ b/src/spice2x/util/libutils.h @@ -77,4 +77,6 @@ namespace libutils { intptr_t rva2offset(const std::filesystem::path &path, intptr_t rva); intptr_t offset2rva(IMAGE_NT_HEADERS *nt_headers, intptr_t offset); intptr_t offset2rva(const std::filesystem::path &path, intptr_t offset); + + void print_dll_info(std::filesystem::path filename); }