on disk copy protection. Good, you'all need a refresher
course on so here it is (YO JB study hard, you might learn
something).
CHAMBER of the SCI-MUTANT PREISTEST (CSMP) is a really
fucked up game but was simple to unprotect. So, lets dive
right in. We will be using DEBUG here (although I used
periscope but then shit I'm special) to do the crack. Lets
dive in. When we first load CSMP (the file ERE.COM) and
unassemble it here is what we get.
u 100 10B
119A:0100 8CCA MOV DX,CS
119A:0102 81C2C101 ADD DX,01C1
119A:0106 52 PUSH DX
119A:0107 BA0F00 MOV DX,000F
119A:010A 52 PUSH DX
119A:010B CB RETF
I included the register listing for a reason. NOTICE
that this piece of code just seem to stop (the RETF)
statement. Well, what is really does is place the address
(segment and offset) of the real starting point on to the
stack and the execute a far return to that location. Now
this might fool a real beginner (or at least make him worry a
bit but us...no way).
If you take the current CS value and add 1C1 to it (in
segment addition) you will get the segment address 135B (that
is if you are using my example of 119A. If not then you will
not get 135B but trust me, it's the right value).
So since we want to be at the real program, execute the
code until 10B (ie use the command "G 10B") then trace
through the next instruction.
If you now unassemble the code, here is what it should
look like.
-u 000f 36
135B:000F 9C PUSHF
135B:0010 50 PUSH AX
135B:0011 1E PUSH DS
135B:0012 06 PUSH ES
135B:0013 0E PUSH CS
135B:0014 1F POP DS
135B:0015 0E PUSH CS
135B:0016 07 POP ES
135B:0017 FC CLD
135B:0018 89260B00 MOV [000B],SP
135B:001C C70600000102 MOV WORD PTR [0000],0201
135B:0022 B013 MOV AL,13
135B:0024 A23500 MOV [0035],AL
135B:0027 A2FF01 MOV [01FF],AL
135B:002A A22F02 MOV [022F],AL
135B:002D A23901 MOV [0139],AL
135B:0030 B280 MOV DL,80
135B:0032 B408 MOV AH,08
135B:0034 CD21 INT 21
135B:0036 7232 JB 006A
Since we are looking for a disk based copy protection,
it might be a good time to look for INT 13. So search the
current segment for INT 13 with the command
S 135B:0 FFFF CD 13
But shit, nothing. You mean this program doesn't use
int 13. Be real. Reread the first lesson. You know the one
that talks about self modifing code. This is what we have
here. Let's take a closer look at the last bit of code but
this time, with my comments added.
-u 000f 36
; The first part of the code simple sets up for the return to
; dos as well as sets ES and DS
135B:000F 9C PUSHF
135B:0010 50 PUSH AX
135B:0011 1E PUSH DS
135B:0012 06 PUSH ES
135B:0013 0E PUSH CS
135B:0014 1F POP DS ; Set DS to CS
135B:0015 0E PUSH CS
135B:0016 07 POP ES ; Set ES to DS
135B:0017 FC CLD
135B:0018 89260B00 MOV [000B],SP
; The next instruction sets up a variable that is used in the
; routine that reads in the sectors from the disk. More on
; later.
135B:001C C70600000102 MOV WORD PTR [0000],0201
; Now, here is the self modifing code. Notice at AL is 13
; (INT 13h ... Get it). Look at the first memory location
; (35h) and remember that DS = CS. With this in mind, when
; then instuction at 135B:0024 is executed byte at 135B:0035
; will be changed to 13h. That will in fact change the
; INT 21h at 135B:0034 to an INT 13h. And so on, and so on.
135B:0022 B013 MOV AL,13 ; New value
135B:0024 A23500 MOV [0035],AL ; Change to INT 13h
135B:0027 A2FF01 MOV [01FF],AL ; Change to INT 13h
135B:002A A22F02 MOV [022F],AL ; Change to INT 13h
135B:002D A23901 MOV [0139],AL ; Change to INT 13h
; If you lookup DOS function 08 you will find it's CONSOLE
; INPUT. Now does that seem out of place to you.
135B:0030 B280 MOV DL,80
135B:0032 B408 MOV AH,08
135B:0034 CD21 INT 21 ; Changed to INT 13h
135B:0036 7232 JB 006A
Whoa, that was tricky. If you execute up to 135B:30
here is what it should look like..
135B:0030 B280 MOV DL,80
135B:0032 B408 MOV AH,08
135B:0034 CD13 INT 13
135B:0036 7232 JB 006A
AHA, now we are getting somewhere. If we lookup what
disk function 08 means, you won't be suprised. Function 08h
is GET DRIVE TYPE. It will tell what type of disk drive we
have. Remember, if you are loading off of a hard disk then
it wants to use a different routine. Since we want it to
think we are loading off of disk, then we want to take this
jump. So for now, force the jmp by setting IP to 6A.
At 135B:006A you find another jmp instruction
135B:006A EB6B JMP 00D7
This jumps to the routine that does the actual disk
check. Here is the outer loop of that code (With my comments
of course).
; This first part of this routine simply test to see how many
; disk drives you have.
135B:00D7 CD11 INT 11
135B:00D9 25C000 AND AX,00C0
135B:00DC B106 MOV CL,06
135B:00DE D3E8 SHR AX,CL
135B:00E0 FEC0 INC AL
135B:00E2 FEC0 INC AL
135B:00E4 A20200 MOV [0002],AL
; Next, so setup for the actual disk check
135B:00E7 C606090000 MOV BYTE PTR [0009],00
135B:00EC B9F127 MOV CX,27F1
135B:00EF 8BE9 MOV BP,CX
135B:00F1 B107 MOV CL,07
135B:00F3 F8 CLC
; This calls the protection routine part 1
135B:00F4 E82F00 CALL 0126
135B:00F7 B9DE27 MOV CX,27DE
135B:00FA 8BE9 MOV BP,CX
135B:00FC B108 MOV CL,08
135B:00FE F9 STC
; This calls the protection routine part 2
135B:00FF E82400 CALL 0126
135B:0102 8D1E5802 LEA BX,[0258]
135B:0106 8D361C01 LEA SI,[011C]
135B:010A 8BCD MOV CX,BP
135B:010C AC LODSB
135B:010D 8AC8 MOV CL,AL
; This calls the protection routine part 3
135B:010F E8E300 CALL 01F5
; Makes the final check
135B:0112 7271 JB 0185
135B:0114 AC LODSB
135B:0115 0AC0 OR AL,AL
135B:0117 75F4 JNZ 010D ; If not correct, try again
135B:0119 EB77 JMP 0192 ; Correct, continue program
135B:011B 90 NOP
There are calls to 2 different subroutines. The routine
at 126 and the routine at 1F5. If you examine the routine at
126 you find that it makes several calls to the routine at
1F5. Then you you examine the routine at 1F5 you see the
actual call to INT 13. Here is the code for both routine
with comments
; First, it sets up the sector, head and drive information.
; DS:000A holds the sector to read
135B:0126 880E0A00 MOV [000A],CL
135B:012A 8A160900 MOV DL,[0009]
135B:012E B600 MOV DH,00
; Sets the DTA
135B:0130 8D365802 LEA SI,[0258]
135B:0134 7213 JB 0149
; Resets the disk
135B:0136 33C0 XOR AX,AX
135B:0138 CD13 INT 13
; Calls the the check
135B:013A B90114 MOV CX,1401 ; TRACK 14 sector 1
135B:013D 8BDE MOV BX,SI
135B:013F E8B300 CALL 01F5
; The next track/sector to read in is stored in BP
135B:0142 8BCD MOV CX,BP
135B:0144 E8AE00 CALL 01F5
135B:0147 7234 JB 017D ; If an error occured,
; trap it.
135B:0149 88160900 MOV [0009],DL ; Reset drive
135B:014D 8A0E0A00 MOV CL,[000A] ; reset sector
135B:0151 E8A100 CALL 01F5 ; check protection
135B:0154 722F JB 0185 ; Check for an error
135B:0156 8D5C20 LEA BX,[SI+20]
135B:0159 8BCD MOV CX,BP ; Get next T/S
135B:015B B010 MOV AL,10 ; Ignore this
135B:015D E89500 CALL 01F5 ; Check protection
135B:0160 7223 JB 0185 ; check for error
; The next sector of code checks to see if what was read in
; is the actual protected tracks
; First check
135B:0162 8DBCAC00 LEA DI,[SI+00AC]
135B:0166 B91000 MOV CX,0010
135B:0169 F3 REPZ
135B:016A A7 CMPSW
; NOTE: If it was a bad track, it will jmp to 185. A good
; read should just continue
135B:016B 7518 JNZ 0185
; Second check
135B:016D 8D365802 LEA SI,[0258]
135B:0171 8D3E3702 LEA DI,[0237]
135B:0175 B90400 MOV CX,0004
135B:0178 F3 REPZ
135B:0179 A7 CMPSW
; see NOTE above
135B:017A 7509 JNZ 0185
; This exit back to the main routine.
135B:017C C3 RET
; Here is the start of the error trap routines. Basicly what
; they do is check an error count. If it's not 0 then it
; retries everything. If it is 0 then it exit back to dos.
135B:017D FEC2 INC DL
135B:017F 3A160200 CMP DL,[0002]
135B:0183 72B1 JB 0136
135B:0185 E85400 CALL 01DC
135B:0188 8B260B00 MOV SP,[000B]
135B:018C 2BC9 SUB CX,CX
135B:018E 58 POP AX
135B:018F 50 PUSH AX
135B:0190 EB1F JMP 01B1
** Here is the actual code the does the check **
; ES:BX points to the buffer
135B:01F5 1E PUSH DS
135B:01F6 07 POP ES
; SI is set to the # of retries
135B:01F7 56 PUSH SI
135B:01F8 BE0600 MOV SI,0006
; Remember how I said we would use what was in DS:0000 later.
; well, here is where you use it. It loads in the FUNCTION
; and # of sectors from what is stored in DS:0000. This is
; just a trick to make the int 13 call more vague.
135B:01FB A10000 MOV AX,[0000]
135B:01FE CD13 INT 13
; If there is no errors, then exit this part of the loop
135B:0200 7309 JNB 020B
135B:0202 F6C480 TEST AH,80
; Check to see if it was a drive TIMEOUT. If so, then set
; an error flag and exit
135B:0205 7503 JNZ 020A
; It must have been a load error. Retry 6 times
135B:0207 4E DEC SI
135B:0208 75F1 JNZ 01FB
; Set the error flag
135B:020A F9 STC
; restore SI and return
135B:020B 5E POP SI
135B:020C C3 RET
If you follow through all of that. You will see that
the only real way out is the jmp to "135B:0192" at 135B:0119.
So, how do we test it. Simple. Exit back to dos and let's
add a temporary patch.
Reload ERE.COM under debug. Execute the program setting
a breakpoint at 135B:0022 (if you remember, that is right at
the begining of the self modifing code). When execution
stops, change you IP register to 192. Now execute the code.
Well shit, we are at the main menu. We just bypassed
the entire protection routine. So, now where to add the
patch. We will be adding the patch at 135B:0022. But what
should the patch be. In this case, simply jumping to
135B:0192 will do. So, reload ERE.COM under debug. Execute
the code until 135B:0022. Now unassemble it. Here is the
code fragment we need.
135B:0022 B013 MOV AL,13
135B:0024 A23500 MOV [0035],AL
135B:0027 A2FF01 MOV [01FF],AL
135B:002A A22F02 MOV [022F],AL
135B:002D A23901 MOV [0139],AL
Here is the code we want to use as the patch
135B:0022 E96D01 JMP 192
So, to add the patch, we search the file ERE.COM using
PC-TOOLS. For our search string we use
B0 13 A2 35 00 A2 FF 01 A2 2F 02 A2 39 01
PC-TOOLS should find the search string at reletive
sector #13. Edit the sector and change "B0 13 A2" to
"E9 6D 01" (our patch) and save the sector.
BOOM! your done and CSMP is cracked. Fun huh. You just
kicked 5 seconds off of the load time. Preaty fucken good.
Well, I hope this textfile helped.
-Buckaroo Banzai
-Cracking Guru
0 comments:
Post a Comment