
Free Information Xchange '98 presents:

Virtua Squad - CD crack by Static Vengeance

Requirements:
hex editor and full install

	Having already played (and cracked) Virtua Squad 2 (VS2), I thought I would look at Virtua Squad.
The first game is a bit older and as such doesn't support Direct3D which is shame.  However the game has
different "cases" (locations) to play so I decided to crack this one too.  And as long as I am going to go
through the effort I thought I would pass along what I learned from this one.  First the CD check routine
is nearly the same as the one used in VS2, but I added a few other comments to Virtua Squad's routine.  Okay,
lets get started, you will need to use W32Dasm to follow along.  Alright, first thing you need to do is to
disassemble the exe file ppjdd.exe.  Now when you run the game without the CD a dialog box comes up right
away and asks for the CD, no network option like VS2.  However, unlike VS2, there is a string ref you will
find while in W32Dasm.  Using the same old method, go up to the menu bar and select "Refs" and then select
"String data references" from the drop down menu.  Then from the Refs box, grab the slider bar and scroll down.
You will find the following string refs to check out: "Please insert VIRTUA SQUAD CD."  and like VS2 there is
a ref to the executable file on the CD with volume (path) name for you to check out:  "NATIVE\VCOP\PPJDD.EXE"
  So double click on the "Please insert..." ref and that will drop you right in the middle of the routine
that checks for the CD.  If you doulble click on the exe file's path you will be in the middle of the code
that looks for the file on the CD, which is actual CD check.  So let's begin with the section that asks
the user to put the CD in the drive and see where things go from there:

* Referenced by a CALL at Address:
|:004094D6                                   <-- Where the called came from, we'll make use of this later
|
:0040AEA0 56                      push esi

* Reference To: USER32.MessageBoxA, Ord:0197h
                                  |
:0040AEA1 8B3530C42D01            mov esi, dword ptr [012DC430]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AEDB(C)
|
:0040AEA7 E864FFFFFF              call 0040AE10                  <-- Actual CD check routine (see below)

* Possible StringData Ref from Data Obj ->"VIRTUA SQUAD"
                                  |
:0040AEAC 8B0D10674800            mov ecx, dword ptr [00486710]
:0040AEB2 A3EC452D01              mov dword ptr [012D45EC], eax  <-- Get the result of the CD check from here
:0040AEB7 83F8FF                  cmp eax, FFFFFFFF              <-- Compare against known fail value
:0040AEBA A1202D2D01              mov eax, dword ptr [012D2D20]
:0040AEBF 7520                    jne 0040AEE1                   <-- Take this jump if the CD check passed
:0040AEC1 6A35                    push 00000035                  <-- Otherwise "fall" through and ask for
:0040AEC3 85C0                    test eax, eax                  <-- the user to put the CD in the drive.
:0040AEC5 51                      push ecx
:0040AEC6 7407                    je 0040AECF

* Possible StringData Ref from Data Obj ->"VIRTUA SQUAD "
                                  |
:0040AEC8 6890684800              push 00486890
:0040AECD EB05                    jmp 0040AED4

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AEC6(C)
|
* Possible StringData Ref from Data Obj ->"Please insert VIRTUA SQUAD CD."  <-- String which lead us here
                                  |
:0040AECF 6870684800              push 00486870

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AECD(U)
|
:0040AED4 6A00                    push 00000000
:0040AED6 FFD6                    call esi                      <-- Do the pop up dialog box
:0040AED8 83F802                  cmp eax, 00000002             <-- 00000002 means you hit "cancel"
:0040AEDB 75CA                    jne 0040AEA7                  <-- Otherwise loop back up and check again
:0040AEDD 33C0                    xor eax, eax                  <-- A zero in eax means CD check failed
:0040AEDF 5E                      pop esi
:0040AEE0 C3                      ret                           <-- Return to caller with result

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AEBF(C)
|
:0040AEE1 B801000000              mov eax, 00000001             <-- A one in eax means CD check passed!
:0040AEE6 5E                      pop esi
:0040AEE7 C3                      ret                           <-- Return to caller

	That was the code that asks the user to put the CD in the drive if not found during the CD check.
