#include #include #include #include #include #include #include //How I figured out where to patch the Shadow Warrior executable: // // (Numbers are from the Shadow Warrior v1.2 shareware executable) // //Step 1: Look for this unique sequence of bytes in the EXE: // // ;(Somewhere inside JS_ProcessEchoSpot function in jsector.c) // C13A1: 66 3D C8 00 cmp ax, 200 // C13A5: 7E 05 jle l1 // C13A7: B8 C8 00 00 00 mov eax, 200 // C13AC: 66 3D 64 00 l1: cmp ax, 100 // C13B0: 7D 05 jge l2 // C13B2: B8 64 00 00 00 mov eax, 100 // C13B7: 98 l2: cwde // C13B8: B3 01 mov bl, 1 // C13BA: E8 D9 9A FD FF call COVER_SetReverb // C13BF: 88 1C 24 89 mov [esp], bl // // Try looking for "66 3D C8 00 7E 05" - it's unlikely to have duplicates // //Step 2: Find the target of the COVER_SetReverb call. You can identify the // call statement because it will be the only byte nearby that's an E8. // The 4 numbers after it make up the RELATIVE jump. Add this value to // the position of the byte RIGHT AFTER the 5-byte call statement. Here's // how you do the calculation for my example: // // C13BF + FFFD9AD9 = 9AE98 // // That's all you need - 9AE98 is the magic offset! // // Just for fun, let's see what's there: // // COVER_SetReverb: // 9AE98: 83 3D CC 54 0A 00 08 cmp dword ptr [variable], 8 // 9AE9F: 74 F5 je l3 ;points to C3 (ret) // 9AEA1: E9 4E 5F 0A 00 jmp l4 ;jump to FX_SetReverb? // //Step 3: Replace the first byte of the COVER_SetReverb function with a // return (C3) // // 9AE98: C3 ret // 9AE99: 3D CC 54 ... ;invalid opcodes, but who cares! // //---------------------------------------------------------------------- // // Here are the values for Shadow Warrior v1.2 (registered): // // C26F6: E8 11 91 FD FF call COVER_SetReverb // // COVER_SetReverb: // 9B80C: 83 3D 80 AA 0B 00 08 cmp dword ptr [variable], 8 main () { int fil, i; long fileng, offs; unsigned char ch, tempbuf[8]; puts(""); puts("SWSNDFX for Shadow Warrior by Kenneth Silverman (04/28/2000)"); puts(""); puts("This program fixes a sound crashing bug in SW.EXE that occurs on newer"); puts(" (PCI?) sound cards. If the game crashes when going underwater or going"); puts(" on the train tracks of the 1st level, then you've found the right program."); puts(""); puts("Please note: This program supports ONLY these versions of Shadow Warrior:"); puts(" v1.2 Shareware and Registered"); puts(""); puts(" None of the 3dfx versions are currently supported."); puts(""); puts("Also, be aware that as a side effect, reverberation will be disabled."); puts(""); puts("Do you want to continue with patching SW.EXE? (Y/N)"); do { ch = getch(); } while ((ch != 'n') && (ch != 'N') && (ch != 'y') && (ch != 'Y') && (ch != 27)); if ((ch == 'n') || (ch == 'N') || (ch == 27)) { puts("Operation aborted"); exit(0); } if ((fil = open("SW.EXE",O_BINARY|O_RDWR,S_IREAD)) == -1) { puts("ERROR 1: Can't read SW.EXE: Make sure it is in the current directory."); exit(0); } fileng = filelength(fil); offs = -1; if (fileng == 2324603) offs = 0x9ae98; //1.2 (shareware) if (fileng == 2323389) offs = 0x9b80c; //1.2 (registered) if (offs == -1) { puts("ERROR 2: SW.EXE unrecognized or not currently supported."); exit(0); } lseek(fil,offs,SEEK_SET); read(fil,tempbuf,8); close(fil); if (fileng == 2324603) { if ((tempbuf[0] == 0xc3) && (tempbuf[1] == 0x3d) && (tempbuf[2] == 0xcc) && (tempbuf[3] == 0x54) && (tempbuf[4] == 0x0a) && (tempbuf[5] == 0x00) && (tempbuf[6] == 0x08) && (tempbuf[7] == 0x74)) { puts("This sound patch has already been applied to SW.EXE."); exit(0); } if ((tempbuf[0] != 0x83) || (tempbuf[1] != 0x3d) || (tempbuf[2] != 0xcc) || (tempbuf[3] != 0x54) || (tempbuf[4] != 0x0a) || (tempbuf[5] != 0x00) || (tempbuf[6] != 0x08) || (tempbuf[7] != 0x74)) { puts("ERROR 3: SW.EXE unrecognized, or not currently supported."); exit(0); } } if (fileng == 2323389) { if ((tempbuf[0] == 0xc3) && (tempbuf[1] == 0x3d) && (tempbuf[2] == 0x80) && (tempbuf[3] == 0xaa) && (tempbuf[4] == 0x0b) && (tempbuf[5] == 0x00) && (tempbuf[6] == 0x08) && (tempbuf[7] == 0x74)) { puts("This sound patch has already been applied to SW.EXE."); exit(0); } if ((tempbuf[0] != 0x83) || (tempbuf[1] != 0x3d) || (tempbuf[2] != 0x80) || (tempbuf[3] != 0xaa) || (tempbuf[4] != 0x0b) || (tempbuf[5] != 0x00) || (tempbuf[6] != 0x08) || (tempbuf[7] != 0x74)) { puts("ERROR 3: SW.EXE unrecognized, or not currently supported."); exit(0); } } //Actually modify the exe here: if ((fil = open("SW.EXE",O_BINARY|O_RDWR,S_IWRITE)) == -1) { puts("ERROR 4: Can't write to SW.EXE: Make sure it has write priviledges."); exit(0); } lseek(fil,offs,SEEK_SET); tempbuf[0] = 0xc3; write(fil,tempbuf,1); close(fil); puts("SUCCESS! SW.EXE has been patched to prevent the sound crashing bug."); }