Skip to content

Commit

Permalink
FEAR stuff, SecuROM v7 guard
Browse files Browse the repository at this point in the history
Exit process instantly if SecuROM v7 is detected to prevent it from installing to your system
  • Loading branch information
anzz1 authored Aug 14, 2023
1 parent 87b2090 commit 4e4d3d7
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 12 deletions.
56 changes: 54 additions & 2 deletions dllmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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();

Expand Down Expand Up @@ -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);
}
Expand Down
83 changes: 73 additions & 10 deletions include/game_fear.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
65 changes: 65 additions & 0 deletions include/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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

1 comment on commit 4e4d3d7

@mirh
Copy link

@mirh mirh commented on 4e4d3d7 Aug 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no "installation"?
At most the thing has two keys in the registry, and a file with the licenses.

Please sign in to comment.