We now have enough information to crack this one.  We know where the call to the above routine is made
from and we know a successful call returns with 00000001 in eax.  However, becuase this is a tutorial I'll
also show you the routine that checks for the CD.  That routine is at 40AE10 and looks alot like this:

* Referenced by a CALL at Address:
|:0040AEA7   
|
:0040AE10 83EC50                  sub esp, 00000050
:0040AE13 53                      push ebx
:0040AE14 56                      push esi
:0040AE15 57                      push edi
:0040AE16 33DB                    xor ebx, ebx                   <-- Try/retry counter, zero it out
:0040AE18 55                      push ebp

* Reference To: KERNEL32.GetLogicalDrives, Ord:00E7h             <-- Good text string to search for is
                                  |                              <-- "GetLogicalDrives"
:0040AE19 FF15E8C32D01            Call dword ptr [012DC3E8]
:0040AE1F 8BE8                    mov ebp, eax

* Reference To: KERNEL32._lopen, Ord:0262h
                                  |
:0040AE21 8B350CC42D01            mov esi, dword ptr [012DC40C]

* Reference To: KERNEL32.GetDriveTypeA, Ord:00CEh                <-- Another useful text string would be
                                  |                              <-- "GetDriveType"
:0040AE27 8B3DD4C32D01            mov edi, dword ptr [012DC3D4]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AE7F(C)
|
:0040AE2D B801000000              mov eax, 00000001
:0040AE32 8ACB                    mov cl, bl
:0040AE34 D3E0                    shl eax, cl
:0040AE36 85C5                    test ebp, eax
:0040AE38 7441                    je 0040AE7B
:0040AE3A 8D4341                  lea eax, dword ptr [ebx+41]
:0040AE3D 8D4C2410                lea ecx, dword ptr [esp+10]
:0040AE41 50                      push eax

* Possible StringData Ref from Data Obj ->"%c:\"                <-- Commonly used Ref string in CD checks
                                  |
:0040AE42 6868684800              push 00486868
:0040AE47 51                      push ecx

* Reference To: USER32.wsprintfA, Ord:026Ch
                                  |
:0040AE48 FF15A4C42D01            Call dword ptr [012DC4A4]
:0040AE4E 8D4C241C                lea ecx, dword ptr [esp+1C]
:0040AE52 83C40C                  add esp, 0000000C
:0040AE55 51                      push ecx
:0040AE56 FFD7                    call edi
:0040AE58 83F805                  cmp eax, 00000005
:0040AE5B 751E                    jne 0040AE7B
:0040AE5D 8D442410                lea eax, dword ptr [esp+10]

* Possible StringData Ref from Data Obj ->"NATIVE\VCOP\PPJDD.EXE"  <-- File to check for with the CD path
                                  |
:0040AE61 6850684800              push 00486850
:0040AE66 50                      push eax

* Reference To: KERNEL32.lstrcatA, Ord:0266h
                                  |
:0040AE67 FF15D0C32D01            Call dword ptr [012DC3D0]
:0040AE6D 8D442410                lea eax, dword ptr [esp+10]
:0040AE71 6A00                    push 00000000
:0040AE73 50                      push eax
:0040AE74 FFD6                    call esi
:0040AE76 83F8FF                  cmp eax, FFFFFFFF
:0040AE79 7508                    jne 0040AE83                <-- Take this jump if the file was read

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0040AE38(C), :0040AE5B(C)
|
:0040AE7B 43                      inc ebx                     <-- Made another check, add 1 to ebx
:0040AE7C 83FB20                  cmp ebx, 00000020           <-- Try up to 20h (32) times
:0040AE7F 7CAC                    jl 0040AE2D                 <-- Keep trying to find the CD until you hit 32
:0040AE81 EB07                    jmp 0040AE8A                <-- Tried 32 times and STILL didn't find it

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AE79(C)
|
:0040AE83 50                      push eax

