
Free Information Xchange presents:

Thief v1.14 - CD crack by R!SC - 10/01/99

REQUIREMENTS:
Hex editor
W32Dasm 8.93 !

  Do a full install, remove the CD, run the game. You get a standard messagebox asking you to 
insert the CD. "Missing CD"-"Please insert the CD into the CD Drive"

  First off, make a copy of thief.exe, load this into W32Dasm. We begin by looking through the
string references for one of our messages. Heh, I didnt find any ref's! So we take a different
approach. Look through the imported functions for a reference to KERNEL32.GetDriveTypeA
(commonly used in CD checks(as you remember!)). Double click on the reference several times,
looking at the code every time you click it. GetDriveTypeA returns a value in eax between 0 &
6, we are only intrested in the code that checks eax for a '5'. There is only one reference
that does this.


* Referenced by a CALL at Addresses:
|:0050D773   , :0050DA5E   <-- Trace the call back by double right clicking these (hit F12 to return)
|
:0050D720 8B442404                mov eax, dword ptr [esp+04]
:0050D724 50                      push eax            <-- Points to a null-terminated string that specifies
                                                        - the root directory of the disk to return information about.
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh       - this mean 'C:\',0 or whatever drive letter the caller might be on...
                                  |
:0050D725 FF1528315B00            Call dword ptr [005B3128]
:0050D72B 33C9                    xor ecx, ecx        <-- zero ecx (ecx=32bit reg, cx=16bit reg, cl=low 8bits of cx)
:0050D72D 83F805                  cmp eax, 00000005   <-- checking for a CD-ROM
:0050D730 0F94C1                  sete cl             <-- sets the byte in cl to a '01' if eax=5
:0050D733 8BC1                    mov eax, ecx        <-- copies ecx into eax (what the last command did or didnt set)
:0050D735 C3                      ret                 <-- Return to caller



 Normally, in most cases I have seen, when there's a call to a CD check, there is normally a test
and a conditional jump afterwards, the protection can be bypassed by either forcing the jump, or
not taking the call at all. So I wanted to trace this code back to the original caller. Using
WDasm 8.93! like I stated at the top, double right click the first caller '50D773'. This code is
right beneath the call to GetDriveTypeA.


* Referenced by a CALL at Addresses:
|:0050D7FA   , :0050D84D   
|
:0050D740 8B442404                mov eax, dword ptr [esp+04]
:0050D744 53                      push ebx
:0050D745 85C0                    test eax, eax
:0050D747 B341                    mov bl, 41          <-- 'A'
:0050D749 7444                    je 0050D78F
:0050D74B 8B4C240C                mov ecx, dword ptr [esp+0C]
:0050D74F 85C9                    test ecx, ecx
:0050D751 7410                    je 0050D763
:0050D753 0FBE00                  movsx eax, byte ptr [eax]
:0050D756 50                      push eax
:0050D757 E8D4EF0800              call 0059C730
:0050D75C 8BD8                    mov ebx, eax
:0050D75E 83C404                  add esp, 00000004
:0050D761 FEC3                    inc bl              <-- go onto the next drive letter...

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D751(C)
|
:0050D763 80FB5A                  cmp bl, 5A          <-- 'Z'
:0050D766 7F27                    jg 0050D78F           - simple routine to clear eax and ret

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D784(C)      <-- referenced to by itself
|

* Possible StringData Ref from Data Obj ->"D:\"
                                  |
:0050D768 6808BF6000              push 0060BF08       <-- pushes the drive letter were on
:0050D76D 881D08BF6000            mov byte ptr [0060BF08], bl  <-- stores the next letter to check
:0050D773 E8A8FFFFFF              call 0050D720       <-- call to GetDriveTypeA Subroutine that brought us here
:0050D778 83C404                  add esp, 00000004     - return a 01 in eax if weve got a CD-ROM
:0050D77B 85C0                    test eax, eax      
:0050D77D 7509                    jne 0050D788        <-- if eax in not equal(to 0) jump!
:0050D77F FEC3                    inc bl              <-- increase the letter
:0050D781 80FB5A                  cmp bl, 5A          <-- compare it with 'Z' 
:0050D784 7EE2                    jle 0050D768        <-- loop until we found a CD-ROM
:0050D786 5B                      pop ebx               - or ran out of drive letters
:0050D787 C3                      ret


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D77D(C)
|

