reversing a lame cd-check, pay attention boy! by R!SC -- risc@notme.com


starting from the top, cd-checks normally use kernel32!getdrivetypea to find out what sort of
drive they are looking at, you simply push a pointer to a drive letter, then after getdrivetypea
eax=03 for hard disk or eax=05 for a cd-rom.

so load crackcd.exe, enter softice, and type in 'bpx getdrivetypea'. Click on the CheckCD
button, and bingo! we have located the code to check the CD.. now pay close attention to the
comments in dead listing...



015F:004011B3  68EB234000          PUSH    004023EB	; pointer to 'kernel32.dll',0
015F:004011B8  E861070000          CALL    KERNEL32!LoadLibraryA
015F:004011BD  8BF0                MOV     ESI,EAX	; save address of kernel32 in esi
015F:004011BF  8D85E8FBFFFF        LEA     EAX,[EBP+FFFFFBE8]
015F:004011C5  50                  PUSH    EAX		; pointer to some free space
015F:004011C6  68F8234000          PUSH    004023F8	; pointer to getdrivetypea (wide char...)
015F:004011CB  E8C3020000          CALL    00401493	; convert it to normal, pasting it into the free space
015F:004011D0  83C408              ADD     ESP,08
015F:004011D3  8D95E8FBFFFF        LEA     EDX,[EBP+FFFFFBE8]
015F:004011D9  52                  PUSH    EDX		; points to the converted 'getdrivetypea'
015F:004011DA  56                  PUSH    ESI		; kernel32
015F:004011DB  E820070000          CALL    KERNEL32!GetProcAddress	; returns the address of 'getdrivetypea' in eax
015F:004011E0  6A00                PUSH    00		; null, return the drivetype of the current drive
015F:004011E2  FFD0                CALL    EAX		; call getdrivetypea (where softice will break)
015F:004011E4  8BF8                MOV     EDI,EAX	; eax will == 3 if the program is run from harddisk
015F:004011E6  56                  PUSH    ESI
015F:004011E7  E820070000          CALL    KERNEL32!FreeLibrary	; free the kernel :) he didnt do it..
015F:004011EC  682C010000          PUSH    0000012C		; size of buffer to store windows directory
015F:004011F1  8D85BCFAFFFF        LEA     EAX,[EBP+FFFFFABC]
015F:004011F7  50                  PUSH    EAX			; pointer to buffer 
015F:004011F8  E8EB060000          CALL    KERNEL32!GetWindowsDirectoryA
015F:004011FD  6880000000          PUSH    00000080		; size of buffer for modulefilename
015F:00401202  8D95E8FBFFFF        LEA     EDX,[EBP+FFFFFBE8]
015F:00401208  52                  PUSH    EDX			; pointer to buffer
015F:00401209  FF35B0254000        PUSH    DWORD PTR [004025B0]	; 00400000, this module...
015F:0040120F  E8DA060000          CALL    KERNEL32!GetModuleFileNameA
015F:00401214  8A8DBCFAFFFF        MOV     CL,[EBP+FFFFFABC]	; [c:\windows]	;WindowsDirectoryA
015F:0040121A  3A8DE8FBFFFF        CMP     CL,[EBP+FFFFFBE8]	; [c:\checkcd1\checkcd.exe]	;ModuleFileNameA
015F:00401220  7518                JNZ     0040123A	; check the drive letters...jump if not equal

yah, all the above code does is get the windows path/directory, get its own path/directory,
compare the drive letters, so it cant be run from the same drive that windows is installed on.
it also get's the drivetype of the current drive, and stores this in EDI... 

015F:00401220  7518                JNZ     0040123A  ; has to be taken, so change it to a JMP
			   eb18				
			   
on with the reversing...

