#include "Inject.h" //########################################################### // ForceLib (c) Y0da! :) //########################################################### #include "ForceLib/ForceLib.h" // // Extern Prototypes // extern void LogText( TCHAR* ); // // Global Variables // PROCESS_INFORMATION pi; STARTUPINFO si; PROCESSENTRY32 pe32; MODULEENTRY32 me32; THREADENTRY32 te32; //########################################################### //## InjectHook() //## //## Determines the method of injection to use, returns //## true or false. The return value is given from the //## method function used. //## //## Returns: FALSE(failed), TRUE(success) //########################################################### BOOL InjectHook() { //########################################################### //## bMethodToUse //## 0 - None [Failed] //## 1 - Proccess already running, CreateRemoteThread() //## 2 - No Process Found, Launch and inject. //########################################################### BYTE bMethodToUse = 0; //########################################################### //## //## INJECTION SELECTOR -- SCAN PROC LIST FOR RUNNING GAME //## //########################################################### HANDLE hSnapshot = NULL; pe32.dwSize = sizeof(PROCESSENTRY32); hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( Process32First( hSnapshot, &pe32 ) ) { do{ if( _tcsstr( pe32.szExeFile, "NostaleX.dat" ) != NULL ) { bMethodToUse = 1; break; } }while( Process32Next( hSnapshot, &pe32 ) ); } if( hSnapshot != INVALID_HANDLE_VALUE ) CloseHandle( hSnapshot ); // Found Process Running, Using Method 1 if( bMethodToUse == 1 ) { LogText( "[INFO] Found Process!" ); LogText( "[INFO] Using injection method 1.." ); return InjectMethod1(); } else { LogText( "[INFO] Process Was Not Found!" ); LogText( "[INFO] Using injection method 2.." ); return InjectMethod2(); } } //########################################################### //## INJECTION METHOD #1 //## //## The process was found in memory so we will attempt //## to hook into it using CreateRemoteThread. //## //## Returns: FALSE(failed), TRUE(success) //########################################################### BOOL InjectMethod1() { // // Although we landed here, we may not // want to inject. Check for the hook. // HANDLE hSnapModules = NULL; me32.dwSize = sizeof(MODULEENTRY32); hSnapModules = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pe32.th32ProcessID ); if( Module32First( hSnapModules, &me32 ) ) { do{ if( _tcsstr( me32.szModule, "NosHook.dll" ) != NULL ) { // // Our hook was found, so lets exit. // CloseHandle( hSnapModules ); LogText( "[ERROR] Injection has failed." ); LogText( "[ERROR] Hook already installed." ); return FALSE; } }while( Module32Next( hSnapModules, &me32 ) ); } CloseHandle( hSnapModules ); // // Our hook was not previous injected so // lets attempt to inject now. [Forcelib] // // First, grab the process thread. // HANDLE hSnapthreads = NULL; te32.dwSize = sizeof(THREADENTRY32); hSnapthreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); if( Thread32First( hSnapthreads, &te32 ) ) { do{ if( te32.th32OwnerProcessID == pe32.th32ProcessID ) { break; } }while( Thread32Next( hSnapthreads, &te32 ) ); } // // Setup our variables for ForceLib // pi.dwProcessId = pe32.th32ProcessID; pi.dwThreadId = te32.th32ThreadID; pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID ); // // Suspend the main thread before injection. // SuspendThread( pi.hThread ); Sleep( 10 ); // Let Windows Catch Up ;) // // Make sure the hook exists :) // TCHAR szHookPath[MAX_PATH]; _tfullpath( szHookPath, "NosHook.dll", MAX_PATH ); if( GetFileAttributes( szHookPath ) == 0xFFFFFFFF ) { LogText( "[ERROR] Hook not found!" ); return FALSE; } // // Attempt to force our hook. [ForceLib] // if( !ForceLibrary( szHookPath, &pi ) ) { LogText( "[ERROR] Injection failed. :(" ); ResumeThread( pi.hThread ); CloseHandle( pi.hThread ); CloseHandle( pi.hProcess ); return FALSE; } else { LogText( "[INFO] Injection successful! :)" ); ResumeThread( pi.hThread ); WaitForSingleObject( pi.hThread, INFINITE ); CloseHandle( pi.hThread ); CloseHandle( pi.hProcess ); return TRUE; } // // Something went wrong :( // LogText( "[CRIT] Unknown error in method 1." ); return FALSE; } //########################################################### //## INJECTION METHOD #2 //## //## The process was not found in memory so we will attempt //## to launch the process and inject into it at startup. //## //## Returns: FALSE(failed), TRUE(success) //########################################################### BOOL InjectMethod2() { // // The process was not found so lets create the // process ourself. THIS BYPASSES THE UPDATER!! // // // First lets make sure the hook exists. // TCHAR szHookPath[MAX_PATH]; _tfullpath( szHookPath, "NosHook.dll", MAX_PATH ); if( GetFileAttributes( szHookPath ) == 0xFFFFFFFF ) { LogText( "[ERROR] Hook not found!" ); return FALSE; } // // Next lets read the registry for the install path. // DWORD dwDataSize = NULL; HKEY hKey = NULL; TCHAR tKey[MAX_PATH] = {0}; TCHAR tGamePath[MAX_PATH] = {0}; _stprintf_s( tKey, sizeof(tKey), "SOFTWARE\\Nostale(UK)" ); if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, tKey, NULL, KEY_READ, &hKey ) != ERROR_SUCCESS ) { LogText( "[ERROR] Registry entry missing..." ); return FALSE; } else { DWORD dwType = REG_SZ; if( RegQueryValueEx( hKey, _T("DestDir"), 0, &dwType, (PBYTE)NULL, &dwDataSize ) == ERROR_SUCCESS ) { RegQueryValueEx( hKey, _T("DestDir"), 0, &dwType, (PBYTE)(LPTSTR)tGamePath, &dwDataSize ); } else { LogText( "[ERROR] Reg: Failed to locate game path." ); return FALSE; } } RegCloseKey( hKey ); // // Create clean variables from path. // TCHAR tGameExe[MAX_PATH] = {0}; _tcscat_s( tGameExe, sizeof(tGamePath), tGamePath ); _tcscat_s( tGameExe, sizeof(tGameExe), _T("\\NostaleX.dat") ); // // Setup our variables for process launching. // ZeroMemory( &si, sizeof(STARTUPINFO) ); TCHAR tCmdArgs[MAX_PATH] = {0}; _tcscat_s( tCmdArgs, sizeof(tGameExe), tGameExe ); _tcscat_s( tCmdArgs, sizeof(tCmdArgs), _T(" EntwellNostaleClient") ); // // Create the process, suspended. // BOOL bResult = CreateProcess(tGameExe, tCmdArgs, NULL, NULL, FALSE, CREATE_SUSPENDED|NORMAL_PRIORITY_CLASS, NULL, tGamePath, &si, &pi); if( !bResult ) { LogText( "[ERROR] Failed to launch the process.." ); return FALSE; } // // Inject our hook into the suspended process. // int hLibModule = 0; LPVOID pLibRemote = VirtualAllocEx( pi.hProcess, NULL, sizeof(szHookPath), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); WriteProcessMemory( pi.hProcess, pLibRemote, szHookPath, sizeof(szHookPath), NULL ); HANDLE hThread = CreateRemoteThread( pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)::GetProcAddress(GetModuleHandle(_T("Kernel32")), "LoadLibraryA"), pLibRemote, 0, NULL ); WaitForSingleObject( hThread, INFINITE ); GetExitCodeThread( hThread, (PDWORD)&hLibModule ); CloseHandle( hThread ); VirtualFreeEx( pi.hProcess, pLibRemote, sizeof(szHookPath), MEM_RELEASE ); // // Check if the hook loaded. // if( !hLibModule ) { LogText( "[ERROR] Failed to load hook." ); LogText( "[ERROR] Killing suspended process." ); TerminateThread( pi.hThread, 0 ); return FALSE; } else { LogText( "[INFO] Injection successful!" ); ResumeThread( pi.hThread ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return TRUE; } // // Something went wrong :( // LogText( "[CRIT] Unknown error in method 2." ); return FALSE; }