How to defeat a cd-lock protection
by zoltan
(24 September 1999)

CD-ROM faking

Courtesy of reverser's pages of reverse engineering ~ slightly edited by reverser+

written by (c) zoltan

As example: COMMANDOS: Behind Enemy Lines
TOOLS REQUIRED: - SoftIce 4.0 W32Dasm, (if you want to follow) Hackers View 6.15 TARGET: Commandos: Behind Enemy Lines - buy it or get the ripp + original exe. Visit the tools section of our web page: a nice tool site...

Briefing about cd-lock:

Today nearly all games that get published has a form of protection called iSO protection (in the scene). It is there to prevent end-users for pirating cd's by just copying them at home with cd-burners. Today im going to Teach you how to reverse one of these protections called CD-LOCK. You check if the cd you have is protected by CD-LOCK: simply explore your cd-drive and look for 4 huge (.afp) files.


Another famous game: Commandos. This one was released to the public by CLASS PC on the 24th of June 1998. It's been availible for download on the internet ever since. Think i leeched it the same day, and got the original (protected) exe from some friends. I started cracking this (cd-check) like i thought it was, because i had never even heard of this cd-lock protection. Anyway i cracked it fairly easy, but i had to admit to myself that this must have been one of the hardest (cd-check, like i thought) i had ever done.
Few months later i heard about the cd-lock protection schemes, and i was like "uhh ohh? that protection got it's own name, cool!" ;). I actually love cracking protections that got their own name, like CD-lock, gives sorta feeling for the scheme...
Anyways enough crap chat... let's begin.

Start off by deleting the commandos.exe witch is Class' intro, or simply copy it over to another dir, if you want to collect that junk like i do. Now you may delete the betasux.exe, because that is the cracked exe from Class, and we dont need it, since we are going to crack this game ourselfs. Run commandos.exe, break on GetDriveTypea, press the "start a new game" option and you should be landing here:

* Referenced by a CALL at Address:0044CAFF      <- where this whole protection was
                                  |             <- called from ..
:004949F0 83EC08                  sub esp, 00000008
:004949F3 A1D0266000              mov eax, dword ptr [006026D0]
:004949F8 89442400                mov dword ptr [esp], eax
:004949FC 53                      push ebx
:004949FD 56                      push esi
:004949FE B341                    mov bl, 41
:00494A00 57                      push edi

* Reference To: KERNEL32.GetDriveTypeA, Ord:00CEh                  
:00494A01 8B3514266600            mov esi, dword ptr [00662614]

* Referenced by a Jump at Address:00494A8C(C)
:00494A07 8D44240C                lea eax, dword ptr [esp+0C]
:00494A0B 885C240C                mov byte ptr [esp+0C], bl
:00494A0F 50                      push eax
:00494A10 FFD6                    call esi                  <- you are here.
:00494A12 83F805                  cmp eax, 00000005         <- compare if drive is a cd-drive
:00494A15 7570                    jne 00494A87              <- jump if not equal

* Possible StringData Ref from Data Obj ->"rb"              <- string that means READ
:00494A17 68900F5F00              push 005F0F90
:00494A1C 881D10266000            mov byte ptr [00602610], bl

* Possible StringData Ref from Data Obj ->"d:\TBTP.AFP"          <- our friend.
:00494A22 6810266000              push 00602610                  <- cdletter:\TBTP.AFP
:00494A27 881D20266000            mov byte ptr [00602620], bl    <- cdletter:\BBVN.AFP
:00494A2D 881D30266000            mov byte ptr [00602630], bl    <- cdletter:\ETAO.AFP
:00494A33 881D40266000            mov byte ptr [00602640], bl    <- cdletter:\BTBW.AFP
:00494A39 E8D2A81300              call 005CF310                  <- check if they are there ..
:00494A3E 83C408                  add esp, 8
:00494A41 8BF8                    mov edi, eax         <- mov checksum result to edi
:00494A43 85FF                    test edi, edi        <- if edi == 1
:00494A45 750A                    jne 00494A51         <- the files exists! ..
:00494A47 C744241000000000        mov [esp+10], 0      <- mov [esp+10], 0 = file doesnt exist
:00494A4F EB2E                    jmp 00494A7F         <- jump and try again.

