From 4e4c85885ce5d828cde08c1663b794a5dabf4f4b Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Sat, 14 Jan 2023 14:35:27 +0100 Subject: [PATCH] Hack together shitty method to retrieve original unhooking bytes via GlosSIConfig Here's hoping that this will prevent access-violation issues for some users --- GlosSIConfig/GlosSIConfig.vcxproj | 5 +- GlosSIConfig/GlosSIConfig.vcxproj.filters | 3 + GlosSIConfig/UIModel.cpp | 36 +++++++++++ GlosSIConfig/UIModel.h | 2 + GlosSITarget/UnhookUtil.cpp | 79 ++++++++++++++++++++++- GlosSITarget/UnhookUtil.h | 5 ++ 6 files changed, 125 insertions(+), 5 deletions(-) diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj index f0c35bf..55a1b71 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj +++ b/GlosSIConfig/GlosSIConfig.vcxproj @@ -69,7 +69,7 @@ %(AdditionalUsingDirectories) /Zc:__cplusplus /Zc:twoPhase- %(AdditionalOptions) false - NOMINMAX;%(PreprocessorDefinitions) + NOMINMAX;CONFIGAPP;%(PreprocessorDefinitions) ..\deps\WinReg;..\deps\fifo_map\src;..\deps\Shortcuts_VDF\include;%(AdditionalIncludeDirectories) @@ -92,7 +92,7 @@ %(AdditionalUsingDirectories) /Zc:__cplusplus /Zc:zwoPhase- /permissive- %(AdditionalOptions) false - NOMINMAX;%(PreprocessorDefinitions) + NOMINMAX;CONFIGAPP;%(PreprocessorDefinitions) ..\deps\WinReg;..\deps\fifo_map\src;..\deps\Shortcuts_VDF\include;%(AdditionalIncludeDirectories) @@ -136,6 +136,7 @@ + diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters index 8999805..fc4e559 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj.filters +++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters @@ -37,6 +37,9 @@ Source Files + + Source Files + diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp index 51e3bce..4473065 100644 --- a/GlosSIConfig/UIModel.cpp +++ b/GlosSIConfig/UIModel.cpp @@ -36,6 +36,9 @@ limitations under the License. #include "ExeImageProvider.h" #include "../version.hpp" +#include "../../GlosSITarget/UnhookUtil.h" + + UIModel::UIModel() : QObject(nullptr) { wchar_t* localAppDataFolder; @@ -63,6 +66,7 @@ UIModel::UIModel() : QObject(nullptr) parseShortcutVDF(); readTargetConfigs(); updateCheck(); + readUnhookBytes(); auto font = QGuiApplication::font(); font.setPointSize(11); @@ -839,3 +843,35 @@ bool UIModel::isSteamInputXboxSupportEnabled() const } return true; } + +void UIModel::readUnhookBytes() const +{ + std::map unhook_bytes; + for (const auto& name : UnhookUtil::UNHOOK_BYTES_ORIGINAL_22000 | std::views::keys) { + auto bytes = UnhookUtil::ReadOriginalBytes( + name, + name.starts_with("Hid") + ? L"hid.dll" + : name.starts_with("Setup") + ? L"setupapi.dll" + : L"Kernel32.dll" + ); + unhook_bytes[name] = bytes; + } + auto path = config_path_; + path /= "unhook_bytes"; + QFile file(path); + if (!file.open(QIODevice::Truncate | QIODevice::ReadWrite)) { + qDebug() << "Couldn't open file for writing: " << path; + return; + } + + for (const auto& [name, bytes] : unhook_bytes) { + file.write( + QString::fromStdString(name + ":").toStdString().data() + ); + file.write(bytes.data(), bytes.size()); + file.write("\n"); + } + file.close(); +} diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h index 1813143..41d5779 100644 --- a/GlosSIConfig/UIModel.h +++ b/GlosSIConfig/UIModel.h @@ -131,4 +131,6 @@ class UIModel : public QObject { void parseShortcutVDF(); bool isSteamInputXboxSupportEnabled() const; + + void readUnhookBytes() const; }; diff --git a/GlosSITarget/UnhookUtil.cpp b/GlosSITarget/UnhookUtil.cpp index c37331d..e300a0c 100644 --- a/GlosSITarget/UnhookUtil.cpp +++ b/GlosSITarget/UnhookUtil.cpp @@ -15,12 +15,63 @@ limitations under the License. */ #include "UnhookUtil.h" +#ifndef CONFIGAPP #include #include "Settings.h" +#endif void UnhookUtil::UnPatchHook(const std::string& name, HMODULE module) { +#ifndef CONFIGAPP + + + std::map original_bytes_from_file; + + wchar_t* localAppDataFolder; + std::filesystem::path configDirPath; + if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) { + configDirPath = std::filesystem::temp_directory_path().parent_path().parent_path().parent_path(); + } + else { + configDirPath = std::filesystem::path(localAppDataFolder).parent_path(); + } + + configDirPath /= "Roaming"; + configDirPath /= "GlosSI"; + if (std::filesystem::exists(configDirPath)) { + auto unhook_file_path = configDirPath / "unhook_bytes"; + if (std::filesystem::exists(unhook_file_path)) { + + std::ifstream ifile; + ifile.open(unhook_file_path, std::ios::binary | std::ios::in); + if (ifile.is_open()) { + + std::string funcName; + char buff; + do { + if (ifile.eof()) { + break; + } + ifile.read(&buff, sizeof(char)); + if (buff != ':') { + funcName.push_back(buff); + } else { + char bytes[8]; + ifile.read(bytes, sizeof(char) * 8); + ifile.read(&buff, sizeof(char)); // newline + original_bytes_from_file[funcName] = std::string(bytes, 8); + funcName = ""; + } + } while (!ifile.eof()); + + ifile.close(); + } + } + } + + + spdlog::trace("Patching \"{}\"...", name); BYTE* address = reinterpret_cast(GetProcAddress(module, name.c_str())); @@ -28,11 +79,19 @@ void UnhookUtil::UnPatchHook(const std::string& name, HMODULE module) spdlog::error("failed to unpatch \"{}\"", name); } std::string bytes; - if (Settings::isWin10 && UNHOOK_BYTES_ORIGINAL_WIN10.contains(name)) { - bytes = UNHOOK_BYTES_ORIGINAL_WIN10.at(name); + + if (original_bytes_from_file.contains(name)) { + bytes = original_bytes_from_file.at(name); + spdlog::trace("Using originalBytes from file for {}", name); } else { - bytes = UNHOOK_BYTES_ORIGINAL_22000.at(name); + if (Settings::isWin10 && UNHOOK_BYTES_ORIGINAL_WIN10.contains(name)) { + bytes = UNHOOK_BYTES_ORIGINAL_WIN10.at(name); + } + else { + bytes = UNHOOK_BYTES_ORIGINAL_22000.at(name); + } + spdlog::trace("Using fallback originalBytes for {}", name); } DWORD dw_old_protect, dw_bkup; const auto len = bytes.size(); @@ -52,4 +111,18 @@ void UnhookUtil::UnPatchHook(const std::string& name, HMODULE module) spdlog::trace("Unpatched \"{}\"", name); } VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... +#endif +} + +std::string UnhookUtil::ReadOriginalBytes(const std::string& name, const std::wstring& moduleName) +{ + auto module = LoadLibraryW(moduleName.c_str()); + auto address = reinterpret_cast(GetProcAddress(module, name.c_str())); + std::string res; + res.resize(8); + + for (int i = 0; i < 8; i++) { + res[i] = static_cast(*(address + i)); + } + return res; } diff --git a/GlosSITarget/UnhookUtil.h b/GlosSITarget/UnhookUtil.h index f96a31b..04f2b33 100644 --- a/GlosSITarget/UnhookUtil.h +++ b/GlosSITarget/UnhookUtil.h @@ -25,6 +25,8 @@ limitations under the License. namespace UnhookUtil { void UnPatchHook(const std::string& name, HMODULE module); +std::string ReadOriginalBytes(const std::string& name, const std::wstring& moduleName); + static inline const std::vector JUMP_INSTR_OPCODES = { 0xE9, 0xE8, @@ -34,6 +36,9 @@ static inline const std::vector JUMP_INSTR_OPCODES = { // Valve Hooks various functions and hides Gaming devices like this. // To be able to query them, unpatch the hook with the original bytes... + +// Bytes here are just fallbacks; originalbytes will get read from GlosSIConfig and stored in %APPDATA%\GlosSI\unhook_bytes + // 22000 ^= Windows build number static inline const std::map UNHOOK_BYTES_ORIGINAL_22000 = { {"SetupDiEnumDeviceInfo", "\x48\x89\x5C\x24\x08"},