From 4e4d3d7351fb1015c629d7ae295b49257714c57b Mon Sep 17 00:00:00 2001 From: anzz1 Date: Tue, 15 Aug 2023 02:39:33 +0300 Subject: [PATCH] FEAR stuff, SecuROM v7 guard Exit process instantly if SecuROM v7 is detected to prevent it from installing to your system --- dllmain.c | 56 ++++++++++++++++++++++++++++-- include/game_fear.h | 83 +++++++++++++++++++++++++++++++++++++++------ include/global.h | 65 +++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 12 deletions(-) diff --git a/dllmain.c b/dllmain.c index 2c0e953..8716d1c 100644 --- a/dllmain.c +++ b/dllmain.c @@ -103,6 +103,54 @@ HINTERNET __stdcall hk_InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, LPC return oInternetOpenUrlA(hInternet, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext); } +static char* securom_msg = "mshta.exe vbscript:Execute(\"msgbox \"\"Your game executable is infested with SecuROM.\"\" & chr(10) & \"\"Process was exit to prevent damage to your operating system.\"\",0,\"\"Notice\"\":close\")"; +__forceinline static int securom_check(HMODULE hModule) { + PIMAGE_DOS_HEADER img_dos_headers; + PIMAGE_NT_HEADERS img_nt_headers; + PIMAGE_SECTION_HEADER img_sec_header; + unsigned int n; + char path[512]; + char* p; + + if (GetModuleFileNameA(hModule, path, 511)) { + path[511] = 0; + p = __strrchr(path, '\\'); + if (p) { + __strcpy(++p, "disable_securom_guard.txt"); + if (FileExistsA(path)) + return 0; + } + } + + img_dos_headers = (PIMAGE_DOS_HEADER)GetModuleHandleA(0); + if (img_dos_headers->e_magic != IMAGE_DOS_SIGNATURE) + return 0; + img_nt_headers = (PIMAGE_NT_HEADERS)((size_t)img_dos_headers + img_dos_headers->e_lfanew); + if (img_nt_headers->Signature != IMAGE_NT_SIGNATURE) + return 0; + if (img_nt_headers->FileHeader.SizeOfOptionalHeader < 4) // OptionalHeader.Magic + return 0; + if (img_nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC || img_nt_headers->OptionalHeader.NumberOfRvaAndSizes < 2) + return 0; + + img_sec_header = (PIMAGE_SECTION_HEADER)((size_t)img_nt_headers + sizeof(img_nt_headers->Signature) + sizeof(img_nt_headers->FileHeader) + img_nt_headers->FileHeader.SizeOfOptionalHeader); + for (n = 0; n < img_nt_headers->FileHeader.NumberOfSections; n++, img_sec_header++) { + if (img_sec_header->Name && !__strncmp(img_sec_header->Name, ".securom", 8)) { + STARTUPINFO si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(STARTUPINFO)); + memset(&pi, 0, sizeof(PROCESS_INFORMATION)); + if(CreateProcessA(0, securom_msg, 0, 0, 0, 0, 0, 0, &si, &pi)) { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + ExitProcess(1); + return 1; + } + } + return 0; +} + static int initialized = 0; int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH && !initialized) { @@ -116,6 +164,10 @@ int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) { // Pin this module to memory GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, (LPCSTR)&p_DirectInput8Create, &hm); + // SecuROM guard + if (securom_check(hm)) + return 1; + // Load system directory to memory InitSysDir(); @@ -188,9 +240,9 @@ int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) { } else if (!__stricmp(p, "vietcong2.exe") || !__stricmp(p, "vc2ded.exe")) { // Vietcong 2 force_bind_ip = 0; patch_vc2(); - } else if (!__stricmp(p, "fearserver.exe")) { // FEAR (Server) + } else if (!__stricmp(p, "fearmp.exe") || !__stricmp(p, "fearserver.exe")) { // FEAR force_bind_ip = 0; - patch_fearserver(); + patch_fear(); } else if (!__stricmp(p, "fear2.exe")) { // FEAR 2 gs_replace_pubkey(0); } diff --git a/include/game_fear.h b/include/game_fear.h index 2095647..aef2db2 100644 --- a/include/game_fear.h +++ b/include/game_fear.h @@ -9,34 +9,97 @@ int __stdcall hk_bind(SOCKET s, struct sockaddr* addr, int namelen); LPHOSTENT __stdcall hk_gethostbyname(const char* name); +typedef HMODULE (__stdcall *LoadLibraryA_fn)(LPCSTR lpLibFileName); +LoadLibraryA_fn oLoadLibraryA = 0; +typedef DWORD (__stdcall *GetPrivateProfileStringA_fn)(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName); +GetPrivateProfileStringA_fn oGetPrivateProfileStringA = 0; + // TODO // -// client: -// not currently working with unmodified retail latest v1.08, as fearmp.exe is protected by SecuROM v7.24.0009 which fks us -// should work with securom removed, but untested -// // server: // server works fine when connected to internet and masterserver is online, but we still need to patch "Unable to use the selected network service" // error to allow offline LAN play // -__forceinline static void fearserver_hook_gs() { - HMODULE server = GetModuleHandleA("EngineServer.dll"); +DWORD __stdcall fear_hk_GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName) { + if (lpAppName && lpKeyName && !__strcmp(lpAppName, "FEAR") && !__strcmp(lpKeyName, "CDKey")) { + if (lpFileName && __strstr(lpFileName, "FEARCombat")) + __strcpy(lpReturnedString, "LER7-BAB6-JYX5-BYX6-6324"); // Generic MPFREE + else + __strcpy(lpReturnedString, "NAS3-XUS9-SER5-JET6-5558"); // Generic Retail + SetLastError(0); + return 24; + } + return oGetPrivateProfileStringA(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName); +} + +HMODULE __stdcall fear_hk_LoadLibraryA(LPCSTR lpLibFileName) { + HMODULE mod = 0; + const char* name = __strrchr(lpLibFileName, '\\'); + if (name) + name++; + else + name = lpLibFileName; + + // Disable PunkBuster + if (!__stricmp(name, "pbag.dll") || !__stricmp(name, "pbags.dll") || + !__stricmp(name, "pbcl.dll") || !__stricmp(name, "pbcls.dll") || + !__stricmp(name, "pbsv.dll")) { + SetLastError(ERROR_MOD_NOT_FOUND); + return 0; + } + + mod = oLoadLibraryA(lpLibFileName); + + // GameClient.dll is extracted to "%LOCALAPPDATA%\Temp\Gam????.tmp" from "FEARE_?.Arch00" + if (mod) { + name = GetModExpName(mod); + if (name && !__strcmp(name, "GameClient.dll")) { + if (oGetPrivateProfileStringA) + detour_iat_func(mod, "GetPrivateProfileStringA", (void*)fear_hk_GetPrivateProfileStringA, "kernel32.dll", 0, FALSE); + else + oGetPrivateProfileStringA = (GetPrivateProfileStringA_fn)detour_iat_func(mod, "GetPrivateProfileStringA", (void*)fear_hk_GetPrivateProfileStringA, "kernel32.dll", 0, FALSE); + } + } + return mod; +} + +LPHOSTENT __stdcall fear_hk_gethostbyname(const char* name) { + if (!__strcmp(name, "www.whatisfear.com")) + return ogethostbyname("motd.openspy.net"); + else + return hk_gethostbyname(name); +} + +__forceinline static void fear_hook_gs() { + HMODULE server; + + if (ogethostbyname) + detour_iat_func(0, "gethostbyname", (void*)fear_hk_gethostbyname, "wsock32.dll", 52, TRUE); + else + ogethostbyname = (gethostbyname_fn)detour_iat_func(0, "gethostbyname", (void*)fear_hk_gethostbyname, "wsock32.dll", 52, TRUE); + + server = GetModuleHandleA("EngineServer.dll"); if (server) { if (ogethostbyname) - detour_iat_func(server, "gethostbyname", (void*)hk_gethostbyname, "wsock32.dll", 52, TRUE); + detour_iat_func(server, "gethostbyname", (void*)fear_hk_gethostbyname, "wsock32.dll", 52, TRUE); else - ogethostbyname = (gethostbyname_fn)detour_iat_func(server, "gethostbyname", (void*)hk_gethostbyname, "wsock32.dll", 52, TRUE); + ogethostbyname = (gethostbyname_fn)detour_iat_func(server, "gethostbyname", (void*)fear_hk_gethostbyname, "wsock32.dll", 52, TRUE); if (obind) detour_iat_func(server, "bind", (void*)hk_bind, "wsock32.dll", 2, TRUE); else obind = (bind_fn)detour_iat_func(server, "bind", (void*)hk_bind, "wsock32.dll", 2, TRUE); } + + if (oLoadLibraryA) + detour_iat_func(0, "LoadLibraryA", (void*)fear_hk_LoadLibraryA, "kernel32.dll", 0, FALSE); + else + oLoadLibraryA = (LoadLibraryA_fn)detour_iat_func(0, "LoadLibraryA", (void*)fear_hk_LoadLibraryA, "kernel32.dll", 0, FALSE); } -static void patch_fearserver() { - fearserver_hook_gs(); +static void patch_fear() { + fear_hook_gs(); } #endif // __GAME_FEAR_H diff --git a/include/global.h b/include/global.h index 812d4e1..4fafdc3 100644 --- a/include/global.h +++ b/include/global.h @@ -74,6 +74,10 @@ __forceinline static char* __strncpy(char* dst, const char* src, unsigned int le dst[i] = 0; return dst; } +//__forceinline static void __strcat(char* dst, const char* src) { +// while (*dst) dst++; +// __strcpy(dst, src); +//} // s2 should be in lowercase __forceinline static char* __stristr(const char* s1, const char* s2) { unsigned int i; @@ -88,6 +92,19 @@ __forceinline static char* __stristr(const char* s1, const char* s2) { } return 0; } +__forceinline static char* __strstr(const char* s1, const char* s2) { + unsigned int i; + char *p; + for (p = (char*)s1; *p != 0; p++) { + i = 0; + do { + if (s2[i] == 0) return p; + if (p[i] == 0) break; + if (s2[i] != p[i]) break; + } while (++i); + } + return 0; +} __forceinline static int __strncmp(const char* s1, const char* s2, unsigned int len) { while (*s1 == *s2) { if (*s1 == 0 || --len == 0) return 0; @@ -275,4 +292,52 @@ __forceinline static void* GetSysProc(const char* modname, const char* funcname) return (hm ? GetProcAddress(hm, funcname) : 0); } +__forceinline static int FileExistsA(const char* path) { + if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) { // 0xFFFFFFFF (-1) + switch (GetLastError()) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_NAME: + case ERROR_INVALID_DRIVE: + case ERROR_NOT_READY: + case ERROR_INVALID_PARAMETER: + case ERROR_BAD_PATHNAME: + case ERROR_BAD_NETPATH: + return 0; + default: + break; + } + } + return 1; +} + +char* GetModExpName(HMODULE hModule) { + PIMAGE_DOS_HEADER img_dos_headers; + PIMAGE_NT_HEADERS img_nt_headers; + PIMAGE_DATA_DIRECTORY img_dir_exports; + PIMAGE_EXPORT_DIRECTORY img_exp_dir; + + if (!hModule) + return 0; + img_dos_headers = (PIMAGE_DOS_HEADER)hModule; + if (img_dos_headers->e_magic != IMAGE_DOS_SIGNATURE) + return 0; + img_nt_headers = (PIMAGE_NT_HEADERS)((size_t)img_dos_headers + img_dos_headers->e_lfanew); + if (img_nt_headers->Signature != IMAGE_NT_SIGNATURE) + return 0; + if (img_nt_headers->FileHeader.SizeOfOptionalHeader < 4) // OptionalHeader.Magic + return 0; + if (img_nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC || img_nt_headers->OptionalHeader.NumberOfRvaAndSizes < 1) + return 0; + + img_dir_exports = (PIMAGE_DATA_DIRECTORY)(&(img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT])); + if (!img_dir_exports->VirtualAddress || img_dir_exports->Size < sizeof(IMAGE_EXPORT_DIRECTORY)) + return 0; + + img_exp_dir = (PIMAGE_EXPORT_DIRECTORY)((size_t)img_dos_headers + img_dir_exports->VirtualAddress); + return (img_exp_dir->Name ? (char*)((size_t)img_dos_headers + img_exp_dir->Name) : 0); +} + + #endif // __GLOBAL_H