From ca0ca2e5a8a9fd6f1f79e628c7a7ceb59e7120bb Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 6 Dec 2022 00:19:42 +0300 Subject: [PATCH] ux/core: Add module verification step for some critical libraries - Prevents running the emu with downloaded dll files --- rpcs3/main.cpp | 13 ++++- rpcs3/module_verifier.hpp | 82 ++++++++++++++++++++++++++++ rpcs3/rpcs3.vcxproj | 1 + rpcs3/rpcs3.vcxproj.filters | 3 + rpcs3/rpcs3qt/fatal_error_dialog.cpp | 13 ++++- 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 rpcs3/module_verifier.hpp diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index 342b852952..f2829eee58 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -30,9 +30,10 @@ #include "Utilities/sema.h" #include "Crypto/decrypt_binaries.h" #ifdef _WIN32 -#include +#include "module_verifier.hpp" #include "util/dyn_lib.hpp" + // TODO(cjj19970505@live.cn) // When compiling with WIN32_LEAN_AND_MEAN definition // NTSTATUS is defined in CMake build but not in VS build @@ -410,6 +411,13 @@ void fmt_class_string + +#include +#include +#include + +[[noreturn]] void report_fatal_error(std::string_view); + +// Validates that system modules are properly installed +// Only relevant for WIN32 +class WIN32_module_verifier +{ + struct module_info_t + { + std::wstring_view name; + std::string_view package_name; + std::string_view dl_link; + }; + + const std::vector special_module_infos = { + { L"vulkan-1.dll", "Vulkan Runtime", "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-runtime.exe" }, + { L"msvcp140.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" }, + { L"vcruntime140.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" }, + { L"msvcp140_1.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" }, + { L"vcruntime140_1.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" } + }; + + // Unless we support ReactOS in future, this is a constant + const std::wstring_view system_root = L"C:\\WINDOWS\\"; + + // Inline impl. This class is only referenced once. + void run_module_verification() + { + for (const auto& module : special_module_infos) + { + const auto hModule = GetModuleHandle(module.name.data()); + if (hModule == NULL) + { + continue; + } + + WCHAR path[MAX_PATH]; + if (const auto len = GetModuleFileName(hModule, path, MAX_PATH)) + { + const std::wstring_view s = path; + if (s.find(system_root) != 0) + { + const auto error_message = fmt::format( + "The module '%s' was incorrectly installed.\n" + "This module is part of the '%s' package.\n" + "You can install this package from this URL:\n" + "%s", + wchar_to_utf8(module.name), + module.package_name, + module.dl_link, + module.dl_link + ); + report_fatal_error(error_message); + } + } + } + } + + WIN32_module_verifier() = default; + +public: + + static void run() + { + WIN32_module_verifier verifier{}; + verifier.run_module_verification(); + } +}; + +#endif // _WIN32 diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 98d2cb1549..1d95dcd361 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -884,6 +884,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 34169fbb58..2e2c9b8f42 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1037,6 +1037,9 @@ Io\evdev + + rpcs3 + diff --git a/rpcs3/rpcs3qt/fatal_error_dialog.cpp b/rpcs3/rpcs3qt/fatal_error_dialog.cpp index fff8500886..fadd530733 100644 --- a/rpcs3/rpcs3qt/fatal_error_dialog.cpp +++ b/rpcs3/rpcs3qt/fatal_error_dialog.cpp @@ -4,6 +4,17 @@ #include #include +static QString process_dialog_text(std::string_view text) +{ + auto html = Qt::convertFromPlainText(QString::fromUtf8(text.data(), text.size())); + + // Let's preserve some html elements destroyed by convertFromPlainText + const QRegExp link_re{ R"(<a\shref='([a-z0-9?=&#:\/\.\-]+)'>([a-z0-9?=&#:\/\.\-]+)<\/a>)", Qt::CaseSensitive, QRegExp::RegExp2}; + html = html.replace(link_re, "\\2"); + + return html; +} + fatal_error_dialog::fatal_error_dialog(std::string_view text) : QMessageBox() { #ifndef __APPLE__ @@ -20,7 +31,7 @@ fatal_error_dialog::fatal_error_dialog(std::string_view text) : QMessageBox() %3

)") - .arg(Qt::convertFromPlainText(QString::fromUtf8(text.data(), text.size()))) + .arg(process_dialog_text(text)) .arg(tr("HOW TO REPORT ERRORS:")) .arg(tr("Please, don't send incorrect reports. Thanks for understanding."))); layout()->setSizeConstraint(QLayout::SetFixedSize);