////////////////////////////////////////////////////////////////////// // ServerStart() // ------------------------------------------------------------------- // Responsible for setting up the server. ////////////////////////////////////////////////////////////////////// BOOL PRIVATE ServerStart(HANDLE hModule) { // Temporary string LPSTR t=NULL; ////////////////////////////////////////////////////////////////// // Before anything else, create the global structures we use in // the hack. Make sure we delete these in ServerStop. ////////////////////////////////////////////////////////////////// si = new SERVERINFO; psi = new PRIVATESERVERINFO; fep = new FUNCTIONENTRYPOINTS; pfep= new PRIVATEFUNCTIONENTRYPOINTS; thisgame=new THISGAMESTRUCT; thisgame->player=NULL; ////////////////////////////////////////////////////////////////// // Force-load needed dll's so we can patch thei'r memory space. // We should unload these is ServerStop. ////////////////////////////////////////////////////////////////// for (int i=0; NeededDlls[i] != NULL; i++) LoadLibrary(NeededDlls[i]); ////////////////////////////////////////////////////////////////// // Build initial data of the SERVERINFO structure ////////////////////////////////////////////////////////////////// si->Version=__SERVERVERSION__; // Get plugin path t=new char[_MAX_PATH]; if (!GetModuleFileName((HINSTANCE)hModule, t, _MAX_PATH)) { MessageBox(NULL, "Unable to get PluginPath!", "D2Hackit Error!", MB_ICONERROR); return FALSE; } int p=strlen(t); while (p) { if (t[p] == '\\') { t[p] = 0; p=0;} else p--; } si->PluginDirectory=new char[strlen(t)+1]; strcpy((LPSTR)si->PluginDirectory, t); psi->DontShowErrors=FALSE; ////////////////////////////////////////////////////////////////// // Build initial data of the PRIVATESERVERINFO structure ////////////////////////////////////////////////////////////////// sprintf(t, "%s\\D2HackIt.ini", t); psi->IniFile=new char[strlen(t)+1]; strcpy((LPSTR)psi->IniFile, t); delete t; /* This block of code is replaced by the single GetCurrentProcessId() call below. This works because DLL initialization is performed within the context of the process to which the DLL is attaching - i.e. under that process's PID // Get Diablo II's hwnd psi->hwnd = FindWindow("Diablo II", "Diablo II"); // Get hwnd if (!psi->hwnd) { MessageBox(NULL, "Can't get Diablo II's window handle.", "D2Hackit Error!", MB_ICONERROR); return FALSE; } // Get Diablo II's pid & Process handle GetWindowThreadProcessId(psi->hwnd, &psi->pid); */ // Get the process ID and the process handle psi->pid = GetCurrentProcessId(); psi->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, psi->pid); if (!psi->hProcess) { MessageBox(NULL, "Can't get Diablo II's process handle.", "D2Hackit Error!", MB_ICONERROR); return FALSE;} // Get build date/time strcpy(psi->BuildDate, __DATE__); strcpy(psi->BuildTime, __TIME__); ////////////////////////////////////////////////////////////////// // Build initial callbacks in the FUNCTIONENTRYPOINTS structure. ////////////////////////////////////////////////////////////////// // fep->GetMemoryAddressFromPattern=&GetMemoryAddressFromPattern; fep->GamePrintString=&GamePrintString; fep->GamePrintInfo=&GamePrintInfo; fep->GamePrintVerbose=&GamePrintVerbose; fep->GamePrintError=&GamePrintError; fep->GetHackProfileString=&GetHackProfileString; fep->GetHackProfileStringEx=&GetHackProfileStringEx; fep->GetHackProfileSectionNames=&GetHackProfileSectionNames; fep->GameSendMessageToChat=&GameSendMessageToChat; ////////////////////////////////////////////////////////////////// // Build initial callbacks in PRIVATEFUNCTIONENTRYPOINTS ////////////////////////////////////////////////////////////////// pfep->GetBaseAddress=&GetBaseAddress; pfep->GetImageSize=&GetImageSize; ////////////////////////////////////////////////////////////////// // Check if D2HackIi.ini exisits ////////////////////////////////////////////////////////////////// if (_access(psi->IniFile, 0)) { LPSTR t=new char[strlen(psi->IniFile)+50]; sprintf(t, "Unable to open ini-file:\n%s", psi->IniFile); MessageBox(NULL, t, "D2Hackit Error!", MB_ICONERROR); delete t; return FALSE; } ////////////////////////////////////////////////////////////////// // Set default prompts ////////////////////////////////////////////////////////////////// t=fep->GetHackProfileString("D2HackIt", "Misc", "InfoPrompt"); lstrcpyn(psi->InfoPrompt, (strlen(t)?t:DEFAULTINFOPROMPT),MAXPROMPTLENGTH-1); delete t; t=fep->GetHackProfileString("D2HackIt", "Misc", "ErrorPrompt"); lstrcpyn(psi->ErrorPrompt, (strlen(t)?t:DEFAULTERRORPROMPT),MAXPROMPTLENGTH-1); delete t; t=fep->GetHackProfileString("D2HackIt", "Misc", "VerbosePrompt"); lstrcpyn(psi->VerbosePrompt, (strlen(t)?t:DEFAULTVERBOSEPROMPT),MAXPROMPTLENGTH-1); t=fep->GetHackProfileString("D2HackIt", "Misc", "Verbose"); if (!stricmp(t, "on")) psi->Verbose = TRUE; else psi->Verbose = FALSE; delete t; ////////////////////////////////////////////////////////////////// // Start by binding a way to print to screen. This is vital, so if // we are unable to do this, exit with an error message! ////////////////////////////////////////////////////////////////// FINGERPRINTSTRUCT fps; if(!GetFingerprint("D2HackIt", "GamePrintStringLocation", fps)) { MessageBox(NULL, "Fingerprint information for 'GamePrintStringLocation'\nmissing or corrupt!", "D2Hackit Error!", MB_ICONERROR); return FALSE; } psi->GamePrintStringLocation=fps.AddressFound; if (!psi->GamePrintStringLocation) { MessageBox(NULL, "Unable to find entrypoint for 'GamePrintStringLocation'!", "D2Hackit Error!", MB_ICONERROR); return FALSE; } // Get playerinfo struct if (!GetFingerprint("D2HackIt", "pPlayerInfoStruct", fps)) { fep->GamePrintError("Fatal error! Exiting!"); return FALSE; } // Messy pointers :) thisgame->player=(PLAYERINFOSTRUCT*)*(DWORD*)(*(DWORD*)fps.AddressFound); // Get gameinfo struct if (!GetFingerprint("D2HackIt", "pPlayerInfoStruct", fps)) { fep->GamePrintError("Fatal error! Exiting!"); return FALSE; } // Get GameSendMessageToChat psi->GameSendMessageToChatLocation = NULL; if(GetFingerprint("D2HackIt", "GameSendMessageToChat", fps)) psi->GameSendMessageToChatLocation = fps.AddressFound; // Messy pointers :) //thisgame->CurrentGame=(GAMESTRUCT*)*(DWORD*)(*(DWORD*)fps.AddressFound); // Initialize critical section InitializeCriticalSection(&psi->csData); // Initialize insert receive buffers psi->nRecvBufferPos = 0; ////////////////////////////////////////////////////////////////// // Print startup banner. ////////////////////////////////////////////////////////////////// t=new char[128]; sprintf(t, "Starting D2HackIt! Mk2 version %d.%.2d (%s@%s)", LOWORD(si->Version), HIWORD(si->Version), psi->BuildDate, psi->BuildTime ); fep->GamePrintInfo(t); ////////////////////////////////////////////////////////////////// // Get loader data ////////////////////////////////////////////////////////////////// BOOL UsingD2Loader=FALSE; psi->DontShowErrors=TRUE; if (!GetFingerprint("D2HackIt", "LoaderStruct", fps)) { psi->DontShowErrors=FALSE; sprintf(fps.ModuleName, "Diablo II.exe"); UsingD2Loader=TRUE; if ((fps.AddressFound=GetMemoryAddressFromPattern(fps.ModuleName, fps.FingerPrint, fps.Offset)) < 0x100) { sprintf(fps.ModuleName, "D2Loader.exe"); if ((fps.AddressFound=GetMemoryAddressFromPattern(fps.ModuleName, fps.FingerPrint, fps.Offset)) < 0x100) { //fep->GamePrintError("Unable to find loader data in 'Game.exe', 'Diablo II.exe' or 'D2Loader.exe'!"); //fep->GamePrintError("Fatal error! Exiting!"); return FALSE; fps.AddressFound=0; } } } psi->loader = (LOADERDATA*)fps.AddressFound; if (psi->loader) { sprintf(t, "Loader version ÿc4%d.%.2d. ÿc0Game is %sstarted with D2Loader.", LOWORD(psi->loader->LoaderVersion), HIWORD(psi->loader->LoaderVersion), (UsingD2Loader?"":"ÿc4not ÿc0")); } else { sprintf(t, "D2Hackit was loaded without loader"); } fep->GamePrintInfo(t); ////////////////////////////////////////////////////////////////// // Continue binding entrypoints and intercepts ////////////////////////////////////////////////////////////////// sprintf(t, "Found 'GamePrintStringLocation' at %.8x", psi->GamePrintStringLocation); fep->GamePrintVerbose(t); /* * No need for this * // Get socket location if (!GetFingerprint("D2HackIt", "pGameSocketLocation", fps)) { fep->GamePrintError("Fatal error! Exiting!"); return FALSE; } psi->GameSocketLocation=*(DWORD*)fps.AddressFound; */ // Get GamePacketReceivedIntercept if (!GetFingerprint("D2HackIt", "GamePacketReceivedIntercept", psi->fps.GamePacketReceivedIntercept)) { fep->GamePrintError("Fatal error! Exiting!"); return FALSE; } Intercept(INST_CALL, psi->fps.GamePacketReceivedIntercept.AddressFound, (DWORD)&GamePacketReceivedInterceptSTUB, psi->fps.GamePacketReceivedIntercept.PatchSize); // Get GamePacketReceivedIntercept2 if (!GetFingerprint("D2HackIt", "GamePacketReceivedIntercept2", psi->fps.GamePacketReceivedIntercept2)) { fep->GamePrintError("Fatal error! Exiting!"); Intercept(INST_CALL, (DWORD)&GamePacketReceivedInterceptSTUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept.PatchSize); return FALSE; } Intercept(INST_JMP, psi->fps.GamePacketReceivedIntercept2.AddressFound, (DWORD)&GamePacketReceivedIntercept2STUB, psi->fps.GamePacketReceivedIntercept2.PatchSize); // Get GamePacketSentIntercept if (!GetFingerprint("D2HackIt", "GamePacketSentIntercept", psi->fps.GamePacketSentIntercept)) { fep->GamePrintError("Fatal error! Exiting!"); Intercept(INST_JMP, (DWORD)&GamePacketReceivedIntercept2STUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept2.PatchSize); Intercept(INST_CALL, (DWORD)&GamePacketReceivedInterceptSTUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept.PatchSize); return FALSE; } Intercept(INST_CALL, psi->fps.GamePacketSentIntercept.AddressFound, (DWORD)&GamePacketSentInterceptSTUB, psi->fps.GamePacketSentIntercept.PatchSize); // Get GamePlayerInfoIntercept if (!GetFingerprint("D2HackIt", "GamePlayerInfoIntercept", psi->fps.GamePlayerInfoIntercept)) { fep->GamePrintError("Fatal error! Exiting!"); Intercept(INST_CALL, (DWORD)&GamePacketSentInterceptSTUB, psi->fps.GamePacketSentIntercept.AddressFound, psi->fps.GamePacketSentIntercept.PatchSize); Intercept(INST_JMP, (DWORD)&GamePacketReceivedIntercept2STUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept2.PatchSize); Intercept(INST_CALL, (DWORD)&GamePacketReceivedInterceptSTUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept.PatchSize); return FALSE; } Intercept(INST_CALL, psi->fps.GamePlayerInfoIntercept.AddressFound, (DWORD)&GamePlayerInfoInterceptSTUB, psi->fps.GamePlayerInfoIntercept.PatchSize); // Get GameSendPacketToGameLocation // Thanks to TechWarrior if (!GetFingerprint("D2HackIt", "GameSendPacketToGameLocation", fps)) { fep->GamePrintError("Fatal error! Exiting!"); Intercept(INST_CALL, (DWORD)&GamePacketSentInterceptSTUB, psi->fps.GamePacketSentIntercept.AddressFound, psi->fps.GamePacketSentIntercept.PatchSize); Intercept(INST_JMP, (DWORD)&GamePacketReceivedIntercept2STUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept2.PatchSize); Intercept(INST_CALL, (DWORD)&GamePacketReceivedInterceptSTUB, psi->fps.GamePacketReceivedIntercept.AddressFound, psi->fps.GamePacketReceivedIntercept.PatchSize); Intercept(INST_CALL, (DWORD)&GamePlayerInfoInterceptSTUB, psi->fps.GamePlayerInfoIntercept.AddressFound, psi->fps.GamePlayerInfoIntercept.PatchSize); return FALSE; } psi->GameSendPacketToGameLocation=fps.AddressFound; // Start TickThread, We dont care about closing it later. // It will be destroyed when unloading the dll. DWORD dummy=0; psi->TickShutDown = 0; psi->TickThreadHandle = CreateThread(NULL,0,TickThread,(void*)&ClientList,0,&dummy); psi->TickThreadActive = psi->TickThreadHandle!=NULL; // Load any clients listed in Autorun t=new char[1024]; t=fep->GetHackProfileString("D2HackIt", "Misc", "Autoload"); if (strlen(t)) { char* command[2]; command[0]=".load"; char *p; p=t; command[1] = p; while (*p != 0) { if (*p == ',') { *(p++) = 0; GameCommandLineLoad(command,2); while (*p == ' ') p++; if (*p != 0) command[1] = p; } else p++; } GameCommandLineLoad(command,2); } delete t; fep->GamePrintInfo("D2HackIt! Mk2 Loaded! Type ÿc4.helpÿc0 for help on commands."); return TRUE; }
//---------------------------------------------------------------------------------------- // Game Patches //---------------------------------------------------------------------------------------- void applyFPSPatch() { SDLOG(0, "Starting FPS unlock...\n"); #ifndef WITHOUT_GFWL_LIB SDLOG(0, "Applying GFWL compatibility\n"); enableGFWLCompatibility(); #endif // Get image info MODULEINFO moduleInfo; PIMAGE_DOS_HEADER dosHeader; PIMAGE_NT_HEADERS ntHeader; IMAGE_FILE_HEADER header; if(GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &moduleInfo, sizeof(moduleInfo))) { ImageBase = (DWORD)moduleInfo.lpBaseOfDll; SDLOG(0, "ImageBase at 0x%08X\n", ImageBase); dosHeader = (PIMAGE_DOS_HEADER)ImageBase; ntHeader = (PIMAGE_NT_HEADERS)((DWORD)(dosHeader) + (dosHeader->e_lfanew)); header = ntHeader->FileHeader; DWORD TimeStamp = header.TimeDateStamp; SDLOG(0, "Executable timestamp: 0x%08X, config: 0x%08X\n", TimeStamp, EXE_TIMESTAMP); // Perform pattern matching if timestamp differs if (TimeStamp != EXE_TIMESTAMP) { SDLOG(0, "Trying pattern matching...\n"); DWORD address; address = GetMemoryAddressFromPattern(NULL, TS_PATTERN, TS_OFFSET); if(address != NULL) { SDLOG(0, "ADDR_TS found at 0x%08X\n", address); ADDR_TS = address; } else { SDLOG(0, "Could not match ADDR_TS pattern, FPS not unlocked\n"); return; } address = GetMemoryAddressFromPattern(NULL, PRESINT_PATTERN, PRESINT_OFFSET); if(address != NULL) { SDLOG(0, "ADDR_PRESINT found at 0x%08X\n", address); ADDR_PRESINT = address; } else { SDLOG(0, "Could not match ADDR_PRESINT pattern, FPS not unlocked\n"); return; } address = GetMemoryAddressFromPattern(NULL, GETCMD_PATTERN, GETCMD_OFFSET); if(address != NULL) { SDLOG(0, "ADDR_GETCMD found at 0x%08X\n", address); ADDR_GETCMD = address; } else { SDLOG(0, "Could not match ADDR_GETCMD pattern, FPS not unlocked\n"); return; } SDLOG(0, "Pattern matching successful\n"); } else SDLOG(0, "Using configured addresses\n"); } else { SDLOG(0, "GetModuleInformation failed, FPS not unlocked\n"); return; } // Init counter for frame-rate calculations lastRenderTime = 0.0f; QueryPerformanceFrequency(&timerFreq); QueryPerformanceCounter(&counterAtStart); // Binary patches //-------------------------------------------------------------- DWORD address; DWORD data; // Override D3D Presentation Interval address = convertAddress(ADDR_PRESINT); data = 5; //Set to immediate writeToAddress(&data, address, sizeof(data)); // Detour call to getDrawThreadMsgCommand address = convertAddress(ADDR_GETCMD); DetourApply((BYTE*)address, (BYTE*)getDrawThreadMsgCommand, 5, CALLOP); SDLOG(0, "FPS unlocked\n"); }
////////////////////////////////////////////////////////////////////// // GetFingerPrint // ------------------------------------------------------------------- // Reads szFingerPrintName from the [FingerprintData] section of the // ini-file asociated with szHackName. // // It breaks up the components of the string, does some basic sanity- // check and calls GetMemoryAddressFromPattern() to store the address // of the fingerprint, if found. ////////////////////////////////////////////////////////////////////// BOOL EXPORT GetFingerprint(LPCSTR szHackName, LPCSTR szFingerprintName, FINGERPRINTSTRUCT &fps) { LPSTR szReturnString; sprintf(fps.Name, szFingerprintName); fps.AddressFound=0; int i; int nFields=0; char *t; szReturnString=fep->GetHackProfileString(szHackName, "FingerprintData", szFingerprintName); // No such fingerprint! if (!strlen(szReturnString)) { t=new char[256]; sprintf(t, "Can't find fingerprint for '%s' in '%s.ini'", szFingerprintName, szHackName); fep->GamePrintError(t); delete t, szReturnString; return FALSE; } // Make sure we have 4 fields for (i=0; szReturnString[i]; i++) if (szReturnString[i] == ',') nFields++; if (nFields != 3) { t=new char[256]; sprintf(t, "Fingerprint for '%s' in '%s.ini' is corrupt.", szFingerprintName, szHackName); fep->GamePrintError(t); delete t, szReturnString; return FALSE; } // Loop backwards to get fingerprint info for (;i!=0;i--) { if (szReturnString[i] == ',') { szReturnString[i] = 0; nFields--; switch (nFields) { case 2: strcpy(fps.FingerPrint, &szReturnString[i+1]); break; case 1: fps.Offset=atoi(&szReturnString[i+1]); break; case 0: fps.PatchSize=atoi(&szReturnString[i+1]); break; } } } strcpy(fps.ModuleName, szReturnString); delete szReturnString; if ((fps.AddressFound=GetMemoryAddressFromPattern(fps.ModuleName, fps.FingerPrint, fps.Offset)) < 0x100) { if (psi->DontShowErrors) return FALSE; t=new char[256]; sprintf(t, "Unable fo find location for '%s'.", szFingerprintName, szHackName); fep->GamePrintError(t); delete t; return FALSE; } else { t=new char[256]; sprintf(t, "Found '%s' at %.8x", szFingerprintName, fps.AddressFound); fep->GamePrintVerbose(t); delete t; return TRUE; } }