* Possible StringData Ref from Data Obj ->"D:\"
                                  |
:0050D788 B808BF6000              mov eax, 0060BF08   <-- exit with the Drive letter of CD-Drive in eax
:0050D78D 5B                      pop ebx
:0050D78E C3                      ret

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0050D749(C), :0050D766(C)
|
:0050D78F 33C0                    xor eax, eax
:0050D791 5B                      pop ebx
:0050D792 C3                      ret


 This code starts with drive letter 'A' and calls our previous subroutine to determine if were
looking at a CD-ROM, if not it increases the letter and checks again. Anyway trace this back to
one of its callers. Double right click '50D7FA'

* Referenced by a CALL at Addresses:
|:0050D9CA   , :0050D9E1   <-- the original callers to this routine (trace these back)
|
:0050D7A0 81EC04010000            sub esp, 00000104
:0050D7A6 8D442400                lea eax, dword ptr [esp]
:0050D7AA 53                      push ebx
:0050D7AB 56                      push esi
:0050D7AC 57                      push edi
:0050D7AD 6804010000              push 00000104
:0050D7B2 50                      push eax

* Possible StringData Ref from Data Obj ->"cd_path"
                                  |
:0050D7B3 68C0BF6000              push 0060BFC0
:0050D7B8 33DB                    xor ebx, ebx
:0050D7BA E871B20300              call 00548A30
:0050D7BF 83C40C                  add esp, 0000000C
:0050D7C2 84C0                    test al, al
:0050D7C4 7528                    jne 0050D7EE        <-- this jne
:0050D7C6 BF18516700              mov edi, 00675118
:0050D7CB 83C9FF                  or ecx, FFFFFFFF
:0050D7CE 33C0                    xor eax, eax
:0050D7D0 8D54240C                lea edx, dword ptr [esp+0C]
:0050D7D4 F2                      repnz
:0050D7D5 AE                      scasb
:0050D7D6 F7D1                    not ecx
:0050D7D8 2BF9                    sub edi, ecx
:0050D7DA 8BC1                    mov eax, ecx
:0050D7DC 8BF7                    mov esi, edi
:0050D7DE 8BFA                    mov edi, edx
:0050D7E0 C1E902                  shr ecx, 02
:0050D7E3 F3                      repz
:0050D7E4 A5                      movsd
:0050D7E5 8BC8                    mov ecx, eax
:0050D7E7 83E103                  and ecx, 00000003
:0050D7EA F3                      repz
:0050D7EB A4                      movsb
:0050D7EC EB05                    jmp 0050D7F3        <-- this jmp

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D7C4(C)    <-- ref by same routine, the jne up there
|
:0050D7EE BB01000000              mov ebx, 00000001

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D7EC(U)    <-- ref by same routine, the jmp just up there.
|
:0050D7F3 8D4C240C                lea ecx, dword ptr [esp+0C]
:0050D7F7 6A00                    push 00000000
:0050D7F9 51                      push ecx
:0050D7FA E841FFFFFF              call 0050D740       <-- Call that we traced back
:0050D7FF 83C408                  add esp, 00000008
:0050D802 A314516700              mov dword ptr [00675114], eax <-- save varible in eax
:0050D807 85C0                    test eax, eax       <-- check return value of previous call
:0050D809 746B                    je 0050D876         <-- if it was zero we never found a CD-Drive


 Weve not get to the original caller to the CD-Check routine yet, so lets carry on tracing back.
Double right click '50D9CA' at the top of this code.

* Referenced by a CALL at Address:
|:0050DAD5   <-- only one caller this time ;)
|
:0050D9C0 C7051451670000000000    mov dword ptr [00675114], 00000000
:0050D9CA E8D1FDFFFF              call 0050D7A0       <-- Call that we just traced back
:0050D9CF 85C0                    test eax, eax       <-- check return value
:0050D9D1 7517                    jne 0050D9EA

 Goddamn it. Still not there yet, trace this back.
 
