Free Information Xchange '98 presents:

Ultim@te Race Pro - CD crack by Static Vengeance

Requirements:
Hex editor and full game install
W32Dasm if you wish to follow along

	Ultim@te Race Pro (URP) is a great racing sim that really shows off what one of the new VooDoo2
cards can do.  It also supports PowerVR cards in native SGL mode and other 3D cards with Direct3D.  Anyways,
there is one little problem with the game that needs to be FiX'ed and that is the CD check.  When you try
to run the game without the CD up pops a standard Win95 dialog box and it tells you to "Insert the Ultim@te
Race Pro CD-ROM !!!"  Great, no problem we'll just disassemble the game exe with W32Dasm and track down the
string.  Well, when I tried to disassemble the file W32Dasm came up and started, but the code segment had
an offset of 00000000 and a size of 00000000.  So no code listed was generated.  I ended up with this:

Disassembly of File: Ultim@te Race Pro.exe
Code Offset = 00000000, Code Size = 00000000  <-- Something is wrong here!
Data Offset = 00106A00, Data Size = 00041600

Number of Objects = 0006 (dec), Imagebase = 00400000h

   Object01: .text    RVA: 00001000 Offset: 00000400 Size: 00102400 Flags: C0000020  <-- here is a clue
   Object02: .rdata   RVA: 00104000 Offset: 00102800 Size: 00004200 Flags: 40000040
   Object03: .data    RVA: 00109000 Offset: 00106A00 Size: 00041600 Flags: C0000040
   Object04: .idata   RVA: 004EF000 Offset: 00148000 Size: 00001400 Flags: C0000040
   Object05:          RVA: 004F1000 Offset: 00149400 Size: 00001400 Flags: C0000040
   Object06: .rsrc    RVA: 004F3000 Offset: 0014A800 Size: 00001800 Flags: 40000040

	Hmmmmmmmm... there must be some type of problem in the internal file link.  So I started comparing
disassembly listings for other programs I had cracked like Powerboat Racing:

Disassembly of File: PBoat.exe
Code Offset = 00000400, Code Size = 00097800  <-- Everything seems ok here
Data Offset = 00097C00, Data Size = 0000DC00

Number of Objects = 0006 (dec), Imagebase = 00400000h

   Object01: BEGTEXT  RVA: 00001000 Offset: 00000400 Size: 00097800 Flags: 60000020  <-- Different values here
   Object02: DGROUP   RVA: 00099000 Offset: 00097C00 Size: 0000DC00 Flags: C0000040
   Object03: .bss     RVA: 000A7000 Offset: 00000000 Size: 00048800 Flags: C0000080
   Object04: .idata   RVA: 000F0000 Offset: 000A5800 Size: 00001000 Flags: C0000040
   Object05: .reloc   RVA: 000F1000 Offset: 000A6800 Size: 00010000 Flags: 42000040
   Object06: .rsrc    RVA: 00101000 Offset: 000B6800 Size: 00001200 Flags: 40000040

	The more comparisons I did the more I noticed that the "Flags" for the code section were usually
60000020 and in URP it was C0000020 and most programs the code had an offset or 400h.  So I got HEdit up and
running and looked at the first section of the URP file.  Then I compared it's structure against other games
that I had cracked.  Seeing the general pattern, the only real difference seemed to be the Flag value of
C0000020.  So I renamed the URP exe file and copied another copy to the directory I was working in.  Then
I editted the renamed copy to change the Flags value to 60000020.  At offset 412 I changed the 20 to a 40
and at 415 I changed the C0 to 60.  Then I tried to disassmble it again with W32Dasm and it worked!  I was
rewarded with a disassmbled listing of Ultim@te Race Pro that I could start poking around in.  So now it's
back to the normal routine of going up to the menu bar and selecting "Refs" and then select "String data
references" from the drop down menu.  Now, in the pop up reference box scroll down until you see the string
"Insert the Ultim@te Race Pro CD-ROM" double click on it and W32Dasm will put you in the middle of the CD
checking routine that looks like this:

* Referenced by a CALL at Address:
|:00493BEF                                              <-- Where it was called from
|
:00493DE0 81EC00020000            sub esp, 00000200

* Possible StringData Ref from Data Obj ->"CD_NEEDED"
                                  |
:00493DE6 B964575300              mov ecx, 00535764
:00493DEB E8D0F10000              call 004A2FC0
:00493DF0 85C0                    test eax, eax
:00493DF2 0F84D0000000            je 00493EC8
:00493DF8 8D8C2400010000          lea ecx, dword ptr [esp+00000100]
:00493DFF E88CFDFFFF              call 00493B90
:00493E04 8D842400010000          lea eax, dword ptr [esp+00000100]

* Possible StringData Ref from Data Obj ->"French"            <-- Various languages supported
                                  |
:00493E0B 6864125200              push 00521264
:00493E10 50                      push eax
:00493E11 E82A390600              call 004F7740
:00493E16 83C408                  add esp, 00000008
:00493E19 85C0                    test eax, eax
:00493E1B 750A                    jne 00493E27