015F:00401222  6A00                PUSH    00
015F:00401224  6A00                PUSH    00
015F:00401226  8D45B0              LEA     EAX,[EBP-50]
015F:00401229  50                  PUSH    EAX		; pointer to wide char 'HeHe! Try again'
015F:0040122A  53                  PUSH    EBX
015F:0040122B  E81C020000          CALL    0040144C	; convert wide char, display messagebox
015F:00401230  83C410              ADD     ESP,10
015F:00401233  33C0                XOR     EAX,EAX
015F:00401235  E909020000          JMP     00401443	; jump to exit (failed cd-check)

015F:0040123A  83EF05              SUB     EDI,05	; where we end up if we take the first good-check jump
015F:0040123D  0F8596010000        JNZ     004013D9	; 05=cd-rom, 05-05=0, so edi must be 0 to carry on.
015F:00401243  8D9574FCFFFF        LEA     EDX,[EBP-038C]	; total number of clusters
015F:00401249  52                  PUSH    EDX		; pointers
015F:0040124A  8D8D78FCFFFF        LEA     ECX,[EBP-0388]	; how many free clusters
015F:00401250  51                  PUSH    ECX		; to
015F:00401251  8D857CFCFFFF        LEA     EAX,[EBP-0384]	;  bytes per sector
015F:00401257  50                  PUSH    EAX		; various
015F:00401258  8D9580FCFFFF        LEA     EDX,[EBP-0380]	; sectors per cluster
015F:0040125E  52                  PUSH    EDX		; buffers
015F:0040125F  6A00                PUSH    00		; pRootPathName, null = current drive
015F:00401261  E8BE060000          CALL    KERNEL32!GetDiskFreeSpaceA
015F:00401266  83BD78FCFFFF00      CMP     DWORD PTR [EBP-0388],00	; compare the amount of free clusters with '0'
015F:0040126D  7418                JZ      00401287	; again, if it was run from CD, the freespace is always '0'

okay, still simple enough, subtracts 5 from the returned value for this drive, if its not equal,
i.e. not zero, jumps to the 'hehe try again' messagebox, if it passed this part, it checks for 
free space, and there should be none on a CD, so ...

015F:0040123D  0F8596010000        JNZ     004013D9 ; this jump has to be killed to carry on with the check
               0f8500000000
			   
015F:0040126D  7418                JZ      00401287 ; this jump has to be taken to carry on...
               eb18
			   
on with the reversing...

015F:0040126F  6A00                PUSH    00
015F:00401271  6A00                PUSH    00
015F:00401273  8D4DB0              LEA     ECX,[EBP-50]	; de-ja-vu
015F:00401276  51                  PUSH    ECX		; pointer to wide char 'HeHe! Try again'
015F:00401277  53                  PUSH    EBX
015F:00401278  E8CF010000          CALL    0040144C	; our message box friend again
015F:0040127D  83C410              ADD     ESP,10
015F:00401280  33C0                XOR     EAX,EAX
015F:00401282  E9BC010000          JMP     00401443	; jump to exit (failed cd-check)

015F:00401287  6880000000          PUSH    00000080
015F:0040128C  8D95BCF9FFFF        LEA     EDX,[EBP+FFFFF9BC]
015F:00401292  52                  PUSH    EDX
015F:00401293  8D8D68FCFFFF        LEA     ECX,[EBP-0398]
015F:00401299  51                  PUSH    ECX
015F:0040129A  8D856CFCFFFF        LEA     EAX,[EBP-0394]
015F:004012A0  50                  PUSH    EAX
015F:004012A1  8D9570FCFFFF        LEA     EDX,[EBP-0390]
015F:004012A7  52                  PUSH    EDX
015F:004012A8  6880000000          PUSH    00000080
015F:004012AD  8D8D3CFAFFFF        LEA     ECX,[EBP+FFFFFA3C]
015F:004012B3  51                  PUSH    ECX
015F:004012B4  6A00                PUSH    00
015F:004012B6  E839060000          CALL    KERNEL32!GetVolumeInformationA
015F:004012BB  81BD70FCFFFF21787573CMP     DWORD PTR [EBP-0390],73757821	; compare read label with 'sux!'
015F:004012C5  0F85F9000000        JNZ     004013C4	; jump if not equal to failed check...
015F:004012CB  F68568FCFFFF10      TEST    BYTE PTR [EBP-0398],10	; i dont know, but it has to be equal :)
015F:004012D2  7418                JZ      004012EC	; jump passed horrid message if above test is true
015F:004012D4  6A00                PUSH    00
015F:004012D6  6A00                PUSH    00
015F:004012D8  8D45B0              LEA     EAX,[EBP-50]	;de-ja-vu again
015F:004012DB  50                  PUSH    EAX			; see the pattern, ebp-50, call 40144c?
015F:004012DC  53                  PUSH    EBX
015F:004012DD  E86A010000          CALL    0040144C
015F:004012E2  83C410              ADD     ESP,10
015F:004012E5  33C0                XOR     EAX,EAX
015F:004012E7  E957010000          JMP     00401443

