//================================================================== // Constructor //================================================================== CByteArray::CByteArray( int size ) { // Allocate space m_codeBytes = (unsigned char *)malloc( size ); if( m_codeBytes ) { m_totalSize = size; // Fill with nops fill_nop(m_codeBytes, size); // Allow patching / execution SetMemPatchable(m_codeBytes, size); // Set index to 0 m_curIndex = 0; // This was not an existing piece of memory. m_bExisting = false; } else { printf("Couldn't malloc space for CByteArray!\n"); return; } }
void PlayerSlots::Patch() { #if defined PLATFORM_WINDOWS bool firstTime = !(humanLimitSig && lobbyConnectSig); #else bool firstTime = !(lobbyConnectSig); #endif L4D_DEBUG_LOG("PlayerSlots - Patching ..."); /* Server patch ** Needed on windows only. On Linux, this called GetMaxHumanPlayers L4DToolZ doesn't patch this anymore? */ #if defined PLATFORM_WINDOWS if(firstTime) { if (!g_pGameConf->GetMemSig("HumanPlayerLimitReached", &humanLimitSig) || !humanLimitSig) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'HumanPlayerLimitReached' signature"); return; } } //code pages can't be written to by default, so ApplyPatch changes that ;) /* jl around the string "Human player limit reached (%d/%d)" jl -> jmp (Windows) jle -> nop (Linux) we never check if the human player limit has been reached */ patch_t humanLimitPatch; //#if defined PLATFORM_WINDOWS humanLimitPatch.bytes = 1; humanLimitPatch.patch[0] = OP_JMP_REL8; //#else //PLATFORM_LINUX // humanLimitPatch.bytes = OP_JLE_REL8_SIZE; // fill_nop(humanLimitPatch.patch, humanLimitPatch.bytes); //#endif ApplyPatch(humanLimitSig, /*offset*/0, &humanLimitPatch, firstTime ? &humanLimitRestore : NULL); L4D_DEBUG_LOG("PlayerSlots -- 'HumanPlayerLimitReached' jl(e) patched to jmp"); #endif /* Engine patch */ if (!g_pGameConf->GetMemSig("ConnectClientLobbyCheck", &lobbyConnectSig) || !lobbyConnectSig) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'ConnectClientLobbyCheck' signature"); return; } #if defined PLATFORM_WINDOWS /* jz around the string "#Valve_Reject_Server_Full" jz -> nop (linux or windows) do not skip to the server is full code when sv_allow_lobby_connect is 0 */ patch_t lobbyConnectPatch; lobbyConnectPatch.bytes = OP_JZ_REL8_SIZE; fill_nop(lobbyConnectPatch.patch, OP_JZ_REL8_SIZE); ApplyPatch(lobbyConnectSig, /*offset*/0, &lobbyConnectPatch, firstTime ? &lobbyConnectRestore : NULL); unsigned char oldValue2 = lobbyConnectRestore.patch[0]; L4D_DEBUG_LOG("PlayerSlots -- 'ConnectClientLobbyCheck' jz(%x) patched to 2 nops", oldValue2); #endif }
void PlayerSlots::PatchSlotCheckOnly() { if(!lobbyConnectSig) return; //avoid a null dereference if we failed to lookup the sig bool firstTime = (serverFullOffset == -1); if(firstTime) { ////////////////////////// //valve reject server full if (!g_pGameConf->GetOffset("ValveRejectServerFullFirst", &serverFullOffset)) { g_pSM->LogError(myself, "PlayerSlots -- Could not find 'ValveRejectServerFullFirst' offset"); return; } //the offset should point to the cmp eax, [esi+180h]... first byte incorrect => wrong offset if(*((uint8_t*)lobbyConnectSig + serverFullOffset) != OP_CMP_R32_RM32) { g_pSM->LogError(myself, "PlayerSlots -- Offset for 'ValveRejectServerFullFirst' is incorrect"); return; } } /* cmp around the string "#Valve_Reject_Server_Full" cmp eax, [esi+180h] -> cmp eax, IMM32(PLAYER_SLOTS_MAX) (Windows) cmp esi, [ebx+17Ch] -> cmp esi, IMM32(PLAYER_SLOTS_MAX) (Linux) we effectively change how many max players we allow */ patch_t serverFullPatch; #if defined PLATFORM_LINUX serverFullPatch.bytes = OP_CMP_RM32_IMM32_SIZE; serverFullPatch.patch[0] = OP_CMP_RM32_IMM32; serverFullPatch.patch[MODRM_BYTE] = MODRM_MOD_DIRECT | OP_CMP_RM32_IMM32_MODRM_DIGIT | MODRM_RM_ESI; //0xFF *(uint32_t*)(serverFullPatch.patch+MODRM_BYTE+sizeof(uint8_t)) = (uint32_t)PLAYER_SLOTS_MAX; #else //PLATFORM_WINDOWS serverFullPatch.bytes = OP_CMP_R32_RM32_SIZE; //replace the first part of cmp eax, [esi+180h] with cmp eax, IMM32(player_slots_max) serverFullPatch.patch[0] = OP_CMP_EAX_IMM32; *(uint32_t*)(serverFullPatch.patch+sizeof(uint8_t)) = (uint32_t)PLAYER_SLOTS_MAX; //fill in the rest of the patch size with nops fill_nop(serverFullPatch.patch + OP_CMP_EAX_IMM32_SIZE, OP_CMP_R32_RM32_SIZE - OP_CMP_EAX_IMM32_SIZE); #endif if(firstTime) { ApplyPatch(lobbyConnectSig, serverFullOffset, &serverFullPatch, &serverFullRestore); } else { ApplyPatch(lobbyConnectSig, serverFullOffset, &serverFullPatch, /*restore*/NULL); } L4D_DEBUG_LOG("PlayerSlots -- 'ValveRejectServerFullFirst' patched to CMP eax, %d", PLAYER_SLOTS_MAX); // L4D_DEBUG_LOG("PlayerSlots -- CBaseServer player limit: %d", *(unsigned int *)((int)g_pServer+ 0x17C)); }