Securom crack tutorial by Pedro

First, a simple explanation about Securom.

Securom is a cd-rom protection that can't be copied when you duplicate a cd.
It's used by a lot of games, for the purpose of this tutorial I tried Conflict
Freespace (english version), Grim Fandango (italian version) and Might and
Magic VI (italian version).
This is the first tutorial I write, so forgive me if I'm not clear or if my
english is bad. I decided to write this tutorial because the generic
Securom crack by Laxity doesn't work on the games I tried. I also found that
part of Securom code is encrypted, and is decrypted by a key read from the cd.
My aim is to let the protection decrypt itself, then put decrypted code
into the executable and remove Securom cdrom check.

Software you need:
- Softice
- Adump v1.0 by UCF: this is a Softice dumper, I found it at
  http://www.suddendischarge.com/Decompressors.html
- Supcomp and Supwrite: I wrote these tools and they are included as C
  source code
- Procdump32 v1.1 by UCF: this is a universal PE unpacker and is nedeed to
  unpack the main executable of Grim Fandango. You need it only if the
  game you are trying to crack is compressed by Petite.
  I found it at http://www.crackstore.com/tools.htm
- A Hex Editor

Supcomp and Supwrite can be compiled with any DOS C compiler. I personally
use the great DJGPP 32 bit compiler that is free (http://www.delorie.com).
There is no documentation for Supcomp and Supwrite: just run them with
no parameters and you'll find what they do.

First, let's look at the main executable. Conflict Freespace and Might and
Magic VI are not packed, while Grim Fandango is packed with Petite.
So the first thing we have to do is to unpack Grim Fandango's executable.
Luckily it's quite easy if we use Procdump32, that has support for unpacking
Petite compressed programs.

Ok, let's start with the real cracking ;-)

When we start these games, we see that they load something from disk and
they simply exit (because we put a copy, not the original into the reader :-)
Well, we can try to breakpoint the usual call SendDriverMessage, but nothing
happens. Hmm, it seems Securom doesn't use the Windows API to access the cdrom.
I spare you the effort of finding how the program accesses the cdrom: it
uses INT 31 with AH=03 (DPMI 0.9+ - SIMULATE REAL MODE INTERRUPT) to call
MSCDEX interrupt.
Ok, let's step a bit after the breakpoint, we get into CMS32_95.DLL that is
part of the protection, then we get to the main executable.
Now if we search for some of the code bytes we see, we can't find them in the
main executable file! Parts of the code are crypted, and they are decrypted
when the program is run.
How can the program modify itself during execution? By calling
WriteProcessMemory. So we put a breakpoint on this call. We see that all
these games call it at least three times, even if we didn't put the cdrom
into the reader. So this decryption doesn't depend on the data on the
original cdrom. This is just the code that makes the last decryption.
In fact if we put the original cdrom into the reader, the API is called once
more, and the decrypted code is correct, while if we put a copy into the
reader, either WriteProcessMemory is not called the fourth time (bad copy,
so the protection realizes it's false) or it is called but the decrypted code
is garbage and the program realizes it's wrong and exits. So the fourth
decryption DOES depend on the data read from the original cdrom.
If we look at the API reference we see that when the breakpoint is
activated on WriteProcessMemory we have:
ESP+08: destination address
ESP+0c: source address
ESP+10: length of area to copy
So, we might dump the code bytes after the decryption and substitute them
into the main executable file.
First we make a copy of the main executable called mm6_2.exe (for this purpose
I use Might and Magic VI, but the others work the same way). It's
important to use short file names, otherwise supcomp and supwrite
won't work. The rule is: we execute the original mm6.exe to get decrypted code
and we patch mm6_2.exe (don't run mm6_2.exe before it's completely
patched or it will hang).
Let's run Adump. With command "R" I see that the starting memory area
for dumping is 0x83651000.
Now let's run mm6.exe with breakpoint on WriteProcessMemory.
Ok, I see that 0x5000 bytes are to be written, the source address is at
0xe80078 while the destination address is at 0x4ae000. So I copy the two
areas (source and destination) into two different areas of dump memory:
m 4ae000 l 5000 83651000 (original code)
m e80078 l 5000 83661000 (decrypted code)
I let the process end, I go to the dumper and I write the two areas of memory
to two files.
w c:\orig1.dat 5000 83651000
w c:\modif1.dat 5000 83661000
Now I open orig1.dat with a hex editor and I take the first 16 bytes. I search
for those bytes into mm6_2.exe. I find them at offset 0xad400. Let's see if all
0x5000 bytes are identical.
I open a DOS window and I run:
supcomp c:\orig1.dat mm6_2.exe 0 0xad400 0x5000
Ok, no differences, so we can patch them.
supwrite c:\modif1.dat mm6_2.exe 0 0xad400 0x5000
But now if we run mm6_2.exe it hangs because it tries to decrypt already
decrypted data and gets garbage. So let's run mm6.exe again, and when we reach
the breakpoint we write "u @esp" and we go up some lines:

017F:008CC2FE  8D8D64FEFFFF        LEA     ECX,[EBP-019C]
017F:008CC304  51                  PUSH    ECX
017F:008CC305  8B95C4FEFFFF        MOV     EDX,[EBP-013C]
017F:008CC30B  52                  PUSH    EDX              ;length
017F:008CC30C  8B85E4FEFFFF        MOV     EAX,[EBP-011C]
017F:008CC312  50                  PUSH    EAX              ;source
017F:008CC313  8B8DBCFEFFFF        MOV     ECX,[EBP-0144] 
017F:008CC319  2B8DB4FEFFFF        SUB     ECX,[EBP-014C]
017F:008CC31F  51                  PUSH    ECX              ;destination
017F:008CC320  8B15B87D9F00        MOV     EDX,[009F7DB8]
017F:008CC326  52                  PUSH    EDX              ;handle
017F:008CC327  FF15B8839F00        CALL    [KERNEL32!WriteProcessMemory]

We must set length to 0 so we change:

mov edx,[ebp-13c]
push edx

to:

xor edx,edx
nop
nop
nop
nop
push edx

That is, we search for bytes (in mm6_2.exe):
8B 95 C4 FE FF FF 52 8B 85 E4 FE FF FF 50 8B 8D BC FE FF FF 2B 8D B4 FE FF
FF 51 8B 15 B8 7D 9F 00 52 FF 15 B8 83 9F 00
and we change the first 6 bytes to:
33 D2 90 90 90 90
(it's best to search for many bytes, because there are similar parts of code,
and we have to make sure we have found the exact place).

You have to work the same way for the two other breakpoints (change crypted
code with decrypted code and set to zero the length for WriteProcessMemory).
Someone might wonder why I didn't write a program to do all this automatically.
Well, the problem is, the code is similar but not the same for the games
I tried (for example Grim Fandango uses ECX as the register to push
the length parameter).

Now we really need the original cdrom (you bought it, haven't you? :-) to get
correctly decrypted code.
We must still repeat the above procedure to decrypt and set length to zero
when it reaches the fourth WriteProcessMemory (this time edx is kindly XORed
for us, so we just need to "NOP" the following instruction that loads edx).
We must also crack the part of code where it checks for the original cdrom
and exits without executing our patched code (this is in the part of code
we decrypted before, so if we hadn't decrypted it, we couldn't find it
easily in the executable file). In fact if we try to execute the program
after fourth decryption but before the last crack, it won't work, even
with the original cdrom in the recorder!

The last part of the crack is a bit trickier because you can't step into
the program's code (F8 or F10 won't work). Moreover, if the program
detects that you are trying to step into it, next time won't even load
until you restart Windows, so you shouldn't put breakpoints except the
ones I'll tell you.
I'll spare you the time I spent to understand what the program does.
First you can put a breakpoint on GetDriveTypeA that is used to find
the cdrom. With F11 you get back to the program's code. If you scroll
the code window some pages down, you'll find a series of POPs and a RET
followed by a few INT 03. Put a breakpoint on the RET.
Run the original mm6.exe with the original cd. Hmm, it doesn't reach the RET.
Remove the cd from the reader and run it again. Ahh, now it reaches the RET
with EAX=2. Put the original cdrom again into the reader but run
mm6_2.exe (you must have decrypted and patched it ALL four times). It
reaches the RET with EAX=7. If you put a copy into the reader you also
get EAX=7.
So it's easy to understand that EAX contains an error code when something
goes wrong, and the RET is never reached when all goes right.
Now you must run the modified mm6_2.exe after putting the original cd into
the recorder and setting a breakpoint on GetDriveTypeA and on
the RET. Press F11 to get to the code when it reaches GetDriveTypeA.
Remember, you should get error code 7 so scroll down till you find:

test edx,edx	;error?
jnz ........	;if it jumps => no error
call [.....]	;start of error routine
push 07
call .......
mov eax,7	;error code
jmp ........	;jumps to the POPs and RET

So the first jnz must be changed to jmp. We search for the following bytes:
75 17 FF 15 B0 83 9F 00 6A 07
into mm6_2.exe and we change 75 to EB.

Run it. Another error, with return code 8. In the code we find:

test edx,edx	;error?
jnz ........	;if it jumps => no error
call [.....]	;start of error routine
push 08
call .......
mov eax,8	;error code
jmp ........	;jumps to the POPs and RET

Search for:
75 17 FF 15 B0 83 9F 00 6A 08
and change 75 to EB.

This time if you run it, you get error code 0. You find this code near
the RET:

jnz ........	;jumps if error
push 2c		;all checks passed!
call .......
jmp ........	;run, baby, run :-)

So you must simply change jnz -> nop nop.
The sequence to search for is
75 09 6A 2C
and you change 75 09 with 90 90

At last the modified executable runs again with the original. But what
about a copy, I hear you ask? Hooray, it works too because you removed
error codes 7, 8 and 0 that also a copy produces! Of course the copy
must have the right volume name, otherwise you'll get "Wrong disc"
message box.

Well, I don't know if this is the simplest way to crack Securom: I wrote
all this especially for didactic purposes. It should work on any Securom
protected game. So bye, bye Securom, we won't miss you :-)

For comments write to:
Pedro <pedro_i@iname.com>