void SteamProxy_DoThatTwinklyStuff() { if (!GAME_FLAG(GAME_FLAG_DEDICATED) && false) { Com_Printf(0, "Performing Steam authentication...\n"); // wait until some non-unverified result is returned while (g_steamProxy.eaState == ExternalAuthStateUnverified) { Sleep(1); NP_RunFrame(); if (g_steamProxy.eaCall == 2 && !g_steamProxy.initialized) // if on the second call, and we're not running Steam { Com_Error(1, "Steam must be running for initial authentication to succeed. Please start Steam and restart the game to continue."); } } // do stuff based on verification result if (g_steamProxy.eaState == ExternalAuthStatePirate) { Com_Error(1, "Your current Steam account does not own Call of Duty: Modern Warfare 2. Please purchase the game or try another Steam account."); } else if (g_steamProxy.eaState == ExternalAuthStateError) { Com_Error(1, "An error occurred during Steam verification. Please try again later. If this issue persists, ask on http://fourdeltaone.net/."); } // guess the twinkles were right, you really do own the game! Com_Printf(0, "Steam authentication passed.\n"); } }
void AddEntryNameHookFunc(int type, const char* name) { if (GAME_FLAG(GAME_FLAG_ENTRIES) || useEntryNames) { OutputDebugString(va("%d: %s\n", type, name)); } if (type == ASSET_TYPE_STRINGTABLE) { if (currentSTable < MAX_STABLE_NAMES) { sTableNames[currentSTable] = name; currentSTable++; } } return; /*if (type == ASSET_TYPE_RAWFILE) { if (currentRawFile < MAX_RAWFILE_NAMES) { rawFileNames[currentRawFile] = name; currentRawFile++; } }*/ }
void PatchMW2_Networking() { // gethostbyname *(DWORD*)0x6D7458 = (DWORD)custom_gethostbyname; char* webName = "http://" masterName ":13000/pc/"; if (GAME_FLAG(GAME_FLAG_OFFLINE) || weWantOffline) { // master server strcpy((char*)0x6D9CBC, "127.0.0.1"); *(DWORD*)0x4D4800 = (DWORD)"127.0.0.1:13000/pc/"; *(DWORD*)0x4D481F = (DWORD)"127.0.0.1:13000/pc/"; } else { // master server strcpy((char*)0x6D9CBC, masterName); *(DWORD*)0x4D4800 = (DWORD)webName; *(DWORD*)0x4D481F = (DWORD)webName; } // increase maximum LSP packet size *(DWORD*)0x682614 = 3500; *(DWORD*)0x68262A = 3500; }
void PatchMW2_FrameTime() { if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { call(0x47DD80, Com_FrameWaitHookStub, PATCH_JUMP); } else { call(0x4BAAAD, SV_FrameWaitHookStub, PATCH_CALL); } }
CSteamID CSteamUser014::GetSteamID() { if (GAME_FLAG(GAME_FLAG_DEDICATED)) { return CSteamID(0xDED1CA7E, 1, k_EUniversePublic, k_EAccountTypeIndividual); } NPID npID; bool result = NP_GetNPID(&npID); return CSteamID(npID); }
__declspec(dllexport) void __cdecl SteamAPI_RunCallbacks() { NP_RunFrame(); CSteamBase::RunCallbacks(); if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { if (NP_FriendsConnected()) { if (!didRichPresence) { NP_SetRichPresence("currentGame", "iw4mp"); NP_StoreRichPresence(); Friends_ObtainStats(); didRichPresence = true; } } ServerStorage_EnsureSafeRetrieval(); } }
void SteamProxy_Init() { //SetEnvironmentVariable("SteamAppId", "10190"); if (GAME_FLAG(GAME_FLAG_DEDICATED)) { return; } FILE* file = fopen("steam_appid.txt", "w"); if (file) { fprintf(file, "10190"); fclose(file); } g_steamProxy.initialized = SteamProxy_InitInternal(); if (g_steamProxy.initialized) { SteamProxy_LoadGameOverlayRenderer(); } }
// patches fs_game/IWD script support void PatchMW2_Modding() { // remove limit on IWD file loading //memset((void*)0x643B94, 0x90, 6); *(BYTE*)0x642BF3 = 0xEB; // remove convar write protection (why?) //*(BYTE*)0x647DD4 = 0xEB; // kill most of pure (unneeded in 159, 180+ messed it up) //memset((void*)0x45513D, 0x90, 5); //memset((void*)0x45515B, 0x90, 5); //memset((void*)0x45516C, 0x90, 5); //memset((void*)0x45518E, 0x90, 5); //memset((void*)0x45519F, 0x90, 5); //*(BYTE*)0x449089 = 0xEB; // other IWD things (pure?) //*(BYTE*)0x4C5E7B = 0xEB; //*(BYTE*)0x465107 = 0xEB; // default sv_pure to 0 // TODO: implement client-side downloading/default to 1 for no-mods *(BYTE*)0x4D3A74 = 0; // disable sv_pure for .iwi/.wav/.mp3-only IWDs (for now we only want to get rid of scripts) /*strcpy((char*)0x6F1DBC, ".iwi"); strcpy((char*)0x6E1B94, ".wav"); strcpy((char*)0x71325C, ".mp3");*/ // disable configstring checksum matching (it's unreliable at most) //*(BYTE*)0x4A75A7 = 0xEB; // SV_SpawnServer //*(BYTE*)0x5AC2CF = 0xEB; // CL_ParseGamestate *(BYTE*)0x5AC2C3 = 0xEB; // CL_ParseGamestate // steam stuff (steam authentication) *(DWORD*)0x414ACC = 0x90909090; *(WORD*)0x414AD0 = 0x9090; // hopefully allow alt-tab during game, used at least in alt-enter handling *(BYTE*)0x45ACE0 = 0xB0; *(BYTE*)0x45ACE1 = 0x01; *(BYTE*)0x45ACE2 = 0xC3; // set cg_scoreboardPingText to 1 *(BYTE*)0x45888E = 1; // disable migration_dvarErrors *(BYTE*)0x60BDA7 = 0; // allow vid_restart even if 'connected' memset((void*)0x4CA1FA, 0x90, 6); // remove 'impure stats' checking *(BYTE*)0x4BB250 = 0x33; *(BYTE*)0x4BB251 = 0xC0; *(DWORD*)0x4BB252 = 0xC3909090; // remove fs_game profiles *(WORD*)0x4A5D74 = 0x9090; // fs_game crash fix removing some calls // (NOTE: CoD4 comparison shows this is related to LoadObj weaponDefs, might fix the crash we're having) *(BYTE*)0x452C1D = 0xEB; // remove fs_game check for moddable rawfiles - allows non-fs_game to modify rawfiles *(WORD*)0x61AB76 = 0x9090; // kill filesystem init default_mp.cfg check -- IW made it useless while moving .cfg files to fastfiles // and it makes fs_game crash // not nopping everything at once, there's cdecl stack cleanup in there memset((void*)0x461A9E, 0x90, 5); memset((void*)0x461AAA, 0x90, 5); memset((void*)0x461AB2, 0x90, 0xB1); // for some reason fs_game != '' makes the game load mp_defaultweapon, which does not exist in MW2 anymore as a real asset // kill the call and make it act like fs_game == '' // UPDATE 2010-09-12: this is why CoD4 had text weapon files, those are used with fs_game. // CLARIFY 2010-09-27: we don't have textual weapon files, as such we should load them from fastfile as usual // TODO: change this into a delay-loading hook for fastfile/loadobj (2011-05-20) *(BYTE*)0x4081FD = 0xEB; // exec fixing execIsFSHook.initialize(execIsFSHookLoc, ExecIsFSHookStub); execIsFSHook.installHook(); // exec whitelist removal (YAYFINITY WARD) memset((void*)0x609685, 0x90, 5); *(WORD*)0x60968C = 0x9090; if (GAME_FLAG(GAME_FLAG_OFFLINE) || weWantOffline) { // allow joining 'developer 1' servers *(BYTE*)0x478BA2 = 0xEB; } PatchMW2_FFHash(); }
__declspec(dllexport) bool __cdecl SteamAPI_Init() { #if USE_MANAGED_CODE IW4::AdminPluginCode::Initialize(); #endif //HideCode_FindCreateFile(); #ifdef PRE_RELEASE_DEMO DisableOldVersions(); #endif NP_SetLogCallback(NP_LogCB); NP_Init(); NP_RegisterEACallback(NPA_StateSet); #ifdef KEY_DISABLED if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { #endif if (!NP_Connect(NP_SERVER, 3025)) { // TODO: offer offline mode in this case/with an offline gameflag Com_Error(1, "Could not connect to NP server at " NP_SERVER); return false; } #ifdef KEY_DISABLED } #endif NPAuthenticateResult* result; if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithToken(Auth_GetSessionID()); result = async->Wait(); } else { //NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithLicenseKey("123456789012345678901234"); #ifndef KEY_DISABLED /*const char* licenseKey = GetLicenseKey(); if (!licenseKey) { Com_Error(1, "No license key set. Pass a license key in the command line of the application (like iw4.exe #123456789012345678901234)."); }*/ dvar_t* licenseKey = Dvar_RegisterString("np_licenseKey", "", DVAR_FLAG_DEDISAVED, "NP dedicated server license key"); dvar_t* licenseID = Dvar_RegisterString("np_licenseID", "", DVAR_FLAG_DEDISAVED, "NP dedicated server ID"); InitializeDediConfig(); if (!licenseKey->current.string[0]) { NPAsync<NPRegisterServerResult>* regAsync = NP_RegisterServer("iw4m ftw! hey guys, it's me, the cake hero! cake is lovely and tasty! eat many cakes in your life! bye!"); NPRegisterServerResult* regResult = regAsync->Wait(); if (regResult->result != AuthenticateResultOK) { switch (result->result) { case AuthenticateResultBadDetails: Com_Error(1, "Could not register to NP server at " NP_SERVER " -- bad details."); break; case AuthenticateResultServiceUnavailable: Com_Error(1, "Could not register to NP server at " NP_SERVER " -- service unavailable."); break; case AuthenticateResultBanned: Com_Error(1, "Could not register to NP server at " NP_SERVER " -- banned."); break; case AuthenticateResultUnknown: Com_Error(1, "Could not register to NP server at " NP_SERVER " -- unknown error."); break; } } Dvar_SetCommand("np_licenseKey", regResult->licenseKey); Dvar_SetCommand("np_licenseID", va("%i", regResult->serverID)); } NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithLicenseKey(licenseKey->current.string); result = async->Wait(); //dvar_t* net_port = Dvar_FindVar("net_port"); //NP_SendRandomString(va("port %i", net_port->current.integer)); #endif } #ifndef KEY_DISABLED if (result->result != AuthenticateResultOK) { switch (result->result) { case AuthenticateResultBadDetails: Dvar_SetCommand("np_licenseKey", ""); if (GAME_FLAG(GAME_FLAG_DEDICATED)) { Com_SaveDediConfig(); } Com_Error(1, "Could not authenticate to NP server at " NP_SERVER " -- bad details."); break; case AuthenticateResultAlreadyLoggedIn: Com_Error(1, "Could not authenticate to NP server at " NP_SERVER " -- already logged in."); break; case AuthenticateResultServiceUnavailable: Com_Error(1, "Could not authenticate to NP server at " NP_SERVER " -- service unavailable."); break; case AuthenticateResultBanned: Com_Error(1, "Could not authenticate to NP server at " NP_SERVER " -- banned."); break; case AuthenticateResultUnknown: Com_Error(1, "Could not authenticate to NP server at " NP_SERVER " -- unknown error."); break; } } #endif g_extDLL = (IExtDLL*)NP_LoadGameModule(BUILDNUMBER); if (!g_extDLL) Com_Error(1, "Could not load the extension DLL for revision number " BUILDNUMBER_STR); g_extDLL->Initialize(_gameFlags, new ClientDLLAPI()); ignoreThisFx = g_extDLL->AssetRestrict_Trade1(&useEntryNames); g_nuiDraw = g_extDLL->GetNUIDraw(); g_scriptability = g_extDLL->GetScriptability(); g_scriptability->cbExceptionFilter = CustomUnhandledExceptionFilter; #ifdef WE_DO_WANT_NUI g_scriptability->cbInitNUI(); #endif NP_RegisterKickCallback(NPA_KickClient); SteamProxy_Init(); // perform Steam validation SteamProxy_DoThatTwinklyStuff(); NPID npID; NP_GetNPID(&npID); return true; // private build? int id = npID & 0xFFFFFFFF; if (id != 2 && id != 1052 && id != 2337 && id != 5428 && id != 233 && id != 337 && id != 341138 && id != 228 && id != 165422 && id != 1304 && id != 1126 && id != 348 && id != 1330 && id != 826 && id != 24140 && id != 66 && id != 8206 && id != 1546 && id != 172 && id != 677 && id != 406 && id != 217 && id != 111 && id != 561 && id != 39566 && id != 669 && id != 788 && id != 616 && id != 161 && id != 303 && id != 40974 && id != 208 && id != 351 && id != 264 && id != 699 && id != 1710) { ExitProcess(1); } return true; }
void PatchMW2_Game() { // remove system pre-init stuff (improper quit, disk full) *(BYTE*)0x411350 = 0xC3; // remove STEAMSTART checking for DRM IPC memset((void*)0x451145, 0x90, 5); *(BYTE*)0x45114C = 0xEB; // internal version *(int*)0x463C61 = 99; // protocol version (workaround for hacks) *(int*)0x4FB501 = 1337; // was 8E // protocol command *(int*)0x4D36A9 = 1337; // was 8E *(int*)0x4D36AE = 1337; // was 8E *(int*)0x4D36B3 = 1337; // was 8E // cause 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored (issue #8) *(BYTE*)0x49D007 = 0xEB; // cause Steam auth to always be requested memset((void*)0x46FB8C, 0x90, 6); // disable Steam auth *(BYTE*)0x4663A8 = 0xEB; // un-neuter Com_ParseCommandLine to allow non-connect_lobby *(BYTE*)0x464AE4 = 0xEB; CrashHandlerInit(); PatchMW2_Modding(); PatchMW2_Redirect(); PatchMW2_Load(); PatchMW2_Prefix(); PatchMW2_AssetRestrict(); PatchMW2_ClientConsole(); PatchMW2_LogInitGame(); PatchMW2_Branding(); PatchMW2_Stats(); PatchMW2_ScoreboardInfo(); PatchMW2_Dvars(); PatchMW2_XPBar(); PatchMW2_VA(); PatchMW2_LocalizedStrings(); PatchMW2_Commands(); PatchMW2_Networking(); PatchMW2_SuicideMessages(); //if (GAME_FLAG(GAME_FLAG_OFFLINE)) //{ PatchMW2_Offline(); weWantOffline = true; //} if (GAME_FLAG(GAME_FLAG_CONSOLE)) { // always enable system console, not just if generating reflection probes memset((void*)0x60BB58, 0x90, 11); } FreeConsole(); }
bool ExtDLL_CheckSafety() { // check #1: NP validity NPAsync<NPGetPublisherFileResult>* async = NP_GetPublisherFile("hello_world.txt", (uint8_t*)helloWorld, sizeof(helloWorld)); NPGetPublisherFileResult* result = async->Wait(); if (result->result != GetFileResultOK) { MessageBoxA(NULL, "The IW4M extension DLL failed to load due to the master server lacking support for the functionality provided by this DLL.", "IW4M", MB_OK); return false; } // check #2: DLL signature if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { HMODULE iw4m = GetModuleHandleA("iw4m.dll"); if (!iw4m) { return false; } wchar_t filename[MAX_PATH]; GetModuleFileNameW(iw4m, filename, sizeof(filename) / 2); WINTRUST_FILE_INFO info; memset(&info, 0, sizeof(info)); info.cbStruct = sizeof(info); info.pcwszFilePath = filename; info.hFile = NULL; info.pgKnownSubject = NULL; GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; WINTRUST_DATA data; memset(&data, 0, sizeof(data)); data.cbStruct = sizeof(data); data.pPolicyCallbackData = NULL; data.pSIPClientData = NULL; data.dwUIChoice = WTD_UI_NONE; data.fdwRevocationChecks = WTD_REVOKE_NONE; data.dwUnionChoice = WTD_CHOICE_FILE; data.dwStateAction = 0; data.hWVTStateData = NULL; data.pwszURLReference = NULL; data.dwUIContext = 0; data.pFile = &info; LONG status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data); if (status != ERROR_SUCCESS) { MessageBoxA(NULL, va("The IW4M extension DLL failed to load due to a trust chain error. The specific error was 0x%x.", status), "IW4M", MB_OK); return false; } } return true; }
__declspec(dllexport) bool __cdecl SteamAPI_Init() { NP_SetLogCallback(NP_LogCB); NP_Init(); #ifdef KEY_DISABLED if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { #endif if (!NP_Connect(MASTER_SERVER, 3025)) { // TODO: offer offline mode in this case/with an offline gameflag Com_Error(1, "Could not connect to NP server at " MASTER_SERVER); return false; } #ifdef KEY_DISABLED } #endif NPAuthenticateResult* result; if (!GAME_FLAG(GAME_FLAG_DEDICATED)) { //NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithToken(Auth_GetSessionID()); NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithLicenseKey("123456789012345678901234"); result = async->Wait(); } else { //NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithLicenseKey("123456789012345678901234"); #ifndef KEY_DISABLED //const char* licenseKey = GetLicenseKey(); Dvar_RegisterString("dw_licensefile", "dwkey.dat", 16, ""); char licenseKey[26]; if (!DW_ReadLicenseKey(licenseKey, sizeof(licenseKey))) { return false; } licenseKey[24] = '\0'; NPAsync<NPAuthenticateResult>* async = NP_AuthenticateWithLicenseKey(licenseKey); result = async->Wait(); #endif } #ifndef KEY_DISABLED if (result->result != AuthenticateResultOK) { switch (result->result) { case AuthenticateResultBadDetails: Com_Error(1, "Could not authenticate to NP server at " MASTER_SERVER " -- bad details."); break; case AuthenticateResultAlreadyLoggedIn: Com_Error(1, "Could not authenticate to NP server at " MASTER_SERVER " -- already logged in."); break; case AuthenticateResultServiceUnavailable: Com_Error(1, "Could not authenticate to NP server at " MASTER_SERVER " -- service unavailable."); break; case AuthenticateResultBanned: Com_Error(1, "Could not authenticate to NP server at " MASTER_SERVER " -- banned."); break; case AuthenticateResultUnknown: Com_Error(1, "Could not authenticate to NP server at " MASTER_SERVER " -- unknown error."); break; } } #endif NP_RegisterKickCallback(NPA_KickClient); return true; }