==================================================================================== # # this file has been created for the Lame patcher program available for both *nix # and Windows platforms. # You need this program for continuing the patching of your files: # # http://aluigi.org/mytoolz.htm#lpatch # # Quick step-by-step for Windows: # - launch lpatch.exe # - select this q3cbufexecfix.lpatch file # - read the message windows and click yes # - select the file (usually executables or dlls) to patch # - read the message windows to know if everything has been patched correctly # - test your game # # NOTE lpatch >= 0.4.3 required!!! TITLE Quake 3 engine Cbuf_Execute commands execution universal fix 0.1 (Windows) by Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org INTRO This unofficial patch, available for the games based on the Quake 3 engine, is referred to the following problem: . . http://aluigi.freeforums.org/quake3-engine-callvote-bug-t686.html . http://bugzilla.icculus.org/show_bug.cgi?id=3593 . The work-around I have adopted has been the scanning of the input in Cbuf_ExecuteText using something like the following: . . void Cbuf_ExecuteText (int exec_when, const char *text) . { . if(text) { . int i = 0; . do { . if(/*(text[i] == ';') ||*/ (text[i] == '\n') || (text[i] == '\r')) { . if(text[i+1]) // needed in case of "string\n" . text[i] = 0; . } . i++; . } while(text[i-1]); . } . ... . The patch has been tested with almost all the latest versions of the game servers based on the Quake 3 engine only for Windows, older versions will be NOT supported by me so don't ask. . note: this patch works ONLY with Lpatch 0.4.3 and above. note: if the patch modifies more than 53 bytes means that your exe is not supported FILE *.exe EXECUTABLE // forces the parsing of the executable, needed for the X functions ONLY_ONE //MAX_CHANGES // commented because if lpatch fixes more than 52 or 53 bytes means there are duplicates // 1 // and so the user can see this difference ; on Windows the pattern is ever the same, except some rare cases like et255, sof2 and ef ; in which the difference is minimal. ; different situation for Linux, that's why the executables for Linux are not supported here. ; if you want to manually find the location of Cbuf_ExecuteText search the string ; "Cbuf_ExecuteText: bad exec_when" referenced in the executable. ; ; anyway the best way to fix this and other bugs/annoying things (like using line feeds ; in the say command) is adopting the same scanning used here (optionally without the ; commenting of the ';' check) into SV_ExecuteClientCommand where arrive ALL the commands ; sent by the client. ; unfortunately I can't do it here for the usual obvious compatibility problems which avoid ; to create universal fixes, but this is useful to anyone who wants a game specific fix. /* the majority of the games */ BYTES_ORIGINALX 8B 44 24 04 ; mov eax, dword ptr [esp+04] 83 E8 00 ; sub eax, 00000000 74 37 ; je 00419A70 // the patch is long but it's needed to avoid to touch other registers or the stack (only EAX) // note: the other BYTES_PATCHX in this file are exactly the SAME as the following BYTES_PATCHX 8B 44 24 08 ; MOV EAX,DWORD PTR SS:[ESP+8] 85 C0 ; TEST EAX,EAX 74 1F ; JE quit // the check of ';' has been removed because various genuine sequences of commands pass through // Cbuf_ExecuteText so is not possible to make distinction between valid and malicious // anyway ';' is usually already checked by the server's code. if you are paranoid modify the following: 90 90 90 // 80 38 3B ; CMP BYTE PTR DS:[EAX],3B // redo 90 90 // 74 0A ; JE check 80 38 0A ; CMP BYTE PTR DS:[EAX],0A 74 05 ; JE check 80 38 0D ; CMP BYTE PTR DS:[EAX],0D 75 09 ; JNZ check_null 80 78 01 00 ; CMP BYTE PTR DS:[EAX+1],0 // check if the next is null because "string\n" is correct 74 03 ; JZ check_null C6 00 00 ; MOV BYTE PTR DS:[EAX],0 40 ; INC EAX 80 78 FF 00 ; CMP BYTE PTR DS:[EAX-1],0 // check_null 75 E1 ; JNZ redo 8B 44 24 04 ; mov eax, dword ptr [esp+04] // quit 90 90 90 90 90 ; reserved for the jmp 85 C0 ; test eax, eax 7 ; the amount of previous bytes /* et255 */ BYTES_ORIGINALX 8B 44 24 04 ; mov eax, dword ptr [esp+04] 83 E8 00 ; sub eax, 00000000 74 32 ; je 00419A70 BYTES_PATCHX 8B 44 24 08 ; MOV EAX,DWORD PTR SS:[ESP+8] 85 C0 ; TEST EAX,EAX 74 1F ; JE quit 90 90 90 // 80 38 3B ; CMP BYTE PTR DS:[EAX],3B // redo 90 90 // 74 0A ; JE check 80 38 0A ; CMP BYTE PTR DS:[EAX],0A 74 05 ; JE check 80 38 0D ; CMP BYTE PTR DS:[EAX],0D 75 09 ; JNZ check_null 80 78 01 00 ; CMP BYTE PTR DS:[EAX+1],0 // check if the next is null because "string\n" is correct 74 03 ; JZ check_null C6 00 00 ; MOV BYTE PTR DS:[EAX],0 40 ; INC EAX 80 78 FF 00 ; CMP BYTE PTR DS:[EAX-1],0 // check_null 75 E1 ; JNZ redo 8B 44 24 04 ; mov eax, dword ptr [esp+04] // quit 90 90 90 90 90 ; reserved for the jmp 85 C0 ; test eax, eax 7 ; the amount of previous bytes /* sof2, elite force and possibly others (possible false positives!!!) */ BYTES_ORIGINALX 8B 44 24 04 ; mov eax, dword ptr [esp+04] 83 E8 00 ; sub eax, 00000000 BYTES_PATCHX 8B 44 24 08 ; MOV EAX,DWORD PTR SS:[ESP+8] 85 C0 ; TEST EAX,EAX 74 1F ; JE quit 90 90 90 // 80 38 3B ; CMP BYTE PTR DS:[EAX],3B // redo 90 90 // 74 0A ; JE check 80 38 0A ; CMP BYTE PTR DS:[EAX],0A 74 05 ; JE check 80 38 0D ; CMP BYTE PTR DS:[EAX],0D 75 09 ; JNZ check_null 80 78 01 00 ; CMP BYTE PTR DS:[EAX+1],0 // check if the next is null because "string\n" is correct 74 03 ; JZ check_null C6 00 00 ; MOV BYTE PTR DS:[EAX],0 40 ; INC EAX 80 78 FF 00 ; CMP BYTE PTR DS:[EAX-1],0 // check_null 75 E1 ; JNZ redo 8B 44 24 04 ; mov eax, dword ptr [esp+04] // quit 90 90 90 90 90 ; reserved for the jmp 85 C0 ; test eax, eax 7 ; the amount of previous bytes =======================================================================================