* Possible StringData Ref from Data Obj ->"Ins"
                                  |
:00493E1D 6890585300              push 00535890
:00493E22 E994000000              jmp 00493EBB

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493E1B(C)
|
:00493E27 8D942400010000          lea edx, dword ptr [esp+00000100]

* Possible StringData Ref from Data Obj ->"Spanish"
                                  |
:00493E2E 6844125200              push 00521244
:00493E33 52                      push edx
:00493E34 E807390600              call 004F7740
:00493E39 83C408                  add esp, 00000008
:00493E3C 85C0                    test eax, eax
:00493E3E 750C                    jne 00493E4C
:00493E40 8D442400                lea eax, dword ptr [esp]
:00493E44 6864585300              push 00535864
:00493E49 50                      push eax
:00493E4A EB74                    jmp 00493EC0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493E3E(C)
|
:00493E4C 8D8C2400010000          lea ecx, dword ptr [esp+00000100]

* Possible StringData Ref from Data Obj ->"German"
                                  |
:00493E53 6854125200              push 00521254
:00493E58 51                      push ecx
:00493E59 E8E2380600              call 004F7740
:00493E5E 83C408                  add esp, 00000008
:00493E61 85C0                    test eax, eax
:00493E63 750C                    jne 00493E71
:00493E65 8D542400                lea edx, dword ptr [esp]

* Possible StringData Ref from Data Obj ->"Legen Sie die Ultim@te Race Pro-CD!!!"  <-- Say it in German
                                  |
:00493E69 683C585300              push 0053583C
:00493E6E 52                      push edx
:00493E6F EB4F                    jmp 00493EC0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493E63(C)
|
:00493E71 8D842400010000          lea eax, dword ptr [esp+00000100]

* Possible StringData Ref from Data Obj ->"Italian"
                                  |
:00493E78 6834585300              push 00535834
:00493E7D 50                      push eax
:00493E7E E8BD380600              call 004F7740
:00493E83 83C408                  add esp, 00000008
:00493E86 85C0                    test eax, eax
:00493E88 7507                    jne 00493E91

* Possible StringData Ref from Data Obj ->"Inserire il CD Ultim@te Race Pro "  <-- Say it in Italian
                                        ->"!!!"
                                  |
:00493E8A 680C585300              push 0053580C
:00493E8F EB2A                    jmp 00493EBB

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493E88(C)
|
:00493E91 8D942400010000          lea edx, dword ptr [esp+00000100]

* Possible StringData Ref from Data Obj ->"Portuguese"
                                  |
:00493E98 6838125200              push 00521238
:00493E9D 52                      push edx
:00493E9E E89D380600              call 004F7740
:00493EA3 83C408                  add esp, 00000008
:00493EA6 85C0                    test eax, eax
:00493EA8 750C                    jne 00493EB6
:00493EAA 8D442400                lea eax, dword ptr [esp]

* Possible StringData Ref from Data Obj ->"Coloque o CD de Ultim@te Race "  <-- Say it in Portuguese?!?
                                        ->"Pro !!!"
                                  |
:00493EAE 68E4575300              push 005357E4
:00493EB3 50                      push eax
:00493EB4 EB0A                    jmp 00493EC0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493EA8(C)
|
* Possible StringData Ref from Data Obj ->"Insert the Ultim@te Race Pro CD-ROM "  <-- The string that got us
                                        ->"!!!"                                   <-- here in the first place
                                  |
:00493EB6 68BC575300              push 005357BC

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00493E22(U), :00493E8F(U)
|
:00493EBB 8D4C2404                lea ecx, dword ptr [esp+04]
:00493EBF 51                      push ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00493E4A(U), :00493E6F(U), :00493EB4(U)
|
:00493EC0 E88BF30500              call 004F3250
:00493EC5 83C408                  add esp, 00000008

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493DF2(C)
|
:00493EC8 A1500D8E00              mov eax, dword ptr [008E0D50]
:00493ECD 6835200000              push 00002035
:00493ED2 8D542404                lea edx, dword ptr [esp+04]

* Possible StringData Ref from Data Obj ->"Ultim@te Race Pro Message"
                                  |
:00493ED6 68147A5200              push 00527A14
:00493EDB 52                      push edx
:00493EDC 50                      push eax

* Reference To: USER32.MessageBoxA, Ord:0195h
                                  |
:00493EDD FF15E8F58E00            Call dword ptr [008EF5E8]
:00493EE3 83F802                  cmp eax, 00000002                 <-- 02 means you hit cancel
:00493EE6 7507                    jne 00493EEF
:00493EE8 33C9                    xor ecx, ecx
:00493EEA E8F14E0300              call 004C8DE0

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493EE6(C)
|
:00493EEF E81CDE0300              call 004D1D10
:00493EF4 81C400020000            add esp, 00000200
:00493EFA C3                      ret

	Alright now lets back trace the program a little and check out the routine that called the above
code to see what it does:

