diff --git a/tools/steamclient_loader/win/extra_protection/dllmain.cpp b/tools/steamclient_loader/win/extra_protection/dllmain.cpp index e274650e..180f653f 100644 --- a/tools/steamclient_loader/win/extra_protection/dllmain.cpp +++ b/tools/steamclient_loader/win/extra_protection/dllmain.cpp @@ -1,6 +1,5 @@ #include "pe_helpers/pe_helpers.hpp" -#include "extra_protection/stubdrm_v3.hpp" - +#include "extra_protection/stubdrm.hpp" BOOL APIENTRY DllMain( HMODULE hModule, @@ -10,13 +9,13 @@ BOOL APIENTRY DllMain( switch (reason) { case DLL_PROCESS_ATTACH: - stubdrm_v3::patch(); + stubdrm::patch(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: - stubdrm_v3::restore(); + stubdrm::restore(); break; } return TRUE; diff --git a/tools/steamclient_loader/win/extra_protection/extra_protection/stubdrm.hpp b/tools/steamclient_loader/win/extra_protection/extra_protection/stubdrm.hpp new file mode 100644 index 00000000..04da2728 --- /dev/null +++ b/tools/steamclient_loader/win/extra_protection/extra_protection/stubdrm.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +namespace stubdrm +{ + bool patch(); + + bool restore(); +} diff --git a/tools/steamclient_loader/win/extra_protection/extra_protection/stubdrm_v3.hpp b/tools/steamclient_loader/win/extra_protection/extra_protection/stubdrm_v3.hpp deleted file mode 100644 index cf48b355..00000000 --- a/tools/steamclient_loader/win/extra_protection/extra_protection/stubdrm_v3.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace stubdrm_v3 -{ - bool patch(); - - bool restore(); -} diff --git a/tools/steamclient_loader/win/extra_protection/stubdrm.cpp b/tools/steamclient_loader/win/extra_protection/stubdrm.cpp new file mode 100644 index 00000000..4caf46d8 --- /dev/null +++ b/tools/steamclient_loader/win/extra_protection/stubdrm.cpp @@ -0,0 +1,271 @@ +#include "pe_helpers/pe_helpers.hpp" +#include "common_helpers/common_helpers.hpp" +#include "extra_protection/stubdrm.hpp" +#include "detours/detours.h" +#include +#include +#include + +typedef struct SnrUnit { + std::string search_patt{}; + std::string replace_patt{}; +} SnrUnit_t; + +typedef struct SnrDetails { + std::string detection_patt{}; + std::vector snr_units{}; +} SnrDetails_t; + +// x64 +#if defined(_WIN64) + const std::vector snr_patts { + { + // detection_patt + "FF 94 24 ?? ?? ?? ?? 88 44 24 ?? 0F BE 44 24 ?? 83 ?? 30 74 ?? E9", + // snr_units + { + // patt 1 is a bunch of checks for registry + files validity (including custom DOS stub) + // patt 2 is again a bunch of checks + creates some interfaces via steamclient + calls getappownershipticket() + { + "E8 ?? ?? ?? ?? 84 C0 75 ?? B0 33 E9", + "B8 01 00 00 00 ?? ?? EB", + }, + { + "E8 ?? ?? ?? ?? 44 0F B6 ?? 3C 30 0F 84 ?? ?? ?? ?? 3C 35 0F 85 ?? ?? ?? ?? 8B ?? ?? FF 15", + "B8 30 00 00 00 ?? ?? ?? ?? ?? ?? 90 E9", + }, + }, + }, + + { + // detection_patt + "FF D? 44 0F B6 ?? 3C 30 0F 85", + // snr_units + { + { + "E8 ?? ?? ?? ?? 44 0F B6 ?? 3C 30 0F 84 ?? ?? ?? ?? 3C ?? 0F 85", + "B8 30 00 00 00 ?? ?? ?? ?? ?? ?? 90 E9 ?? ?? ?? ?? ?? ?? ?? ??", + }, + }, + }, + }; + +#endif + +// x32 +#if !defined(_WIN64) + + const std::vector snr_patts { + { + // detection_patt + "FF 95 ?? ?? ?? ?? 88 45 ?? 0F BE 4D ?? 83 ?? 30 74 ?? E9", + // snr_units + { + // patt 1 is a bunch of checks for registry + files validity (including custom DOS stub) + // patt 2 is again a bunch of checks + creates some interfaces via steamclient + calls getappownershipticket() + { + "5? 5? E8 ?? ?? ?? ?? 83 C4 08 84 C0 75 ?? B0 33", + "?? ?? B8 01 00 00 00 ?? ?? ?? ?? ?? EB", + }, + { + "E8 ?? ?? ?? ?? 83 C4 04 88 45 ?? 3C 30 0F 84 ?? ?? ?? ?? 3C 35 75 ?? 8B ?? ?? FF 15", + "B8 30 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 90 E9", + }, + }, + }, + + { + // detection_patt + "FF 95 ?? ?? ?? ?? 89 85 ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 8B ?? ?? 89 ?? ?? ?? ?? ?? 83 A5 ?? ?? ?? ?? ?? EB", + // snr_units + { + { + "F6 C? 02 0F 85 ?? ?? ?? ?? 5? FF ?? 6?", + "?? ?? ?? 90 E9 00 03", + }, + }, + }, + + { + // detection_patt + "FF D? 88 45 ?? 3C 30 0F 85 ?? ?? ?? ?? B8 4D 5A", + // snr_units + { + { + "5? E8 ?? ?? ?? ?? 83 C4 ?? 88 45 ?? 3C 30 0F 84", + "?? B8 30 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 90 E9", + }, + { + "5? E8 ?? ?? ?? ?? 8? ?? 83 C4 ?? 8? F? 30 74 ?? 8?", + "?? B8 30 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? EB", + }, + }, + }, + + }; + +#endif // _WIN64 + +const std::vector *current_snr_units = nullptr; + +static std::recursive_mutex mtx_win32_api{}; +static uint8_t *proc_addr_base = (uint8_t *)GetModuleHandleW(NULL); +static uint8_t *bind_addr_base = nullptr; +static uint8_t *bind_addr_end = nullptr; + +bool restore_win32_apis(); + +static void patch_if_possible(void *ret_addr) +{ + if (!ret_addr) return; + + auto page_details = pe_helpers::get_mem_page_details(ret_addr); + if (!page_details.BaseAddress || page_details.AllocationProtect != PAGE_READWRITE) return; + + bool anything_found = false; + for (const auto &snr_unit : *current_snr_units) { + auto mem = pe_helpers::search_memory( + (uint8_t *)page_details.BaseAddress, + page_details.RegionSize, + snr_unit.search_patt); + + if (mem) { + anything_found = true; + + auto size_until_match = (uint8_t *)mem - (uint8_t *)page_details.BaseAddress; + bool ok = pe_helpers::replace_memory( + (uint8_t *)mem, + page_details.RegionSize - size_until_match, + snr_unit.replace_patt, + GetCurrentProcess()); + // if (!ok) return; + } + } + + if (anything_found) { + restore_win32_apis(); + } + + // MessageBoxA(NULL, ("ret addr = " + std::to_string((size_t)ret_addr)).c_str(), "Patched", MB_OK); +} + +// https://learn.microsoft.com/en-us/cpp/intrinsics/addressofreturnaddress +static bool GetTickCount_hooked = false; +static decltype(GetTickCount) *actual_GetTickCount = GetTickCount; +__declspec(noinline) +static DWORD WINAPI GetTickCount_hook() +{ + std::lock_guard lk(mtx_win32_api); + + if (GetTickCount_hooked) { // american truck doesn't call GetModuleHandleA + void* *ret_ptr = (void**)_AddressOfReturnAddress(); + patch_if_possible(*ret_ptr); + } + + return actual_GetTickCount(); +} + +static bool GetModuleHandleA_hooked = false; +static decltype(GetModuleHandleA) *actual_GetModuleHandleA = GetModuleHandleA; +__declspec(noinline) +static HMODULE WINAPI GetModuleHandleA_hook( + LPCSTR lpModuleName +) +{ + std::lock_guard lk(mtx_win32_api); + + if (GetModuleHandleA_hooked && + lpModuleName && + common_helpers::ends_with_i(lpModuleName, "ntdll.dll")) { + void* *ret_ptr = (void**)_AddressOfReturnAddress(); + patch_if_possible(*ret_ptr); + } + + return actual_GetModuleHandleA(lpModuleName); +} + +static bool GetModuleHandleExA_hooked = false; +static decltype(GetModuleHandleExA) *actual_GetModuleHandleExA = GetModuleHandleExA; +__declspec(noinline) +static BOOL WINAPI GetModuleHandleExA_hook( + DWORD dwFlags, + LPCSTR lpModuleName, + HMODULE *phModule +) +{ + std::lock_guard lk(mtx_win32_api); + + if (GetModuleHandleExA_hooked && + (dwFlags == (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) && + ((uint8_t *)lpModuleName >= bind_addr_base && (uint8_t *)lpModuleName < bind_addr_end)) { + void* *ret_ptr = (void**)_AddressOfReturnAddress(); + patch_if_possible(*ret_ptr); + } + + return actual_GetModuleHandleExA(dwFlags, lpModuleName, phModule); +} + +static bool redirect_win32_apis() +{ + if (DetourTransactionBegin() != NO_ERROR) return false; + if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) return false; + + if (DetourAttach((PVOID *)&actual_GetTickCount, GetTickCount_hook) != NO_ERROR) return false; + if (DetourAttach((PVOID *)&actual_GetModuleHandleA, GetModuleHandleA_hook) != NO_ERROR) return false; + if (DetourAttach((PVOID *)&actual_GetModuleHandleExA, GetModuleHandleExA_hook) != NO_ERROR) return false; + bool ret = DetourTransactionCommit() == NO_ERROR; + if (ret) { + GetTickCount_hooked = true; + GetModuleHandleA_hooked = true; + GetModuleHandleExA_hooked = true; + } + return ret; +} + +static bool restore_win32_apis() +{ + GetTickCount_hooked = false; + GetModuleHandleA_hooked = false; + GetModuleHandleExA_hooked = false; + + if (DetourTransactionBegin() != NO_ERROR) return false; + if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) return false; + + DetourDetach((PVOID *)&actual_GetTickCount, GetTickCount_hook); + DetourDetach((PVOID *)&actual_GetModuleHandleA, GetModuleHandleA_hook); + DetourDetach((PVOID *)&actual_GetModuleHandleExA, GetModuleHandleExA_hook); + return DetourTransactionCommit() == NO_ERROR; +} + +bool stubdrm::patch() +{ + auto bind_section = pe_helpers::get_section_header_with_name(((HMODULE)proc_addr_base), ".bind"); + if (!bind_section) return false; // we don't have .bind section + + bind_addr_base = proc_addr_base + bind_section->VirtualAddress; + MEMORY_BASIC_INFORMATION mbi{}; + if (!VirtualQuery((LPVOID)bind_addr_base, &mbi, sizeof(mbi))) return false; + + bind_addr_end = bind_addr_base + mbi.RegionSize; + auto addrOfEntry = proc_addr_base + pe_helpers::get_optional_header((HMODULE)proc_addr_base)->AddressOfEntryPoint; + if (addrOfEntry < bind_addr_base || addrOfEntry >= bind_addr_end) return false; // entry addr is not inside .bind + + for (const auto &patt : snr_patts) { + auto mem = pe_helpers::search_memory( + bind_addr_base, + bind_section->Misc.VirtualSize, + patt.detection_patt); + + if (mem) { + current_snr_units = &patt.snr_units; + return redirect_win32_apis(); + } + } + + return false; +} + +bool stubdrm::restore() +{ + return restore_win32_apis(); +} diff --git a/tools/steamclient_loader/win/extra_protection/stubdrm_v3.cpp b/tools/steamclient_loader/win/extra_protection/stubdrm_v3.cpp deleted file mode 100644 index c8554d6e..00000000 --- a/tools/steamclient_loader/win/extra_protection/stubdrm_v3.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "pe_helpers/pe_helpers.hpp" -#include "common_helpers/common_helpers.hpp" -#include "extra_protection/stubdrm_v3.hpp" -#include "detours/detours.h" -#include -#include -#include -#include - -// patt 1 is a bunch of checks for registry + files validity (including custom DOS stub) -// patt 2 is again a bunch of checks + creates some interfaces via steamclient + calls getappownershipticket() -#ifdef _WIN64 - const static std::string stub_detection_patt_v31 = "FF 94 24 ?? ?? ?? ?? 88 44 24 ?? 0F BE 44 24 ?? 83 ?? 30 74 ?? E9"; - - const static std::string stub_search_patt_1_v31 = "E8 ?? ?? ?? ?? 84 C0 75 ?? B0 33 E9"; - const static std::string stub_replace_patt_1_v31 = "B8 01 00 00 00 ?? ?? EB"; - - const static std::string stub_search_patt_2_v31 = "E8 ?? ?? ?? ?? 44 0F B6 ?? 3C 30 0F 84 ?? ?? ?? ?? 3C 35 0F 85 ?? ?? ?? ?? 8B ?? ?? FF 15"; - const static std::string stub_replace_patt_2_v31 = "B8 30 00 00 00 ?? ?? ?? ?? ?? ?? 90 E9"; -#else // _WIN64 - const static std::string stub_detection_patt_v31 = "FF 95 ?? ?? ?? ?? 88 45 ?? 0F BE 4D ?? 83 ?? 30 74 ?? E9"; - - const static std::string stub_search_patt_1_v31 = "5? 5? E8 ?? ?? ?? ?? 83 C4 08 84 C0 75 ?? B0 33"; - const static std::string stub_replace_patt_1_v31 = "?? ?? B8 01 00 00 00 ?? ?? ?? ?? ?? EB"; - - const static std::string stub_search_patt_2_v31 = "E8 ?? ?? ?? ?? 83 C4 04 88 45 ?? 3C 30 0F 84 ?? ?? ?? ?? 3C 35 75 ?? 8B ?? ?? FF 15"; - const static std::string stub_replace_patt_2_v31 = "B8 30 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 90 E9"; -#endif // _WIN64 - - -static std::recursive_mutex mtx_win32_api{}; -static uint8_t *proc_addr_base = (uint8_t *)GetModuleHandleW(NULL); -static uint8_t *bind_addr_base = nullptr; -static uint8_t *bind_addr_end = nullptr; - -bool restore_win32_apis(); - -static void patch_if_possible(void *ret_addr) -{ - if (!ret_addr) return; - auto page_details = pe_helpers::get_mem_page_details(ret_addr); - if (!page_details.BaseAddress || page_details.AllocationProtect != PAGE_READWRITE) return; - - auto mem = pe_helpers::search_memory( - (uint8_t *)page_details.BaseAddress, - page_details.RegionSize, - stub_search_patt_1_v31); - if (!mem) return; - - auto size_until_match = (uint8_t *)mem - (uint8_t *)page_details.BaseAddress; - bool ok = pe_helpers::replace_memory( - (uint8_t *)mem, - page_details.RegionSize - size_until_match, - stub_replace_patt_1_v31, - GetCurrentProcess()); - if (!ok) return; - - mem = pe_helpers::search_memory( - (uint8_t *)page_details.BaseAddress, - page_details.RegionSize, - stub_search_patt_2_v31); - if (!mem) return; - - size_until_match = (uint8_t *)mem - (uint8_t *)page_details.BaseAddress; - pe_helpers::replace_memory( - (uint8_t *)mem, - page_details.RegionSize - size_until_match, - stub_replace_patt_2_v31, - GetCurrentProcess()); - - restore_win32_apis(); - - // MessageBoxA(NULL, ("ret addr = " + std::to_string((size_t)ret_addr)).c_str(), "Patched", MB_OK); - -} - -// https://learn.microsoft.com/en-us/cpp/intrinsics/addressofreturnaddress -static bool GetTickCount_hooked = false; -static decltype(GetTickCount) *actual_GetTickCount = GetTickCount; -__declspec(noinline) -static DWORD WINAPI GetTickCount_hook() -{ - std::lock_guard lk(mtx_win32_api); - - if (GetTickCount_hooked) { // american truck doesn't call GetModuleHandleA - void* *ret_ptr = (void**)_AddressOfReturnAddress(); - patch_if_possible(*ret_ptr); - } - - return actual_GetTickCount(); -} - -static bool GetModuleHandleA_hooked = false; -static decltype(GetModuleHandleA) *actual_GetModuleHandleA = GetModuleHandleA; -__declspec(noinline) -static HMODULE WINAPI GetModuleHandleA_hook( - LPCSTR lpModuleName -) -{ - std::lock_guard lk(mtx_win32_api); - - if (GetModuleHandleA_hooked && - lpModuleName && - common_helpers::ends_with_i(lpModuleName, "ntdll.dll")) { - void* *ret_ptr = (void**)_AddressOfReturnAddress(); - patch_if_possible(*ret_ptr); - } - - return actual_GetModuleHandleA(lpModuleName); -} - -static bool GetModuleHandleExA_hooked = false; -static decltype(GetModuleHandleExA) *actual_GetModuleHandleExA = GetModuleHandleExA; -__declspec(noinline) -static BOOL WINAPI GetModuleHandleExA_hook( - DWORD dwFlags, - LPCSTR lpModuleName, - HMODULE *phModule -) -{ - std::lock_guard lk(mtx_win32_api); - - if (GetModuleHandleExA_hooked && - (dwFlags == (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) && - ((uint8_t *)lpModuleName >= bind_addr_base && (uint8_t *)lpModuleName < bind_addr_end)) { - void* *ret_ptr = (void**)_AddressOfReturnAddress(); - patch_if_possible(*ret_ptr); - } - - return actual_GetModuleHandleExA(dwFlags, lpModuleName, phModule); -} - -static bool redirect_win32_apis() -{ - if (DetourTransactionBegin() != NO_ERROR) return false; - if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) return false; - - if (DetourAttach((PVOID *)&actual_GetTickCount, GetTickCount_hook) != NO_ERROR) return false; - if (DetourAttach((PVOID *)&actual_GetModuleHandleA, GetModuleHandleA_hook) != NO_ERROR) return false; - if (DetourAttach((PVOID *)&actual_GetModuleHandleExA, GetModuleHandleExA_hook) != NO_ERROR) return false; - bool ret = DetourTransactionCommit() == NO_ERROR; - if (ret) { - GetTickCount_hooked = true; - GetModuleHandleA_hooked = true; - GetModuleHandleExA_hooked = true; - } - return ret; -} - -static bool restore_win32_apis() -{ - GetTickCount_hooked = false; - GetModuleHandleA_hooked = false; - GetModuleHandleExA_hooked = false; - - if (DetourTransactionBegin() != NO_ERROR) return false; - if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR) return false; - - DetourDetach((PVOID *)&actual_GetTickCount, GetTickCount_hook); - DetourDetach((PVOID *)&actual_GetModuleHandleA, GetModuleHandleA_hook); - DetourDetach((PVOID *)&actual_GetModuleHandleExA, GetModuleHandleExA_hook); - return DetourTransactionCommit() == NO_ERROR; -} - -bool stubdrm_v3::patch() -{ - auto bind_section = pe_helpers::get_section_header_with_name(((HMODULE)proc_addr_base), ".bind"); - if (!bind_section) return false; // we don't have .bind section - - bind_addr_base = proc_addr_base + bind_section->VirtualAddress; - MEMORY_BASIC_INFORMATION mbi{}; - if (!VirtualQuery((LPVOID)bind_addr_base, &mbi, sizeof(mbi))) return false; - - bind_addr_end = bind_addr_base + mbi.RegionSize; - auto addrOfEntry = proc_addr_base + pe_helpers::get_optional_header((HMODULE)proc_addr_base)->AddressOfEntryPoint; - if (addrOfEntry < bind_addr_base || addrOfEntry >= bind_addr_end) return false; // entry addr is not inside .bind - - auto mem = pe_helpers::search_memory( - bind_addr_base, - bind_section->Misc.VirtualSize, - stub_detection_patt_v31); - if (!mem) return false; // known sequence of code wasn't found - - return redirect_win32_apis(); -} - -bool stubdrm_v3::restore() -{ - return restore_win32_apis(); -}