diff --git a/GlosSITarget/AppLauncher.cpp b/GlosSITarget/AppLauncher.cpp index 0bbce32..a9f3066 100644 --- a/GlosSITarget/AppLauncher.cpp +++ b/GlosSITarget/AppLauncher.cpp @@ -30,6 +30,8 @@ limitations under the License. #include +#include "UnhookUtil.h" + AppLauncher::AppLauncher( std::vector& process_hwnds, std::function shutdown) : process_hwnds_(process_hwnds), shutdown_(std::move(shutdown)) @@ -175,32 +177,10 @@ void AppLauncher::getProcessHwnds() #ifdef _WIN32 void AppLauncher::UnPatchValveHooks() { - // TODO: move and re-use reusable unhook util from HidHide.cpp - spdlog::debug("Unpatching Valve CreateProcess hook..."); // need to load addresses that way.. Otherwise we may land before some jumps... auto kernel32dll = GetModuleHandle(L"kernel32.dll"); if (kernel32dll) { - BYTE* address = reinterpret_cast(GetProcAddress(kernel32dll, "CreateProcessW")); - if (address) { - DWORD dw_old_protect, dw_bkup; - const auto len = CREATE_PROC_ORIG_BYTES.size(); - VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &dw_old_protect); //Change permissions of memory.. - const auto opcode = *(address); - if (opcode != 0xE9 && opcode != 0xE8 && opcode != 0xEB && opcode != 0xEA && opcode != 0xFF) { - spdlog::debug("\"CreateProcessW\" Doesn't appear to be hooked, skipping!"); - VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... - } else { - for (DWORD i = 0; i < len; i++) // unpatch Valve's hook - { - *(address + i) = CREATE_PROC_ORIG_BYTES[i]; - } - VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... - spdlog::trace("Unpatched CreateProcessW"); - } - } - else { - spdlog::error("failed to unpatch CreateProcessW"); - } + UnhookUtil::UnPatchHook("CreateProcessW", kernel32dll); } else { spdlog::error("kernel32.dll not found... sure..."); diff --git a/GlosSITarget/AppLauncher.h b/GlosSITarget/AppLauncher.h index 5cf5091..6a0fbf0 100644 --- a/GlosSITarget/AppLauncher.h +++ b/GlosSITarget/AppLauncher.h @@ -45,10 +45,7 @@ class AppLauncher { std::vector& process_hwnds_; std::wstring launched_uwp_path_; - - // Valve also hooks "CreateProcess" - // Unpatch that so that launched programs don't also get hooked... - static inline const std::string CREATE_PROC_ORIG_BYTES = "\x4C\x8B\xDC\x48\x83"; + static void UnPatchValveHooks(); void launchWin32App(const std::wstring& path, const std::wstring& args = L""); void launchUWPApp(LPCWSTR package_full_name, const std::wstring& args = L""); diff --git a/GlosSITarget/GlosSITarget.vcxproj b/GlosSITarget/GlosSITarget.vcxproj index 2e4a2eb..37fcc86 100644 --- a/GlosSITarget/GlosSITarget.vcxproj +++ b/GlosSITarget/GlosSITarget.vcxproj @@ -194,6 +194,7 @@ + @@ -215,6 +216,7 @@ + diff --git a/GlosSITarget/GlosSITarget.vcxproj.filters b/GlosSITarget/GlosSITarget.vcxproj.filters index 1a54cea..a68cc6c 100644 --- a/GlosSITarget/GlosSITarget.vcxproj.filters +++ b/GlosSITarget/GlosSITarget.vcxproj.filters @@ -114,6 +114,9 @@ Source Files\tray + + Source Files + @@ -176,6 +179,9 @@ Header Files + + Header Files + diff --git a/GlosSITarget/HidHide.cpp b/GlosSITarget/HidHide.cpp index db5ab73..e0cb83f 100644 --- a/GlosSITarget/HidHide.cpp +++ b/GlosSITarget/HidHide.cpp @@ -36,6 +36,8 @@ limitations under the License. #include #include +#include "UnhookUtil.h" + // {D61CA365-5AF4-4486-998B-9DB4734C6CA3}add the XUSB class GUID as it is missing in the public interfaces DEFINE_GUID(GUID_DEVCLASS_XUSBCLASS, 0xD61CA365, 0x5AF4, 0x4486, 0x99, 0x8B, 0x9D, 0xB4, 0x73, 0x4C, 0x6C, 0xA3); // {EC87F1E3-C13B-4100-B5F7-8B84D54260CB} add the XUSB interface class GUID as it is missing in the public interfaces @@ -171,48 +173,18 @@ void HidHide::UnPatchValveHooks() spdlog::debug("Unpatching Valve HID hooks..."); // need to load addresses that way.. Otherwise we land before some jumps... if (const auto setupapidll = GetModuleHandle(L"setupapi.dll")) { - UnPatchHook("SetupDiEnumDeviceInfo", setupapidll); - UnPatchHook("SetupDiGetClassDevsW", setupapidll); + UnhookUtil::UnPatchHook("SetupDiEnumDeviceInfo", setupapidll); + UnhookUtil::UnPatchHook("SetupDiGetClassDevsW", setupapidll); } if (const auto hiddll = GetModuleHandle(L"hid.dll")) { - for (const auto& name : ORIGINAL_BYTES | std::views::keys) { + for (const auto& name : UnhookUtil::UNHOOK_BYTES_ORIGINAL_22000 | std::views::keys) { if (name.starts_with("Hid")) { - UnPatchHook(name, hiddll); + UnhookUtil::UnPatchHook(name, hiddll); } } } } -void HidHide::UnPatchHook(const std::string& name, HMODULE module) -{ - spdlog::trace("Patching \"{}\"...", name); - - BYTE* address = reinterpret_cast(GetProcAddress(module, name.c_str())); - if (!address) { - spdlog::error("failed to unpatch \"{}\"", name); - } - std::string bytes; - if (Settings::isWin10 && ORIGINAL_BYTES_WIN10.contains(name)) { - bytes = ORIGINAL_BYTES_WIN10.at(name); - } else { - bytes = ORIGINAL_BYTES.at(name); - } - DWORD dw_old_protect, dw_bkup; - const auto len = bytes.size(); - VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &dw_old_protect); // Change permissions of memory.. - const auto opcode = *(address); - if (!std::ranges::any_of(JUMP_INSTR_OPCODES, [&opcode](const auto& op) { return op == opcode; })) { - spdlog::debug("\"{}\" Doesn't appear to be hooked, skipping!", name); - VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... - return; - } - for (DWORD i = 0; i < len; i++) // unpatch Valve's hook - { - *(address + i) = bytes[i]; - } - VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... - spdlog::trace("Unpatched \"{}\"", name); -} void HidHide::enableOverlayElement() { diff --git a/GlosSITarget/HidHide.h b/GlosSITarget/HidHide.h index 1e3790e..e526afa 100644 --- a/GlosSITarget/HidHide.h +++ b/GlosSITarget/HidHide.h @@ -72,38 +72,7 @@ class HidHide { std::filesystem::path steam_path_; bool device_hiding_setup_ = false; - - // Valve Hooks various functions and hides Gaming devices like this. - // To be able to query them, unpatch the hook with the original bytes... - static inline const std::map ORIGINAL_BYTES = { - {"SetupDiEnumDeviceInfo", "\x48\x89\x5C\x24\x08"}, - {"SetupDiGetClassDevsW", "\x48\x89\x5C\x24\x08"}, - {"HidD_GetPreparsedData", "\x48\x89\x5C\x24\x18"}, - {"HidP_GetCaps", "\x4C\x8B\xD1\x48\x85\xC9"}, - {"HidD_GetAttributes", "\x40\x53\x48\x83\xEC"}, - {"HidD_GetProductString", "\x48\x83\xEC\x48\x48"}, - {"HidP_GetUsages", "\x4C\x89\x4C\x24\x20"}, - {"HidP_GetData", "\x4C\x89\x44\x24\x18"}, - {"HidP_GetValueCaps", "\x48\x83\xEC\x48\x49"}, - {"HidP_GetUsageValue", "\x40\x53\x55\x56\x48"}, - {"HidP_GetButtonCaps", "\x48\x83\xEC\x48\x49"}, - }; - - static inline const std::map ORIGINAL_BYTES_WIN10 = { - {"SetupDiEnumDeviceInfo", "\x40\x53\x56\x57\x41\x54\x41\x55"}, - {"SetupDiGetClassDevsW", "\x48\x8B\xC4\x48\x89\x58\x08"}, - }; - - static inline const std::vector JUMP_INSTR_OPCODES = { - 0xE9, - 0xE8, - 0xEB, - 0xEA, - 0xFF - }; - static void UnPatchValveHooks(); - static void UnPatchHook(const std::string& name, HMODULE module); void enableOverlayElement(); sf::Clock overlay_elem_clock_; diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index e5f1890..7706e63 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,0,9,1017003150580 - PRODUCTVERSION 0,0,9,1017003150580 + FILEVERSION 0,0,9,1025000308740 + PRODUCTVERSION 0,0,9,1025000308740 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - SteamTarget" - VALUE "FileVersion", "0.0.9.1-17-g315a58c" + VALUE "FileVersion", "0.0.9.1-25-gc3b874c" VALUE "InternalName", "GlosSITarget" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.0.9.1-17-g315a58c" + VALUE "ProductVersion", "0.0.9.1-25-gc3b874c" END END BLOCK "VarFileInfo" diff --git a/GlosSITarget/UnhookUtil.cpp b/GlosSITarget/UnhookUtil.cpp new file mode 100644 index 0000000..13a4c56 --- /dev/null +++ b/GlosSITarget/UnhookUtil.cpp @@ -0,0 +1,55 @@ +/* +Copyright 2021-2022 Peter Repukat - FlatspotSoftware + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "UnhookUtil.h" + +#include + +#include "Settings.h" + +void UnhookUtil::UnPatchHook(const std::string& name, HMODULE module) +{ + spdlog::trace("Patching \"{}\"...", name); + + BYTE* address = reinterpret_cast(GetProcAddress(module, name.c_str())); + if (!address) { + 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); + } + else { + bytes = UNHOOK_BYTES_ORIGINAL_22000.at(name); + } + DWORD dw_old_protect, dw_bkup; + const auto len = bytes.size(); + if (!VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &dw_old_protect)) { // Change permissions of memory.. + spdlog::error("Couldn't change permissions of memory for \"{}\"", name); + return; + } + const auto opcode = *(address); + if (!std::ranges::any_of(JUMP_INSTR_OPCODES, [&opcode](const auto& op) { return op == opcode; })) { + spdlog::debug("\"{}\" Doesn't appear to be hooked, skipping!", name); + } + else { + for (DWORD i = 0; i < len; i++) // unpatch Valve's hook + { + *(address + i) = bytes[i]; + } + spdlog::trace("Unpatched \"{}\"", name); + } + VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... +} diff --git a/GlosSITarget/UnhookUtil.h b/GlosSITarget/UnhookUtil.h new file mode 100644 index 0000000..55a5cbc --- /dev/null +++ b/GlosSITarget/UnhookUtil.h @@ -0,0 +1,61 @@ +/* +Copyright 2021-2022 Peter Repukat - FlatspotSoftware + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#pragma once + +#define NOMINMAX +#include +#include + +#include +#include + +namespace UnhookUtil { +void UnPatchHook(const std::string& name, HMODULE module); + +static inline const std::vector JUMP_INSTR_OPCODES = { + 0xE9, + 0xE8, + 0xEB, + 0xEA, + 0xFF}; + +// Valve Hooks various functions and hides Gaming devices like this. +// To be able to query them, unpatch the hook with the original bytes... +// 22000 ^= Windows build number +static inline const std::map UNHOOK_BYTES_ORIGINAL_22000 = { + {"SetupDiEnumDeviceInfo", "\x48\x89\x5C\x24\x08"}, + {"SetupDiGetClassDevsW", "\x48\x89\x5C\x24\x08"}, + {"HidD_GetPreparsedData", "\x48\x89\x5C\x24\x18"}, + {"HidP_GetCaps", "\x4C\x8B\xD1\x48\x85\xC9"}, + {"HidD_GetAttributes", "\x40\x53\x48\x83\xEC"}, + {"HidD_GetProductString", "\x48\x83\xEC\x48\x48"}, + {"HidP_GetUsages", "\x4C\x89\x4C\x24\x20"}, + {"HidP_GetData", "\x4C\x89\x44\x24\x18"}, + {"HidP_GetValueCaps", "\x48\x83\xEC\x48\x49"}, + {"HidP_GetUsageValue", "\x40\x53\x55\x56\x48"}, + {"HidP_GetButtonCaps", "\x48\x83\xEC\x48\x49"}, + // Valve hooks "CreateProcess" to detect child-processes + {"CreateProcessW", "\x4C\x8B\xDC\x48\x83"}, +}; + +// SetupApi.dll is different on Win10 than on Win11 +static inline const std::map UNHOOK_BYTES_ORIGINAL_WIN10 = { + {"SetupDiEnumDeviceInfo", "\x40\x53\x56\x57\x41\x54\x41\x55"}, + {"SetupDiGetClassDevsW", "\x48\x8B\xC4\x48\x89\x58\x08"}, +}; + + +} // namespace UnhookUtil