* Referenced by a CALL at Addresses:
|:00493C65   , :00493CB8                             <-- Called twice!
|
:00493BC0 56                      push esi
:00493BC1 8BF1                    mov esi, ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493BF4(U)
|
* Possible StringData Ref from Data Obj ->"CDROM:>Ultim@te Race Pro>Ultim@te "
                                        ->"Race Pro.exe"
                                  |
:00493BC3 B960565300              mov ecx, 00535660
:00493BC8 E883790300              call 004CB550
:00493BCD 85C0                    test eax, eax
:00493BCF 7525                    jne 00493BF6

* Possible StringData Ref from Data Obj ->"CDROM2:>Ultim@te Race Pro>Ultim@te "
                                        ->"Race Pro.exe"
                                  |
:00493BD1 B990565300              mov ecx, 00535690
:00493BD6 E875790300              call 004CB550
:00493BDB 85C0                    test eax, eax
:00493BDD 7517                    jne 00493BF6

* Possible StringData Ref from Data Obj ->"CDROM3:>Ultim@te Race Pro>Ultim@te "
                                        ->"Race Pro.exe"
                                  |
:00493BDF B9C0565300              mov ecx, 005356C0
:00493BE4 E867790300              call 004CB550
:00493BE9 85C0                    test eax, eax
:00493BEB 7509                    jne 00493BF6
:00493BED 8BCE                    mov ecx, esi
:00493BEF E8EC010000              call 00493DE0
:00493BF4 EBCD                    jmp 00493BC3

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00493BCF(C), :00493BDD(C), :00493BEB(C)
|
:00493BF6 5E                      pop esi
:00493BF7 C3                      ret

	Okay, so this routine seems to use some type of call interpeter, where the CDROM-CDROM3 are for
the different types of install options, ie: small, medium and full.  So I decided to go back on step more
and check out the two routines that called this new code above.


  -- Program Code --

:00493C55 B964575300              mov ecx, 00535764
:00493C5A E861F30000              call 004A2FC0
:00493C5F 85C0                    test eax, eax
:00493C61 7407                    je 00493C6A     <-- This conditional jump will be useful
:00493C63 8BCD                    mov ecx, ebp
:00493C65 E856FFFFFF              call 00493BC0   <-- Call the CD check routine

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00493C61(C)
|
:00493C6A 8BFD                    mov edi, ebp
:00493C6C 83C9FF                  or ecx, FFFFFFFF
:00493C6F 33C0                    xor eax, eax

  -- Continuing Program Code --

	No secondary flags or results checked after the call to the CD check routine.  But wait!, look
at the conditional jump (je or Jump Equal) at 493C61.  If taken, it'll jump over the CD check and 
continue the game, which is what we want.  So our edit here will be changing the conditional jump to a
non conditional jump.  Then this CD check is bypassed!  Now lets check the second call out:

  -- Program Code --

:00493CA0 8B442414                mov eax, dword ptr [esp+14]
:00493CA4 85C0                    test eax, eax
:00493CA6 7415                    je 00493CBD

* Possible StringData Ref from Data Obj ->"CD_NEEDED"
                                  |
:00493CA8 B964575300              mov ecx, 00535764
:00493CAD E80EF30000              call 004A2FC0
:00493CB2 85C0                    test eax, eax
:00493CB4 7407                    je 00493CBD     <-- Again, a useful conditional jump
:00493CB6 8BCD                    mov ecx, ebp
:00493CB8 E803FFFFFF              call 00493BC0   <-- Second call to the CD check routine

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00493CA6(C), :00493CB4(C)
|

* Possible StringData Ref from Data Obj ->"CDROM:>Ultim@te Race Pro>"
                                  |
:00493CBD BFF0565300              mov edi, 005356F0
:00493CC2 83C9FF                  or ecx, FFFFFFFF
:00493CC5 33C0                    xor eax, eax

  -- Continuing Program Code --

	Basicly that same as the first call to the CD check and we'll make the same type of edit here as
well.  I made the edit and ran URP to see the effect, it came right up and I raced around for a bit.  So
the only thing left to do is apply the actual edit.  Make the same edit at BOTH locations:

Edit Ultim@te Race Pro at BOTH
offsets of 602,209 AND 602,292
==============================
Search for: 85 C0 74 07 8B CD
Change to : -- -- EB -- -- --


Edit Ultim@te Race Pro v1.03 beta at BOTH
offsets of 607,023 AND 607,105
==============================
Search for: 85 C0 74 07 8B CD
Change to : -- -- EB -- -- --


For the Creative Labs Voodoo2 bundled version of Ultim@te Race Pro:

Edit Ultim@te Race Pro at BOTH
offsets of 602,751 AND 602,834
==============================
Search for: 85 C0 74 07 8B CD
Change to : -- -- EB -- -- --


	Ultim@te Race Pro is now FiX'ed and can be run completly from your hard drive without the need for
the original CD to be in your CD-ROM drive.  For future versions, try searching for "85 C0 74 07 8B CD" and
change the "74" to "EB", you should find two occurrances close together.  That should help you out with other
versions that may come out.

Static Vengeance