Free Information Xchange '97 presents: Virtua Fighter - CD Crack by Static Vengeance Requirements: Hex Editor and Full Install Ok, once again I set out to remove the CD check from a SEGA Entertainment game using W32Dasm from URSoft. Having already cracked two games by Sega (Daytona USA and Virtua Fighter 2) I thought this game would be striaght forward and fairly easy to do. However, just when you count on something being easy, it's not!.. So if you following along I'll show what I found and what I did to remove the CD check from this game. Also bear in mind that the program version I'm using is the updated DirectX v3b version of Virtua Fighter and not the version from the CD, although I have included a simular patch for that version also. Let's get going: Start up W32Dasm and 'Open file to disassemble' using vfpc.exe from where ever you installed it to. Once W32Dasm has finished it's process and is ready, go up to the title bar select 'Refs' and choose 'String data references'. From here grab the slider bar and scroll down looking at the strings. Eventually you find "Cannot find Virtua Fighter(TM) ". So double click on this and it puts you in the middle of the CD check routine. So let's take a look at the code: * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00505544(C), :00505558(C) | :00505565 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Virtua Fighter PC" | :00505567 68D0CFB000 push 00B0CFD0 * Reference To: USER32.FindWindowA, Ord:00C8h | :0050556C FF1598F5BE00 Call dword ptr [00BEF598] :00505572 8945DC mov dword ptr [ebp-24], eax :00505575 837DDC00 cmp dword ptr [ebp-24], 00000000 :00505579 0F8411000000 je 00505590 :0050557F 8B45DC mov eax, dword ptr [ebp-24] :00505582 50 push eax * Reference To: USER32.BringWindowToTop, Ord:000Ah | :00505583 FF15A0F5BE00 Call dword ptr [00BEF5A0] :00505589 33C0 xor eax, eax :0050558B E9D2000000 jmp 00505662 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00505579(C) | :00505590 E87FCEEFFF call 00402414 <-- Check for file on CD :00505595 85C0 test eax, eax <-- Did it pass? :00505597 0F844A000000 je 005055E7 <-- Take this jump for a pass * Reference To: KERNEL32.GetOEMCP, Ord:00F6h <-- Otherwise tell EVIL user to insert CD | :0050559D FF15BCF4BE00 Call dword ptr [00BEF4BC] :005055A3 8945B0 mov dword ptr [ebp-50], eax :005055A6 817DB0A4030000 cmp dword ptr [ebp-50], 000003A4 :005055AD 0F8519000000 jne 005055CC :005055B3 6A30 push 00000030 * Possible StringData Ref from Data Obj ->"Virtua Fighter PC" | :005055B5 68D0CFB000 push 00B0CFD0 * Possible StringData Ref from Data Obj ->"Virtua Fighter(TM) PC " | :005055BA 6820D0B000 push 00B0D020 :005055BF 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:0197h | :005055C1 FF1538F5BE00 Call dword ptr [00BEF538] :005055C7 E914000000 jmp 005055E0 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:005055AD(C) | :005055CC 6A30 push 00000030 * Possible StringData Ref from Data Obj ->"Virtua Fighter PC" | :005055CE 68D0CFB000 push 00B0CFD0 * Possible StringData Ref from Data Obj ->"Cannot find Virtua Fighter(TM) " <-- Seems like something we're ->"PC CD." <-- looking for, right? | :005055D3 68CCD0B000 push 00B0D0CC :005055D8 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:0197h | :005055DA FF1538F5BE00 Call dword ptr [00BEF538] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:005055C7(U) | :005055E0 33C0 xor eax, eax :005055E2 E97B000000 jmp 00505662 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00505597(C) | :005055E7 8B4510 mov eax, dword ptr [ebp+10] :005055EA 50 push eax :005055EB 8B4514 mov eax, dword ptr [ebp+14] :005055EE 50 push eax :005055EF 8B450C mov eax, dword ptr [ebp+0C] :005055F2 50 push eax :005055F3 8B4508 mov eax, dword ptr [ebp+08] :005055F6 50 push eax :005055F7 E815CCEFFF call 00402211 :005055FC 83C410 add esp, 00000010 :005055FF 85C0 test eax, eax :00505601 0F8507000000 jne 0050560E :00505607 33C0 xor eax, eax :00505609 E954000000 jmp 00505662 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00505601(C) | :0050560E C745E000000000 mov [ebp-20], 00000000 :00505615 8D45E0 lea eax, dword ptr [ebp-20] :00505618 50 push eax :00505619 68301C4000 push 00401C30 * Reference To: USER32.EnumWindows, Ord:00C3h | :0050561E FF15A4F5BE00 Call dword ptr [00BEF5A4] :00505624 837DE001 cmp dword ptr [ebp-20], 00000001 :00505628 0F8E07000000 jle 00505635 :0050562E 33C0 xor eax, eax :00505630 E92D000000 jmp 00505662 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00505628(C) | :00505635 A164395400 mov eax, dword ptr [00543964] :0050563A 50 push eax :0050563B 8B4514 mov eax, dword ptr [ebp+14] :0050563E 50 push eax :0050563F 8B4510 mov eax, dword ptr [ebp+10] :00505642 50 push eax :00505643 8B450C mov eax, dword ptr [ebp+0C] :00505646 50 push eax :00505647 8B4508 mov eax, dword ptr [ebp+08] :0050564A 50 push eax :0050564B E872CFEFFF call 004025C2 :00505650 83C414 add esp, 00000014 :00505653 8945EC mov dword ptr [ebp-14], eax :00505656 E888C7EFFF call 00401DE3 :0050565B 33C0 xor eax, eax :0050565D E900000000 jmp 00505662 * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0050553B(U), :00505560(U), :0050558B(U), :005055E2(U), :00505609(U) |:00505630(U), :0050565D(U) | :00505662 5F pop edi :00505663 5E pop esi :00505664 5B pop ebx :00505665 C9 leave :00505666 C21000 ret 0010 The first conditional branch before it prints "cannot find.." comes from 5055AD by way of listed reference at 5055CC.. so time to check out 5055AD and surounding code a little closer. We see the conditional branch/jump (jne) at 5055AD and a call to the KERNEL32.GetOEMCP... so back up some more... and you see at 505590 is a call, a test and a condition jump... this looks interesting... following the code you check out 402414 and will find it jumps to 4ACDF9. Alright, time to follow that section of code and try to see what it does: * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00402414(U) | :004ACDF9 55 push ebp :004ACDFA 8BEC mov ebp, esp :004ACDFC 81EC54010000 sub esp, 00000154 :004ACE02 53 push ebx :004ACE03 56 push esi :004ACE04 57 push edi * Possible StringData Ref from Data Obj ->"rb" | :004ACE05 68C011B400 push 00B411C0 * Possible StringData Ref from Data Obj ->"texture2.bin" <-- Check CD for this file | :004ACE0A 68C411B400 push 00B411C4 :004ACE0F E89250F5FF call 00401EA6 :004ACE14 83C404 add esp, 00000004 :004ACE17 50 push eax :004ACE18 E823F90700 call 0052C740 :004ACE1D 83C408 add esp, 00000008 :004ACE20 8945FC mov dword ptr [ebp-04], eax :004ACE23 837DFC00 cmp dword ptr [ebp-04], 00000000 :004ACE27 0F850A000000 jne 004ACE37 :004ACE2D B801000000 mov eax, 00000001 :004ACE32 E9B8000000 jmp 004ACEEF * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004ACE27(C) | :004ACE37 8B45FC mov eax, dword ptr [ebp-04] :004ACE3A 50 push eax :004ACE3B 6800010000 push 00000100 :004ACE40 6A01 push 00000001 :004ACE42 8D85ACFEFFFF lea eax, dword ptr [ebp+FFFFFEAC] :004ACE48 50 push eax :004ACE49 E812F90700 call 0052C760 :004ACE4E 83C410 add esp, 00000010 :004ACE51 8B45FC mov eax, dword ptr [ebp-04] :004ACE54 50 push eax :004ACE55 E826F80700 call 0052C680 :004ACE5A 83C404 add esp, 00000004 * Possible StringData Ref from Data Obj ->"\vfpc\vfrright.txt" <-- Path of file on CD to check for | :004ACE5D A1BC11B400 mov eax, dword ptr [00B411BC] :004ACE62 50 push eax :004ACE63 0FBE8548FFFFFF movsx eax, byte ptr [ebp+FFFFFF48] :004ACE6A 83C040 add eax, 00000040 :004ACE6D 50 push eax * Possible StringData Ref from Data Obj ->"%c:%s" | :004ACE6E 68D411B400 push 00B411D4 :004ACE73 8D45AC lea eax, dword ptr [ebp-54] :004ACE76 50 push eax :004ACE77 E824FD0700 call 0052CBA0 :004ACE7C 83C410 add esp, 00000010 :004ACE7F 6A00 push 00000000 :004ACE81 8D45AC lea eax, dword ptr [ebp-54] :004ACE84 50 push eax :004ACE85 E856ED0800 call 0053BBE0 :004ACE8A 83C408 add esp, 00000008 :004ACE8D 85C0 test eax, eax <-- Here's a test :004ACE8F 0F850C000000 jne 004ACEA1 <-- Not equal, look again :004ACE95 33C0 xor eax, eax <-- Good, make eax = zero :004ACE97 E953000000 jmp 004ACEEF <-- jmp to end of routine :004ACE9C E94E000000 jmp 004ACEEF * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004ACE8F(C) | * Possible StringData Ref from Data Obj ->"\vfpc\vfrright.txt" <-- File on CD again... | :004ACEA1 A1BC11B400 mov eax, dword ptr [00B411BC] :004ACEA6 50 push eax :004ACEA7 0FBE8547FFFFFF movsx eax, byte ptr [ebp+FFFFFF47] :004ACEAE 83C040 add eax, 00000040 :004ACEB1 50 push eax * Possible StringData Ref from Data Obj ->"%c:%s" | :004ACEB2 68DC11B400 push 00B411DC :004ACEB7 8D45AC lea eax, dword ptr [ebp-54] :004ACEBA 50 push eax :004ACEBB E8E0FC0700 call 0052CBA0 :004ACEC0 83C410 add esp, 00000010 :004ACEC3 6A00 push 00000000 :004ACEC5 8D45AC lea eax, dword ptr [ebp-54] :004ACEC8 50 push eax :004ACEC9 E812ED0800 call 0053BBE0 :004ACECE 83C408 add esp, 00000008 :004ACED1 85C0 test eax, eax <-- Test again :004ACED3 0F850C000000 jne 004ACEE5 <-- not equal, then fail :004ACED9 33C0 xor eax, eax <-- good, set eax to zero :004ACEDB E90F000000 jmp 004ACEEF <-- jmp to end :004ACEE0 E90A000000 jmp 004ACEEF * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004ACED3(C) | :004ACEE5 B801000000 mov eax, 00000001 <-- Force fail value (anything but zero) :004ACEEA E900000000 jmp 004ACEEF * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:004ACE32(U), :004ACE97(U), :004ACE9C(U), :004ACEDB(U), :004ACEE0(U) |:004ACEEA(U) | :004ACEEF 5F pop edi :004ACEF0 5E pop esi :004ACEF1 5B pop ebx :004ACEF2 C9 leave :004ACEF3 C3 ret I guess that seems fairly straight forward... now that I had looked into it a bit. This little section of code is THE determining factor in the CD check: :00505590 E87FCEEFFF call 00402414 <-- Check for \vfpc\vfrright.txt on CD :00505595 85C0 test eax, eax <-- Test the results of the CD check :00505597 0F844A000000 je 005055E7 <-- eax=zero is good check Ok, now we have the code responsible for the CD check, and we see the test and the single conditional jump for a pass or fail of that check. The edit comes in the form of replacing the call with instructions to xor eax,eax (eXcluse OR eax to itself, which zeros out eax and would be the same as a good CD check) which makes the je (jump on equal (zero)) always true. Then fill in the remainder of bytes with NOP's (No OPeration) The actual edits for the crack depends on the version you have: CD file version EDIT vfpc.exe (offset 1,058,725) ================================================ Search for: E8 9C F0 EF FF Change to : 33 C0 90 90 90 dx3b update version EDIT vfpc.exe (offset 1,067,408) ==================================================== Search for: E8 7F CE EF FF Change to : 33 C0 90 90 90 Now you can play Virtua Fighter without putting the CD in the CD-ROM drive first, becuase you have just FiX'ed this game. Static Vengeance