015F:004012EC  F68569FCFFFF80      TEST    BYTE PTR [EBP-0397],80	; i dont know, but it has to be equal :)
015F:004012F3  7418                JZ      0040130D	; jump passed horrid message if above test is true
015F:004012F5  6A00                PUSH    00
015F:004012F7  6A00                PUSH    00
015F:004012F9  8D55B0              LEA     EDX,[EBP-50]	; we know this is the bad cracker bit
015F:004012FC  52                  PUSH    EDX			; so we take the above jump...
015F:004012FD  53                  PUSH    EBX
015F:004012FE  E849010000          CALL    0040144C
015F:00401303  83C410              ADD     ESP,10
015F:00401306  33C0                XOR     EAX,EAX
015F:00401308  E936010000          JMP     00401443

right, i have been a very naughty boy, and admit that two parts of this code i dont understand,
but from the bad-cracker code being duped everywhere, i know to take the jumps.. basicaly, this
is a label check, chacks the disk label against 'sux!', and if they are the same, does these
other two tests, which have to pass to skip the 'hehe! try again' message..

015F:004012C5  0F85F9000000        JNZ     004013C4	; label check, we want to skip this jump...
               0f8500000000
			   
015F:004012D2  7418                JZ      004012EC	; dont know, but it needs taking (JMP)
               eb18
			   
015F:004012F3  7418                JZ      0040130D	; still dont know, but take it (JMP)
               eb18
			   
on with the reversing...

015F:0040130D  6814244000          PUSH    00402414	; some bullshit 'stack overflow'
015F:00401312  8D953CFAFFFF        LEA     EDX,[EBP+FFFFFA3C]	;[ebp+fffffa3c] is from getvolumeinformationa routine
015F:00401318  52                  PUSH    EDX		; some more bullshit 'OVERFLOW'
015F:00401319  E888050000          CALL    004018A6	; dont care :(
015F:0040131E  83C408              ADD     ESP,08
015F:00401321  85C0                TEST    EAX,EAX	; fuckit, change this to xor eax,eax
015F:00401323  0F8586000000        JNZ     004013AF	; so this jump wont be taken cause at 4013af, is the bad check code
015F:00401329  681A244000          PUSH    0040241A	; pointer to a new label
015F:0040132E  6A00                PUSH    00		; what drive to change
015F:00401330  E8DD050000          CALL    KERNEL32!SetVolumeLabelA
015F:00401335  48                  DEC     EAX		; eax = 1 if function succeed
015F:00401336  7526                JNZ     0040135E	; you cant change a CD's label, so eax should be 0 or -1
													; but after the dec eax, if it failed, this jump would be taken..
													
015F:00401338  8D8D3CFAFFFF        LEA     ECX,[EBP+FFFFFA3C]	; waste 
015F:0040133E  51                  PUSH    ECX					; of
015F:0040133F  6A00                PUSH    00					; time
015F:00401341  E8CC050000          CALL    KERNEL32!SetVolumeLabelA
015F:00401346  6A00                PUSH    00
015F:00401348  6A00                PUSH    00
015F:0040134A  8D45B0              LEA     EAX,[EBP-50]	; bad cracker routine
015F:0040134D  50                  PUSH    EAX
015F:0040134E  53                  PUSH    EBX
015F:0040134F  E8F8000000          CALL    0040144C		; again :)
015F:00401354  83C410              ADD     ESP,10
015F:00401357  33C0                XOR     EAX,EAX
015F:00401359  E9E5000000          JMP     00401443