* Referenced by a CALL at Address:
|:00414FCC   <-- YIPPEE! only one caller and the code is located faraway near the start of the executable
|
:0050DAC0 6A00                    push 00000000
:0050DAC2 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"only_check_path"
                                  |
:0050DAC4 68E0BF6000              push 0060BFE0
:0050DAC9 E862AF0300              call 00548A30
:0050DACE 83C40C                  add esp, 0000000C
:0050DAD1 84C0                    test al, al
:0050DAD3 7507                    jne 0050DADC
:0050DAD5 E8E6FEFFFF              call 0050D9C0       <-- call we traced back
:0050DADA EB05                    jmp 0050DAE1

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050DAD3(C)
|
:0050DADC E82FFFFFFF              call 0050DA10       <-- see 'ps' at the bottom of the file

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050DADA(U)
|
:0050DAE1 85C0                    test eax, eax
:0050DAE3 7405                    je 0050DAEA
:0050DAE5 E986FBFFFF              jmp 0050D670

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050DAE3(C)
|
:0050DAEA 33C0                    xor eax, eax
:0050DAEC C3                      ret


 OK, Trace this back to 414FCC, I think weve found what weve been looking for at last..
 
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00414F9B(C), :00414FBF(C)
|
:00414FCC E8EF8A0F00              call 0050DAC0       <-- A CALL
:00414FD1 85C0                    test eax, eax       <-- A TEST
:00414FD3 750B                    jne 00414FE0        <-- A CONDITIONAL JUMP
:00414FD5 50                      push eax              - jump if eax not equal zero
:00414FD6 6A01                    push 00000001
:00414FD8 E8337B1100              call 0052CB10       <-- This traces to a call to Terminate Process
:00414FDD 83C408                  add esp, 00000008    -- Which is very BAD

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00414FD3(C)
|
:00414FE0 E8EB020000              call 004152D0
:00414FE5 8D542440                lea edx, dword ptr [esp+40]
:00414FE9 C744244003000000        mov [esp+40], 00000003
:00414FF1 52                      push edx
:00414FF2 6A01                    push 00000001

 OK, I(we) traced all those calls back to this one call at the start of the file, theres a
call, a test and a conditional jump. I first decided to force the jne by changing it to a jmp.
Saved my change to the code, and ran the game. Shit, it still asks for the CD, I clicked
cancel, then the bloody thing loaded into the game! OK, the message box is somewhere deep
inside of the CD-check routine. I decided to kill the call to the routine instead, so the CD is
never checked, the message box will never be shown, and the game will work? Highlight the call
to the check ':00414FCC E8EF8A0F00              call 0050DAC0' Write down the offset at the
bottom of the screen, probably 0143CC, hexedit thief.exe goto 143CC and change the E8 to a B8.
Save and run the game, it works fine now without needing the CD. 


 Another tutorial comes to an end and another game has been FiX'ed!
 
happy cracking love R!SC -- risc_1@hotmail.com

PS. If you trace back the second caller to GetDriveTypeA (0050DA5E), scroll up a bit, this is
referenced by a call at 50DADC, trace this back to routine, this one is referenced by 414FCC ;)
three easy steps to get there, you should always follow all the routes possible and check them
out, it pays off!


for v1.14 - edit thief.exe at offset 143CC (hex)
===========================================================
Search for: E8 EF 8A 0F 00    call 0050DAC0 
Change to : B8 -- -- -- --    mov  eax, 000F8AEF  (which is not 0, so the jne is always taken)

cleaner crack is b801000000 mov eax, 00000001,  but i think a 1 byte patch is nicer!

I borrowed these off someone else and included them here. (win32api.txt)

GetDriveType Return Function codes: (Donated by: +-=Riddler=-+)

 Value              Meaning
  0                 Drive Cannot Be determined
  1                 Root Dir Does not exist
  2                 DriveRemoveable
  3                 A Fixed Disk (HardDrive)  
  4                 Remote Drive(Network)
  5                 Cd-Rom Drive   <-- Game crackers only intrested if return code is 05!
  6                 RamDisk