* Reference To: KERNEL32._lclose, Ord:025Fh
                                  |
:0040AE84 FF15CCC32D01            Call dword ptr [012DC3CC]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AE81(U)
|
:0040AE8A B8FFFFFFFF              mov eax, FFFFFFFF        <-- This is the fail value
:0040AE8F 83FB20                  cmp ebx, 00000020        <-- Did we fail to find the file 32 times?
:0040AE92 7402                    je 0040AE96              <-- If yes, take this jump  CD check=fail
:0040AE94 8BC3                    mov eax, ebx             <-- This is THE vital instruction for pass/fail
                                                           <-- anything other than FFFFFFFF = pass
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040AE92(C)
|
:0040AE96 5D                      pop ebp
:0040AE97 5F                      pop edi
:0040AE98 5E                      pop esi
:0040AE99 5B                      pop ebx
:0040AE9A 83C450                  add esp, 00000050
:0040AE9D C3                      ret                      <-- Finally return to the caller

	While it's not completely important that you understand each and every instruction and or compare,
you need to see (understand) the general "flow" of the code.  You start off by getting the drive location
(ie drive D, or whatever, is the CD rom), then check for the file on the CD.  The one thing that you really
need to pay attention to is the "return to caller" section of the routine.  This is where the vital choise
is made between pass or fail.  Then back track (through the callers) and find a "good" spot to make your
patch.  One method of cracking Virtua Squad would be to change the je 0040AE96 (at 40AE94) to two NOP's.
This would allow the code to fall through and set up for a "good" CD check (the mov eax, ebx).  However,
I have always believed, why actually go through the CD check routine if you don't HAVE to, right?  That's
why I back track up to a higher level to disable the routine.  As such, let's take a look at the first
section of code where it was called from 4094D6.  We need to list the surounding code (at 4094D6) and see
what we have.

  -- Program Code --
:004094CD 8B44243C                mov eax, dword ptr [esp+3C]
:004094D1 A300152D01              mov dword ptr [012D1500], eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004094B2(C)
|
:004094D6 E8C5190000              call 0040AEA0         <-- Do the whole CD check routine
:004094DB 85C0                    test eax, eax         <-- Test the value returned in eax
:004094DD 750C                    jne 004094EB          <-- Take this jump for a good CD check
:004094DF 33C0                    xor eax, eax          <-- Otherwise set up to quit back to Win95
:004094E1 5D                      pop ebp
:004094E2 5F                      pop edi
:004094E3 5E                      pop esi
:004094E4 5B                      pop ebx
:004094E5 83C420                  add esp, 00000020
:004094E8 C21000                  ret 0010

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004094DD(C)
|
:004094EB 8B7C2440                mov edi, dword ptr [esp+40]
:004094EF 57                      push edi
:004094F0 53                      push ebx
:004094F1 E87A020000              call 00409770
:004094F6 83C408                  add esp, 00000008
  -- Continuing Program Code --

	From here you can see the "only" thing you need to do is to change the call to the CD check to
mov eax, 00000001.  This will in turn force the jne 4094EB to always be taken.  Which, of course, allows
you to play Virtua Squad without having the CD in your CD Rom drive!  Now you need to make the patch to
file.  There are two versions of the game on the CD that I had to look at.  One for Direct Draw called
ppjdd.exe and one that's a native NVida port called vcop.exe.  Too bad there's not a D3D version or a
native glide port for this game.  Anyways, here are the edits for both files:

Edit ppjdd.exe at offset 35,030
===============================
Search for: E8 C5 19 00 00
Chagne to : B8 01 00 00 00

Edit vcop.exe at offset 266,968
===============================
Search for: E8 B7 17 00 00
Chagne to : B8 01 00 00 00

	Another game has been FiX'ed with a little help from your humble author...  Until next time,
practice on something and put out a tutorial for the rest of us to read.  That way I'll know someone
is reading (and learning from) these articles I put out.

Static Vengeance