* Referenced by a Jump at Address:00494A45(C)
:00494A51 6A00                    push 00000000
:00494A53 6800A08329              push 2983A000
:00494A58 57                      push edi
:00494A59 E8C2AD1300              call 005CF820                  <- SetFilePointer
:00494A5E 83C40C                  add esp, 0000000C
:00494A61 57                      push edi
:00494A62 E879AD1300              call 005CF7E0                  <- ReadFile
:00494A67 83C404                  add esp, 00000004
:00494A6A 33C9                    xor ecx, ecx
:00494A6C 83F829                  cmp eax, 00000029              <- compare ...
:00494A6F 0F94C1                  sete cl
:00494A72 894C2410                mov dword ptr [esp+10], ecx
:00494A76 57                      push edi
:00494A77 E8F4A71300              call 005CF270
:00494A7C 83C404                  add esp, 00000004

* Referenced by a Jump at Address:00494A4F(U)
:00494A7F 8B442410        mov eax, dword ptr [esp+10]   <- if [esp+10] = 1 your good cracker.
:00494A83 85C0            test eax, eax                 <- if eax == 1 then jump ..
:00494A85 7514            jne 00494A9B                  <- continue with game ...

* Referenced by a Jump at Address:00494A15(C)
:00494A87 FEC3            inc bl
:00494A89 80FB5A          cmp bl, 5A                    <- compare bl, 5Ah
:00494A8C 0F8E75FFFFFF    jle 00494A07                  <- jump and try again with next drive.
:00494A92 33C0            xor eax, eax                  <- baad cracker.
:00494A94 5F...           ...popout and ret

* Referenced by a Jump at Address:00494A85(C)
:00494A9B B801000000      mov eax, 00000001             <-  good cracker.
:00494AA0 5F...           ...popout and ret
NOW. goto the code location where all this crap was called from, you should be here:

* Referenced by a CALL at Addresses:00447E9C, :00448015       <- (here are the 2 calls)
:0044CAF0 83EC0C                  sub esp, 0000000C
:0044CAF3 A1980A5F00              mov eax, dword ptr [005F0A98]
:0044CAF8 85C0                    test eax, eax
:0044CAFA 90                      nop
:0044CAFB 53                      push ebx
:0044CAFC 56                      push esi
:0044CAFD 7413                    je 0044CB12
:0044CAFF E8EC7E0400              call 004949F0                  <- call check ..
:0044CB04 85C0                    test eax, eax                  <- eax=1
:0044CB06 740A                    je 0044CB12                    <- continue with game ..
:0044CB08 C705980A5F0000000000    mov dword ptr [005F0A98], 00000000

* Referenced by a Jump at Addresses:0044CAFD(C), :0044CB06(C)
* Possible StringData Ref from Data Obj ->"rb"
:0044CB12 68900F5F00              push 005F0F90
:0044CB17 BB00000000              mov ebx, 00000000

* Possible StringData Ref from Data Obj ->"d:\TBTP.AFP"
:0044CB1C 6810266000              push 00602610
:0044CB21 E8EA271800              call 005CF310
:0044CB26 83C408                  add esp, 00000008
:0044CB29 8BF0                    mov esi, eax
more code, more code... but you don't need to care about it ...

The best and the simplest way to crack this protection is probably to find where the protection was called from and then just simply cut inside like this:
:00447E91 8883100D0000            mov byte ptr [ebx+00000D10], al
:00447E97 E834321200              call 0056B0D0
:00447E9C E84F4C0000              call 0044CAF0      <- where it was called from the first time.
:00447EA1 85C0                    test eax, eax      <- eax=1: good cracker, eax=0: baad cracker
:00447EA3 7418                    je 00447EBD        <- continue with game ..
:00447EA5 8D442418                lea eax, dword ptr [esp+18]
:00447EA9 8B4C2434                mov ecx, dword ptr [esp+34]

Second Call:
* Referenced by a Jump at Address:0044800C(U)
:00448015 E8D64A0000              call 0044CAF0      <- where it got called from the 2th time.
:0044801A 85C0                    test eax, eax      <- same as above. 
:0044801C 7418                    je 00448036        <- same as above..
:0044801E 8D442418                lea eax, dword ptr [esp+18]
You simply change both calls to mov eax, 1, and the game should run smooth. ;)

Special greets to: BMonkey, Carphatia, Reverser+, Neural_Noise ...


You'r deep inside reverser's pages of reverse engineering, choose your way out!



red homepage red links red anonymity red +ORC red students' essays red academy database red bots wars
red antismut red tools red cocktails red javascript wars red search_forms red mail_fravia
red Is reverse engineering illegal?