015F:0040135E  6A00                PUSH    00
015F:00401360  8D55A8              LEA     EDX,[EBP-58]
015F:00401363  52                  PUSH    EDX		;pointer to a filename
015F:00401364  E891050000          CALL    KERNEL32!_lcreat	;try to create a file
015F:00401369  83F8FF              CMP     EAX,-01	; would fail, if it tried to create a file on a CD
015F:0040136C  7428                JZ      00401396	; as they are read-only, so force this jump...

015F:0040136E  50                  PUSH    EAX
015F:0040136F  E892050000          CALL    KERNEL32!_lclose	; whoops, we succeeded, so close the newly created file-handle
015F:00401374  8D4DA8              LEA     ECX,[EBP-58]
015F:00401377  51                  PUSH    ECX
015F:00401378  E835050000          CALL    004018B2
015F:0040137D  59                  POP     ECX
015F:0040137E  6A00                PUSH    00
015F:00401380  6A00                PUSH    00
015F:00401382  8D45B0              LEA     EAX,[EBP-50]	;DEJAVU again :0
015F:00401385  50                  PUSH    EAX
015F:00401386  53                  PUSH    EBX
015F:00401387  E8C0000000          CALL    0040144C		; messagebox
015F:0040138C  83C410              ADD     ESP,10
015F:0040138F  33C0                XOR     EAX,EAX
015F:00401391  E9AD000000          JMP     00401443

015F:00401396  6A00                PUSH    00		; if we couldnt create the file, we end up here
015F:00401398  6823244000          PUSH    00402423	; pointer to 'y.e.p.'
015F:0040139D  8D55D4              LEA     EDX,[EBP-2C]
015F:004013A0  52                  PUSH    EDX		; pointer to 'y.a.y.!. .y.o.u. .c.r.a.c.k.e.d. .i.t.!.'
015F:004013A1  53                  PUSH    EBX
015F:004013A2  E8A5000000          CALL    0040144C	; messagebox...
015F:004013A7  83C410              ADD     ESP,10
015F:004013AA  E992000000          JMP     00401441

hmm, the bit at the start, stack overflow, dont understand what or why, but kill this jump

015F:00401323  0F8586000000        JNZ     004013AF
               0f8500000000
			   
you cant change the label of a CD, so this jump needs forcing

015F:00401336  7526                JNZ     0040135E
               eb26
			  
last but not least, you cant create a file on a CD, so this jump needs forcing aswell..

015F:0040136C  7428                JZ      00401396
               eb28

wayhey, then we finally reach the good boy message box!! yippee!!!

after studying the code, and realising what has been done, it just does some simple checks,
then compares the return codes against what they should be, we dont want it re-labeling our
hard disk drive to 'overflow', or creating a file called 'my.dog', basically, we can skip the
whole routine, and just end up at the goodboy message box..so bpx at the first instruction 

015F:004011B3  68EB234000          PUSH    004023EB	; pointer to 'kernel32.dll',0

and re-assemble it to jump to the good-boy message box..

a 4011b3 <ret>
jmp 401396 <ret>
<esc>
x <ret>

015F:004011B3  E9DE010000          JMP     00401396	; skip whole of check, go straight to jail
													; do not pass go, do not collect 200..
:)

then you have a almost cracked checkcd.exe... just gotta patch it, but i cant be bothered, so
i used my process patcher to create a loader for it..(availble from http://csir.xxx.xxx :)

no plugz.. :)

happy reversing / cracking / whatever..

R!SC 6/6/99



