TUTORIAL about Laserlock SPEEnc (Tennis Masters Series 2003):



Commercial protection : Laserlock SPEEnc v 2 (http://www.laserlock.com/)
Editor : Microïds
Release date : FR November 01, 2002
http://www.jeuxvideo.com/articles/0000/00002557_test.htm
Cracking level : [ ] easy    [x] intermediate    [x] confirmed    [ ] expert
It is preferable to have practised or cracked game protections such as Safedisc/SecuROM before reading this tutorial (it also requires knowledge about the PE file format, manual unpacking and imports rebuilding) and perhaps have read my previous tutorial on Laserlock :p

Tools nedeed :
Softice 4.01
Icedump
Procdump/LordPE
Hiew/Hex Workshop
W32Dasm v8.93
Adump
Masm v8

You must own the original disc of this game or a functional clone (there is a Laserlock profile in Alcohol 120%), to be able to apply this tutorial…
Moreover, it is the French version of Tennis Masters Series 2003…
The protected executable file is "Tennis Masters Series 2003.exe", which will now be called "tms2003.exe"…

OS : Win98 SE.
This tutorial can easily be applied to others debuggers (OllyDbg, for example) and other OS.


This tutorial is detailed in the following way:

A) Introduction and general information
B) A "cracking" approach
1. Locating OEP
2. Fixing the call Laserlock
3. Rebuilding the imports
4. Cracking the CD-check
C) A "reversing" approach
1. Fixing the "variable" addresses
2. The polymorphic code
3. The code in general
4. Easily locating the OEP
5. Anti-debugging tricks
6. Integrity checks
7. Stuyding SPEEnc layers
8. Cracking Laserlock SPEEnc without original game CD
D) Generalization and conclusion
E) Greetings

A) Introduction and general information :

Laserlock is a commercial protection, created by MLS LaserLock Inc.
It is characterized by a Laserlok folder (hidden - > they take us for idiots) on CD's root.
[CD is characterized by a ring quite visible on center…]
If they believe that in putting an hidden attribute on important files, we could not see their little game … - > "a pure lamerz technique" :p
This Laserlok folder contains 5 files : laserlok.in, laserlok.o10, laserlok.o11, laserlok.o12 and laserlok.o13, all hidden (~90 Mo!!!) …

Protection is based on these "copy protected" files (they can't be copied the usual way).
So, protection has just to check the presence of these files, to determine whether it is disc copy or not.

On the executable file, protection can easily be detected by editing it with a hexadecimal editor:



Laserlock's guys are cool ; they give us the version of SPEEnc (here, it is version 2).

On their site (copy from September 2003), Laserlock informed us about its protection (Mommy, I 'm really afraid :p) :


LaserLock consists of the following successful combination:

Actually, it is this powerful combination that makes LaserLock protection system so secure, single and applicable, especially when compared to the other protection systems available today!

LaserLock MARATHON is:

- Uncrackable, with No Generic Cracks
- Most resistant against the latest, advanced copying total software and the devices of the market
- The most compatible Copy protection system worldwide (CD-Rom and DVD-Rom drives)
- Transparent Totally to replicators and end-users, No passwords, No extra devices.
- Of low cost and high efficiency.
I don't know what to say :o

Different types of protections :

Executable file of this game is packed :
Packed by SPEEnc V2 Asterios Parlamentas
\=-SPeEnc loader rutin d02-07-01r by Asterios Parlamentas \ = -

Redirection of APIs of tms2003.exe (call/jmp API replaced by call Laserlock).
Redirection of GetProcAddress API on the IAT.
Previous protections are ensured first by execution of a routine, the SPEEnc (contained in the game executable file)…
This one allows variability of addresses, introduction of polymorphic code on its code, but also various techniques of anti-debugging (anti-bpx, etc…), decoding layers, integrity checks, etc…

The different steps of this protection :

1. Setup of "variable" addresses
2. Setup of SPEEnc (SPEEnc has various anti-cracking techniques such as polymorphic code, anti-debugging code, etc…)
3. Executable code blocks of SPEEnc are progressively decoded
4. Then, there is the protection itself (CD's physical structure, made by the protection, is read).



If CD authentification failed, the following box appears :



5. SPEEnc makes some integrity checks (in particular on itself)…
6. SPEEnc then deciphers tms2003.exe and jumps to its OEP
7. APIs are redirected to a routine of SPEEnc, which calculates and returns the good address of redirected APIs

B) "Cracking" Approach :

1. Locating OEP to unpack the executable file :

After two small jump on OEP, we arrive at 0040117B and with a look at the code, which follows, we can already suspect the executable file to be packed… (see the pushad in 0040119F).



To arrive at the "real" OEP, lets first test the traditionals bpx APIs (for example, bpx GetVersion)…
Baooom, the PC explodes… lol… No, just a crash…:p
It is thus useless to put any bpx, because of anti-bpx…
How can we arrive at OEP of our unpacked executable file ?
By putting a bpr 402000 650000 R (memory breakpoint).
Why 402000? Because this way, we avoid the protection's instructions (from 4010D1 to 40192A) before the ret in 0040157C (which enables us to arrive on "variable addresses" code).
Prefer a large range, because a lot of games do not have their OEP in the neighbourhoods of 401000 (contrary to majority of sharewares executables)…
The 1st break brings us on a LODSB instruction at 00BA73FE :



We disable this bpr by a bd 0 and we put a bpx 00BA7417 to leave this loop…
Shucks! We must not use BPX !!! In this case, we crash at 00BA21FA…
So, prefer a bpm 00BA7417 X (hardware breakpoint).
We reactivate then the bpr by a be 0 and we break this time on REPZ MOVSB instruction in 00BA5078 :



We disable the bpr (bd 0) again and execute the REPZ MOVSB instruction at 00BA5078 by F10 (Step Over)…
Then reactivate the bpr (be 0) a last time and finally after 1 minute, we get OEP of the unpacked tms2003.exe ;)

Note: An lame method "to find" the OEP of an unpacked executable file consists in dumping on runtime (so it is decrypted/decompressed), disassembling this dump and looking in the code for these instructions :
push ebp
mov ebp, esp
It can constitute a check, but nothing more (because of several occurrences)…

2. Fixing the call Laserlock

If we attentively look at the code on OEP, we have this:



We see that all the call API (but also JMP API) are replaced by call dword ptr [00BA7760].
It is the redirection of APIs.
(We will call them : "call Laserlock").

Warning : Keep in mind that all addresses like 00BAxxxx, are variable from one execution to another one ("variable addresses"). It is the case of these "call Laserlock". Here, I fixed them to make explanations easier (see the 2nd part of this tutorial, for more details…).

Let us see what there is, inside…



This routine calculates the API address to return, with address of the "call Laserlock", put on stack at time of its call…
Always with the example of the call dword ptr [00BA7760] at 0064697D, let us trace this routine in step over (F10) until 00BA6FAD. After executing the ret, we arrive to API GetVersion (Kernel) located at address BFF92F1B… (addresses, which vary, depending on the OS version).



A little F12 brings us back just after our call Laserlock in 00646983.
To find address of this API in the IAT, we have just to look in the eax register, when we are at 00BA6F8E, on the MOV EAX, [EAX] instruction.
Occurrence is found at 00903938 (idata section).

We must thus replace call Laserlock by call API…
Here, we have just to replace FF156077BA00 by FF1538399000.
e 0064697F 38,39,90,00.
One call fixed ;).

We have just to automate what we have previously done manually, by a small routine (a "call-fixer").
This constitutes an anti-dump protection. So, if these calls are not fixed and that we dump, then executable file "will attempt to go" in memory zones, which do not exist anymore (they were initialized by protection) and it will irreversibly crash…

You will perhaps remember the "Call-fixer" of the previous version of Laserlock (Laserlock version 5, for example, Desperados: Wanted Dead or Alive)?
Well, we can keep the same one to fix all our Call Laserlock of this version (there are only very few things to modify).
If you want more explanations about this routine, I send you back to my previous tutorial :p

Rem: - Compared to the previous version (version 5), there are no more checksums, applied on this routine, which calculates redirection address of the "call Laserlock", nor on the executable file itself , at time of its call. Thus, we can modify the code if it is necessary (and it is what I did, by patching address 00BA6F8E with a jmp edi !!! ).
- The exploit, present in the version 5, which consisted in making the program patch itself and replacing the call Laserlock by call/jmp APIs, from the 50th API and which made possible to avoid CD authentification, has been corrected…


Call-fixer (Laserlock.asm):


title call_fixer
.386
.model small, stdcall
option casemap :none
     
.code
    _TextOffset             equ 00401000h
    _TextSize                equ 00411000h
    _RoutinePatch         equ 00BA6F8Eh

start:
    pushad
    mov esi,_RoutinePatch
    mov word ptr [esi],0E7FFh
    call    @1
@1:
    pop edi
    add edi, offset here1-offset @1
    mov edx, _TextOffset
    mov ecx, _TextSize
   
search_loop:
    cmp word ptr [edx], 15FFh
    jne try_again
    cmp dword ptr [edx+2], 00BA7760h
    jne try_again
    lea eax, [edx+6]
    pushad
    push eax
    ;jmp dword ptr [BA7760h]
    db 0FFh,25h,60h,77h,0BAh,0
here1:
    mov edx, dword ptr [ebp+1Ch]
    mov dword ptr [edx-4], eax
    mov eax, edi
    cmp ebx, 00
    jne @2
    mov byte ptr [edx-5], 25h
    inc eax
@2: add eax, offset here2-offset here1
    mov esi, _RoutinePatch+02
    jmp esi
here2:
    pop eax
    popad
try_again:
    inc edx
    dec ecx
    jne search_loop
    popad
    int 03
end start

Type r in adump to obtain an address where we can load our routine…
We assemble and load this routine in memory by the l command of adump.

Note : Adump was a binary, which allocated some memory in order to load some routines (or anything else), on Softice.
With ollydbg, you can copy this routine just after PE. It is also possible to allocate some memory to do this on OllyDbg (Alt+M to see the Memory map, then a right click > Allocate Memory).

We break thus on OEP of tms2003.exe and we modifie eip to execute our routine (loaded in Adump).

Note: You have just to type i3here one to break on the int 03 of the routine, which indicates the end of its work…
Once the routine has finished its job, we go back to OEP, by a r eip OEP.

All calls are correctly fixed :)

Now, let us examine the IAT (it starts at 00903704 and finishes at 00903CEC).
You will certainly have noticed in this IAT, an "abnormal address", concerning Kernel imports…




Indeed, address at 009038D8 does not point to a BFxxxxxx address, as this should be the case, but to 00BA6EC7…
It is a redirection of the GetProcAddress API. This redirection is done by a modification of the IAT, contrary to the call Laserlock, where the redirection is done by a call to a specific routine, in charge of calculation of address to return and thus requires to transform in the code, all the call/jmp API into call Laserlock…

Here's this routine :



It is the instruction call ds:[ebp+048B5992] at 00BA6F20, which corresponds to a call GetProcAddress.
You just have to replace in IAT (in 009038D8), the value 00BA6F20, by the address of the GetProcAddress API (for me, that will be BFF76DA8).
Here we are : we can dump the executable file :)
Now, we must create a new Imports Table or repair the one we have (and that Laserlock destroyed partially)…

3. Rebuilding the imports
The easiest way: creating a new Import Table :
Run an infinite loop on OEP of tms2003.exe, then run ImpRec, enter good values of the IAT and ImpRec "will attach" to the end of executable file (the previous obtained dump), the new Import Table (it does it by adding a section).



A functional dump is thus obtained, which also run on XP…
Note: You must give the OEP of the unpacked executable. Thus ImpRec also corrects the OEP on PE, which avoids us doing it manually with LordPE.

The hardest way: repairing the original Import Table :
I have dumped so that VO correspond to RO, for more convenience…
Import Table is easily found (generally, it is above the IAT):



To locate it, you have to look for a pointer to the name of a dll (imports), for example KERNEL32.dll, USER32.dll, etc…
You must work of course with VO (remove image base of memory addresses) and take care of possible alignments of the sections (not here) …
Here, the IT starts at 503000 and finishes at 5030F0, which includes 10 null words, indicating as it should be, the end of Import Table (size = 0F0).
Now, put these values for the IT in PE, by editing it with LordPE (EP Editor - > Directories - > Import Table).
For IAT, put RVA and Size to 00000000, and you will not have any problem…
At each launch of program, IAT is always overwritten (by physical addresses of your OS imports…).

Now, we launch our modified executable and we have the following error (A .DLL file, .DLL, is missing) :



lol… I like this error ;-)
We have to check values in Import Table, but we will do so after a remainder (I know, I already do this with my previous tutorial, but it is so concise and clear :p)


Image Import Descriptor Format or Import Table  (read "peering inside the PE" of Matt Pietrek!) :

An entry (a DLL and all its functions) in the Image Import Descriptor consists of 5 Dword.

Dword 1 - Characteristics (hint name array)
This dword is a pointer to the first element of a pointers table.
Each pointer of this table points to the hint name, followed with a function name.

Dword 2 - TimeDateStamp

Dword 3 - ForwarderChain

Dword 4 - DLL’s name
This dword is a pointer to the name of the DLL (null terminated ASCII string)

Dword 5 - Import Address Counts
This dword is a pointer towards the first element of an addresses table.
This addresses table functions in parallel with the one of pointers to the hint names (names of functions).

Extracted from Import Function tutorial.doc / Import-Function in section RDATA.doc by El.CaRaCoL. (In French)
Thank you El.CaRaCoL. ;-)


Import Table seems normal, apart from all the Dwords 4 (underlined in red)…
Indeed, it points to a null string instead of pointing to the name of a .dll (imported).
However, they point to the good place (in the middle of functions names).
Thus, Laserlock has partially destroyed IT , by erasing the names of .dll…
How can we find the missing names of these .dll?

For an entry, search Dword 5 (underlined in green) corresponding to Dword 4 of the same librairy (underlined in red). We find a pointer to the physical addresses of this dll functions and the 1st address (1st function) of this addresses table enables us to find the name of the library (for example, under Softice, by typing u, followed by this address). Of course, we can do the same with Dword 1 (underlined in blue) and find the name of a library, using one of its functions name…
Now, we have just to patch at the good places, with the library names …





And here's a summary table :



Once all these modifications are made, start again and a double error message will appear… (it's still better :p)





The 1st thing that I did was to check if the addresses table (Dword 5 - Import Address Table) corresponds to the one (Dword 1) with pointers to the hint names (names of the functions), concerning the KERNEL32.dll library.
Addresses table (Dword 5) for this library starts at 005037E4.
The table (Dword 1) of pointers to the functions names, concerning the same library, starts at 005031D0.

In 005037E4, we find the BFF92B8F address, which corresponds to SetEvent API. Its function string is pointed in 005031D0.
In 005037E4+F0, we find the BFFA1C7C address, which corresponds to CompareStringA API. Its function string is pointed in 005031D0+F0.
In 005037E4+F4=005038D8, we find the BFF76DA8 address, which corresponds to GetProcAddress API , whereas in 005031D0+F4, it is the CreateSemafore function (its string), which is pointed to !!!

Hum… this must be the problem, here. Moreover, what is this function and why is it there ?

While looking in Win32 Programmer' s Reference, we realize that there is an API of this style, but written as CreateSemaphore and not as CreateSemafore !!!
Then, impossible not to notice that the strings "CreateSemafore" and "GetProcAddress" have the same size (14 characters) !!!
Laserlock thus replaced the name of GetProcAddress API by a string with same size…
We have just to patch like this (replace by the good API, i.e. GetProcAddress):





You can also, even if it is less clean, modify the pointer to the string "CreateSemafore", so that it points to "GetProcAddress" (for example the one, which is not far from the PE and that Laserlock has "redirected" for its own use…).



In this case, you have to put in 005032C4, a pointer to 000004A2 instead of 005046D2… (You must point in fact, 2 bytes before the name of the function, to point to the ordinal).

Now, the game launches without any problem and much more quickly too ;-)
Moreover, it is compatible XP.
Note : You can add the GetProcAddress ordinal (that can be easily found with ImpRec), but the cracked game launches without problems on other OS, if you didn't add it...

Lastly, it remains a CD-check, but this one is independent of the Laserlock commercial protection and is implemented by the editor (and is thus not very hard to crack).

4. Cracking the CD-check:

If you want to crack the game in order to be able to play without CD, ensure first that game is complete (full installation).
We launch the game, after having removed CD. A box with the following message : "Please insert the game CD" appears…



It is a traditional CD-check (like 90% of CD-checks), which determines initially the type of drives, you own, by GetDriveTypeA API, then when it finds a drive letter corresponding to a CD drive, it determines the CD volume (possibly inserted) by GetVolumeInformationA API and finally compares volume with the one, which corresponds to the game… *

Introduction of CD-checks corresponds to the beginnings of the Internet and their goals were only to prevent execution of games, illegally distributed by the Internet.
The democratization of CD writers made their use completely obsolete.
Who doesn't have a CD burner now ? Moreover, it is possible to burn a CD-RW with exactly the same label to play and avoid them, unless there are other checks (about presence of a specific file, CD size, etc.)…
These CD-checks are thus here only to annoy people and by no means prevents the intensive "hacking" of games…
(commercial protections have already great difficulty to fight, then even less them…).
And do you believe that game editors, when they develop or test their game, they insert a game CD, which does not exist yet ?
Stop believing and following instructions from editors & co, with their useless and imperative CD-checks like "you must absolutely insert CD"....

To locate the routine in question, you can disassemble with W32Dasm the previous dumped / rebuilt executable file…
You just have to search APIs like GetDriveTypeA and GetVolumeInformationA APIs .
Four GetDriveTypeA API occurences can be found, but the one, which corresponds to the CD-check is in 0045EC43, where there's the famous cmp eax, 00000005, just after its call…
Concerning the GetVolumeInformationA API, there are 2 occurrences and obviously the important one is in 0045EBE2…

* Here's the routine in question:






This routine can be called from 5 different places in the code. First, it determines, if a drive letter corresponds to a CD drive, by a call to GetDriveTypeA api in 0045EC43.
If it is not the case, we jump in 0045EC86, where al (letter designating a drive) is incremented, then we return to the previous loop (in 0045EBF5) until finding a CD drive or by default, terminating at letter z …
If the routine finds a CD drive, we continue with a call to GetVolumeInformationA API (in 0045EC70). If a CD is inserted in drive, this API returns the volume of this CD, volume, which is immediately compared with the string "CDTMS2003" at 0045EC82.
If the good CD is inserted, the drive letter, where CD is inserted, is finally stored in memory in order to be tested further…
If CD is not present or it is not the good one, we start again the loop, which accomplishes these tests, by incrementing al (letter drive to test) to letter z …

As we saw, the previous routine can be called 5 times.
The call to this routine, in 0045DC77 is the one, which determines or not the MessageBoxA display (which is done by the call ebx in 0045DCDA) :



The loop, starting at 0045DC86, is executed each time we click on "Try again" and each time there is not or a bad CD, inserted (test in 0045DCE7).
If you have just avoid this 1st check, while launching a game, you will have this (Insert CD) :



It is the check at 005EC431. You will not leave this message as long as you will have not inserted the game CD …
Thus, to crack definitively this game, it is proper to force the jump in 0045EC84 (the comparison between the volume and the string "CDTMS2003"), rather than to force the 5 jumps following the calls to the check routine (in 0045DC77, 0045DCE7, 0045EA06, 0045EADC and 005EC431).


C) "Reversing" Approach :

1. Fixing "variable" addresses :
The first problem is these "variable" addresses : it is never the same values on each launching…
What we know, it is that addresses are something like 00BAxxxx, where xxxx vary each time…
We launch tms2003.exe with Symbol Loader and come here (on OEP of this packed program) :



After execution of call at 00401358, we have eax = 00B90000.
After execution of call at 0040141A, we have eax = 00BA0000. Hum…

And, while tracing a little, here's the code, which fixes the "random" aspect of addresses in protection :



The variability of addresses is determined by the variable / random value, contained in eax and computed by routine located in 004015D6, called by the call 004015D6 on 00401447 address.
To remove any variability, type r eax 0, after execution of call 004015D6.
You will thus have same instructions of protection, always at the same addresses. That gets us out of a mess …
How this "random" value is calculated ?
Quite simply from returned values of GetLocalTime and GetSystemTime APIs …



Let us leave this last routine by executing the ret in 00401649 and let's continue to trace the program until 004014D5 :



What does the routine called in 004014D5 make ?
It precisely deciphers beginning of code, which contains variable addresses …
Here, it is a block starting in 00BA0000 (esi) and with a size of 7B9D (ecx)…



Once this block of instructions is deciphered, it has just to jump on this last…



Notice that the jump is not done to 00BA0000 (ebx), but to 00BA0000 + 048B5AC0 - 048B5930 = 00BA0190 (ebx + esi), computed by instructions in 0040155A, 0040155F and 00401565…
Finally, we arrive then after execution of previous ret, in 00BA0190 (beginning of code with variable addresses):



i.e. polymorphic code (interleaved jumps, obfuscation code, junk code), supposed to make hard crackers' life…
Here is another example of this type of code :



Rem: If you want to trace this code, you have to use the Step Into (F8), because of these "call eip+8", which are everywhere in this code…

2. Polymorphic code :

Before an approach of SPEEnc polymorphic code, here is a reminder on this subject by Pulsar (Thank you Pulsar) :


Polymorphic code or overlapping :

It can happen that tracing in SoftIce is obstructed by Appearances Changing Codes (CCA):
Softice disassembles an instruction at offset EIP (let us say that the number of bytes that it makes is called NBI), followed by an instruction, positioned to EIP+NBI....
It is thus rather easy to make CCA.
Let us imagine the following sequence :

jmp @1
dB E8h
@1:
mov eax, [eax]
inc eax
inc edx

In memory, you have something like :

EB01
E8
8B004042

but E8 is the byte, where begins an opcode like "call offset", so this code, if it is disassembled by increasing addresses will give :

EB01 jmp @1
E88B004042 call addresses

When you will trace by jumping the jump, you fall in the middle of the call opcode, and softice will re-disassemble this instruction, what will give the impression, that the code changes appearance - > CCA
You surely understood that it is thus very easy to make code like this, by adding various types of bytes. Instead of E8h, we can add 0CDh, 020h which corresponds to a int 20h - > VMMJump, which uses the DWORD, following the opcode… and SoftIce will thus display something like this :

int 20 VXDJump XXXX, XXXX
with XXXX, the XXXX value contained in the DWORD, following the int 20....

If you have not have understood it, this type of coding is particularly long, painful, and tiring to trace (not to say....), and you have to trace it VERY carefully, since you practically never see, which will be the TRUE following instruction.
To have already met this type of coding, allmost ALL Call address must be traced Step Into (F8).
A solution to trace the CCA is to do it "by the old way" by looking at memories addresses on the left of the screen, and as soon as there is a rather consequent jump, it is that the packer has finished its work.

Another major disadvantage of the CCA is the difficulty in putting BreakPoints on eXecution, SoftIce doesn't accept to put its INT3 in the middle of a code. The BPM address X give good results, but are limited to four.   Pulsar ( from a text about anti-debugging)


Now, we can study polymorphic code of SPEEnc ;)
To be able to clean it as well as possible, it is advised to study in detail its basic structure :





We see a basic sheme with 2 different types of blocks (the 1st and the 2nd) with variations about register nature.

Note: It is not really a listing, such as we could obtain after disassembling… I modified this one to thus make it dynamic "and more comprehensible"...
For example, on the 2nd block, after execution of the MOV EBX, D82407EB in 00BA01C3, we executes the POP EBX (in 00BA01C3+5=00BA01C8) and not the (JMP 00BA01CD) "contained" in instruction MOV EBX, D82407EB, jump at which we arrive by JMP 00BA01C4…
You have to be carefull with the call eip+8, which constitutes "anti-tracing" trick, because a Step Over (F10) in one of these calls starts launching of the program… Thus, you have to trace all code in Step Into (F8), which combined to the polymorphic code, quickly becomes very painful...

The instructions "really" executed are those indicated by an arrow < - (these are those that the author wants to dissimulate, and present before introduction of polymorphic code and finally are important protection instructions…).
The junk code is consequent : on 100 instructions, approximately 90 relate to this last… The "real" code hardly represents 10% of this routine :(
If we reason with place occupied by these junk code instructions, we have approximately 80 bytes occupied by this one, on a total of 120 bytes, that is to say approximately 2/3…
The relative importance (in weight) of this junk code, in the protection code is thus significant !!!
But the fault of this polymorphic code comes to the fact that it is generic; its basic structure is easy to find. It is thus easy to destroy it :)
Poor protectionists… Perhaps another time ?

The polymorphic code being dissected, we can now destroy it using this routine :

title cca
.386
.model small, stdcall
option casemap :none

.code

    _TextStart             equ 00BA0000h
    _TextEnd              equ 00BA7B9Dh

start:
    pushad
    mov edx, _TextStart

@1: cmp edx, _TextEnd
    je @2

check1:
    cmp word ptr [edx], 01EBh
    jne check2
    cmp word ptr [edx+05], 07EBh
    jne check2
    cmp word ptr [edx+0Ah], 0F9EBh
    jne check2
    mov ecx, 0Eh
    jmp paste

check2:
    cmp word ptr [edx], 04EBh
    jne try_again
    cmp word ptr [edx+03], 04EBh
    jne try_again
    cmp dword ptr [edx+14h], 03
    jne try_again
    cmp word ptr [edx+29h], 04EBh
    jne try_again
    cmp word ptr [edx+2Ch], 0FBEBh
    jne try_again
    mov ecx, 2Fh
    jmp paste

paste:
    mov al, 90h
    mov edi, edx
    rep stosb

try_again:
    inc edx
    jmp @1

@2: popad
    int 03
    nop

end start


You have only to put, in _TextStart, address of polymorphic code/routine beginning and in _TextEnd, its end…
Assemble it and load it in adump.
The routine then will nop us all the useless instructions and then, let us show what is useful and interesting ;).
Dump this "unpolymorphic" code… (/DUMP 00BA0000 7B9D C:\SPEEnc.dat under SI).

3. Code in general :

We can now study SPEEnc, quietly…
We can already say, just by using a hexadecimal editor, that this SPEEnc is mainly executable code mingled with datas, comments and even imports!!!










Indeed, having an "infected brain" does not help to make good protections ^^ (just joking :p).

In order to study this code, I use W32Dasm :p…
As I am always in a hurry, I don't have time to wait for IDA's analysis, nor to comment its listing, making it more comprehensible. Moreover, polymorphic code is removed, W32Dasm can disassemble it without any problem …
To make correspondance between addresses in W32Dasm and those in memory (those fixed like previously), you have just to add address base (here, it is 00BA0000h).

4. Locating OEP easily:

When we are on OEP of tms2003.exe, if we take a look at the stack (esp=B7FE3C), we obtain something like that :



Thus, not only, polymorphic code is useless (it is generic and can be easily removed), but it also constitutes one fault, owing to repeated sequences of call eip+8... (they constitute "markers" on the stack).
This enables us to go up on instructions, which "jumps" towards the OEP…

This (going up on these instructions) is interesting for two reasons:
- Now, it is much easier to come at OEP (by a simple bpm 00BA6D87 X).
- the 2 last instructions (FINIT / RET) and even better with the following instructions, it enables to have a signature of this packer. This facilitates thus our life and tracers/unpackers' task, you could code…



The routine of the top (in 00BA5FFB) makes it possible to calculate the OEP where SPEEnc must jump…

ebp+048BD074 is equal to 00BA7744, which contains the value 9B6D10DB.
ebp+048B596E is equal to 00BA003E, which contains the "encoded" OEP: 9B917A32. (in red, here)
ebp+048B5972 is equal to 00BA0042, which contains the Image Bases (400000h). (in green, here)

The Image Base is in SPEEnc since the beginning…
Image Base, which is initialized (at the beginning of protection), by this code:

01A7:004013EC     3E8B853E000B10      MOV EAX, DS:[EBP+100B003E]
01A7:004014F3     89041E                        MOV [EBX+ESI], EAX

So, OEP "is just coded" and a simple subtraction makes it possible to find easily!!!
OEP (VO) = 9B917A32h - 9B6D10DBh = 00246957h

5. Anti-debugging tricks:

At first time, we could say that there were no anti-debugging tricks.
Indeed, game launches without any problem with SoftIce, loaded. We have no warning message, no crashes, exit or anything else...
So, there is no direct debugging detection.
But, when we put bp / bpm (hardware breakpoint), we discover that anti-debugging tricks are present...

First of all, a small log of FrogsIce (Thank you +Frog's Print):



Hook of interruption 3:



Laserlock thus hooks the int 03 to its own routine (located in 00BA21BC), which take care of erasing Debug Registers (dr0, dr1 and dr2) and by the same time clearing the Hardware Breakpoints !!!
Moreover, this routine in 00BA21BC is called (in ring 0) much more than once, by the int 03, disseminated a little everywhere in the code…
By putting a bpx adresse/API, you go directly on this routine (but not when it was planed :p) and you got a pretty crash in 00BA21FA !!! (on Ring 0)
Quite simply because the address ds:[ebp+048B5986] in 00BA21FA (1) is not "valid"…
It is the same for the address ds:[ebp+048BD074] in 00BA231E (2), where you arrive if you avoided the 1st crash by modifying the eip.

And if you manage to return to windows after these crashes, you will got a crash of the explorer, each time you want to go anywhere that the Desktop (My documents, any folder, etc…) and even when you want to restart the computer …
Indeed, a crash (or an early exit) of SPEEnc lets the int 03, hooked (it is not very clean), which is not the case for Starforce. The explorer seems to use int 03, when folders are browsed. If you minimize the game between the hook and the unhook by the SPEEnc, after a breakpoint and an infinite loop, you will obtain explorer's crashes in case of browsing folders.

Now, why these crashes in (1) and (2) ?
Because of the "ebp excentric" value. When SPEEnc is normally executed, ebp has a certain value.
When we are in (1), ebp = FC2EA6D0, so ebp+048B5986 take 00BA0056 as value and eax = 9B6D10DB.
When we are in (2), ebp = ECCD9F74, so ebp+048BD074 take 00BA7744 as value (eax has its previous value).
So, when a int 03 is called at any other moment (that the ones specified by the SPEEnc), like a bp, there will be big chance to have an invalid memory access (on read / write), because of the different value of ebp register.

The restoration of IDT, on the int 03, is done only just before the redirection towards the OEP of the unpacked executable …

Note: The int 03 is hooked by the instructions in 00BA1F7E and 00BA1FCF… (see my Tutorial about Starforce for more detail on the IDT).
If we avoid the hook of int 03 (by avoiding the instructions in 00BA1F7E and 00BA1FCF), the program will crash… (this is due to the int 03, disseminated a little everywhere in the code).

Clearing Drx:



This routine is not very efficient, since I can break on Laserlock code without problems, using a bpm !!!
Indeed, when we put our 1st bpm, SoftIce uses the dr3 and as this one is not erased, we can thus break.
Thus, this routine limit only the use of hardware breakpoints to one!!!
And you are by no means prevented from putting several bpm and breaking without problems in the code separating two consecutive int 03…
Nopping the mov drx, eax makes crash the program, much further, because of the integrity checks of SPEEnc !!!
It is thus necessary to proceed differently to circumvent this…

Interruptions (int 03) disseminated a little everywhere in the code:

Presence of int 03 in 00BA1BD2, 00BA1C93, 00BA205C, 00BA23CA, 00BA2656, 00BA2847, 00BA29CE, 00BA3C48, 00BA3F82, 00BA43A1, 00BA445E, 00BA4A69, 00BA4EBB, 00BA515D, 00BA55FC, 00BA6073 and 00BA66B2. They are thus rather numerous and are as many possibilities of anti-bpx and anti-hardware breakpoint (by clearing the drx).

Some examples:

















etc…

You have certainly seen this recurring cmp dword ptr ds:[ebp+048B59C0], 00000000 and preceding all the int 03 (except the one in 00BA205C)…
And what does correspond ds:[ebp+048B59C0] to ?
It is there, that is stored the old routine ("the address") of the int 03 previously hooked …
However, as we saw, if we only try to avoid the hook of int 03, the program crashes … (because of all these int 03).
Then let's test this :
In 00BA1F26 (storage of the int 03 old routine), we put edx at 0 (r edx 0), so that it saves this value.
In 00BA1F7E, we avoid the instruction while making point eip on the following instruction (r eip eip+3).
In 00BA1FCF, we avoid also the instruction by a "r eip eip+4".
Lastly, we avoid the int 03 in 00BA205C (r eip eip+1).
And now you will be able to put all the bpx/bpx API you want :)
We solve in the same time the anti-bpx and the drx clearing…

But why this presence of cmp / je?
Because contrary to win 98, XP does not make possible any read/write attempt in IDT in ring 3 (normal execution mode of programs)…
This code ensures thus compatibility with this last system.

You will have noticed that this int 03 hook routine is included in a "SEH structure". Any attempt to read / write IDT values on XP send us directly to (39)07A6 (SE Handler), 390000 being Image base of the SPEEnc...

Restoration of IDT (on the int 03 vector):

Just before the "jump" towards the OEP of the unpacked executable, the IDT is restored:



Many exceptions (SEH):

SPEEnc contains many exceptions throughout its code:



Here it is the routine, which determines whether there is enough available memory for SPEEnc.
If it is not the case, the jump in 00BA32DD is not carried out and this following error message appears :



The use of all these exceptions, present a little everywhere in the code, is probably used as anti-tracing technique, but it's useless …

6. Integrity checks :

Here's the integrity checks routine of SPEEnc code, which makes you avoiding code modifications (if not -> risk of a crash) :



This routine is called several times by the call 00BA7248, located in 00BA722C.
On the 3rd call, the check is done on the SPEEnc, about the block starting in 00BA0190 (esi) and with a size of 7540 (ecx).
The result of the operation is finally stored in eax.



7. Decoding layers :

1st decoding layer:
We saw that it was carried out at 004014D5, in order to decipher the block starting at 00BA0000 (esi), with a size of 7B9D (ecx) (see the chapter fixing the variable addresses). But in fact, instructions are valid, only for the block starting in 00BA0190 and finishing in 00BA04A5, which can be explained by the application of a second decoding layer…

2nd decoding layer:
Then, once our 1st block is deciphered, the following routine, at 00BA733F (identical to the previous one, but with polymorphic code, this time), called at 00BA0455, is charged to decipher the block starting at 00BA04A5, with a size of 44F2.



This routine is then called at 00BA1B32, to decipher a block starting at 00BA9A46 for a size of 3421B (from datas…).
The checking of the disc is then carried out…
The call at 00BA1B32, calls this routine again to decipher the code at 00BA4997, with a size of 2617 (all the executable code of SPEEnc is thus deciphered…), then to decipher a block of datas on SPEEnc, starting at 00BA748C and with a size of 244.

Unpacking of the tms2003.exe is finally executed, using this routine also (00BA733F). It is called several times by the call at 00BA5ABC, to proceed by blocks, starting from the end of executable (relocations) and going up gradually…
It remains a last important question : is it possible to crack this version of Laserlock without having an original CD ?
The answer is yes :).

8. Faultsin original disc authentification :

To determine where disc checking is done (authentification), we have to put a breakpoint on GetDriveTypeA API (don't forget to avoid anti-debugging tricks). Then, we land in NIL32.dll module.
When re-running the executable file and putting a breakpoint on CreateFileA, we see that Laserlock creates some temporary files in C:\Windows\TEMP :
- nomouse
- nomouse.com
- nomouse.sp
- NIL32.dll
- SPEEnc.Dup

These files are erased, when the SPEEnc has finished its task (when the game starts).
So, it is possible to retrieve NIL32.dll, by stopping in the code before the time, it is created and after the time, it is deleted (for example, by breaking on GetDriveTypeA). We have just to go in the temporay folder to copy it. The hook (interception) of the int 03 by the SPEEnc must be avoided, because the explorer interferes with this hook (use of int 03 by the explorer in folders navigation) and leads to a crash...
We edit the dll PE with LordPE.
OEP is 0A150 (RVA), Image Base is 0x10000000.
We have just to put a bpm 1000A150 X to break at the OEP.



We break on it. We run again (F5) to break a second time.
The NIL32.dll module is then unpacked (deciphered) and 1000A150 seems to be the OEP of the unpacked dll.



And if it is not the case, it does not matter, because we want to dump this dll, only to study it in dead listing.
In the code, we can see some call [00C0xxxx], corresponding to the Laserlock redirected call [API].
We have again variable addresses at this stage.

We launch a call-fixer to solve this problem.
Then, we dump at the OEP, with LordPE :



We create a new Import Table with ImpRec :



To do it, we choose the tms2003.exe process. We click on Pick DLL and we select the nil32.dll module.
Then, we have just to enter the beginning of the IAT : 1E000 (RVA), its size : 1F4 and to click on Get Imports.



Don't forget to solve the GetProcAddress import to obtain the new Import Table (see previously).

By disassembling the dll, we can see a part of code, which is still ciphered (offsets from 0x2E66 to 0x5CED, that is to say, a size of 0x2E87) :



We can put a bpm 10002E66 X to break and dump the deciphered code with LordPE :



Then, we replace the deciphered code in the previous dumped .dll .

We obtain a fully rebuilt dll. By examining the disassembled code, what can we see ?
The same String Data References as the Laserlock v5 dll : "*LASERLOK* Copyright (c) 1992-1996", "Petros Skalkos **", "v5.00.607 Compile:21/3/2002".

Finally, protectionnists re-release always the same protection but in a different way.
They take their old protection dll (previous version) and have just implemented the SPEEnc, as a layer, enabling to hide the dll protection...

How can the CD authentification be bypassed ?
By putting a bp on the GetDriveTypeA API, we land at this code :






We have the classical APIs couple : GetLogicalDriveStingsA (returns the existing drives on the system) / GetDriveTypeA (returns the type of a specified drive).
The GetFileAttributesA API returns the LASERLOK.IN file attribute (hidden attribute). So, the flag can be reversed (or some nops can be placed).

We can also make inconditional, the jump on 10005620 (it has the same effect).



So, it is possible to crack Laserlock SPEEnc without the original disc.
Bypassing the check on LASERLOK.IN file attribute, seems to be enough to avoid the other physical structure checks,
as some SDRs let it assumed : "_*NTCD_Last5 ChkSum error*", "_*NTCD_Prev ChkSum error*", "_*NTCD_SIGN not found*",
"_*NTCDFound*", etc...

However, Laserlock does not reach the security level of some other protections, at this stage .
Indeed, the CD physical structure (defective sectors or something else) is usually used to prevent copy, but is also used by some protections to extract a key, enabling the game executable to be deciphered...
Then, an original CD is needed to crack it, unless the deciphering algorithm implementation is bad (faults, bruteforce, etc...).


D) Conclusions :

Generalization:

What changes from one game to another?
I looked at another game, protected by the same version of SPEEnc. It is Codename : Outbreak…
When they say that Laserlock is not generic, it makes me laugh.

It is exactly the same principle…
The "differences" are :
- the "Image Base" of SPEEnc changes… It is 007A0000 instead of 00BA0000.
- the OEP is always "decoded" by subtraction. This time, 9F9B992D is subtracted instead of 9B6D10DB
- the instructions of "fixed" SPEEnc have slightly different addresses: the RET, which makes jump towards OEP is in 6C06 instead of 6D89 from tms2003…
This must be explained by a "pseudo-random" insertion of polymorphic code blocks into SPEEnc…
- API GetProcAddress is redirected twice in IAT (in 50C244 and 50C3A4) instead of one…
- the IT is more destroyed than in tms2003, since the pointers towards the name of dlls are also cleared (Dword 1).
In other words, nothing fabulous to deserve the name of "non generic" protection !!!

Infos (for this game) :
OEP = 8E3AC (VO)
IT begins at 50C000 (size: 1D0)
IAT begins at 50C1F4 (size: 9F0)

Now, you have enough information to make your own unpacker ;-)
Creating a unpacker in this case is more educational than another thing ; very few games have been protected with SPEEnc version of Laserlock… (Codename : Outbreak, Tennis Masters Series 2003, Post Mortem and Warrior Kings, in France…).

This protection is finally easier than it appeared at first ;) …
It still contains many errors of conception and is very far from being incrackable, as its authors ensure it…

You can always thank the author for this amusing and interesting protection ; he kindly left us his email…



As for Microïds, I am disappointed, that they closed shop and I do not understand why…
This french editor:studio made good games like Syberia 1 & 2, Tennis Masters Series, War And Peace: 1796-1815, compared to the garbage that french studios like Davilex or Cyanide make, studios which are still alive!!!
They have already tested all the protections available on the market: Laserlock with Tennis Masters Series 2003, Safedisc with Syberia 2, Starforce with War And Peace: 1796-1815, VOB ProtectCD with Tennis Masters Series (the first)… In vain…

Here it is finished with Laserlock tutorials :p



Removing the CD-check of Codename : Outbreak :

Once Laserlock removed from Outbreak.exe, it remains a CD-check to remove :



The game launches (without movies) and then we reach the main menu…
But the two options "Play solo" and "Intro" are grayed and nonaccessible :



Moreover, a click on "Play solo" displays the following error message (it is not the case for "Intro"):



Lol… Even if you have the original, you got a limited version if you do not insert the CD!!!
We will destroy this. Disassemble Outbreak.exe, for example with W32Dasm. We look for GetDriveTypeA/GetVolumeInformationA APIs and we fall on this code :





This routine of CD checking is very close to that of Tennis Masters Series 2003, except for the use of GetLogicalDriveStringsA API…
This API determines the drives configuration of your computer, making it possible to restrict the tests by GetDriveTypeA API on drives to the existing ones only.
The GetDriveTypeA API determines for a given drive, if it is a CD drive.
In a such case, the GetVolumeInformationA API returns the volume of inserted CD (if there is one).
Lastly, returned volume is compared with "OUTBREAK" string …

This routine is called twice, at 0046369B and at 0048E0D8…
The call in 0046369B is not followed by a test, contrary to the one in 0048E0D8 :



You will have understood that you just have to nop the conditional jump in 0048E0DF, to launch the game (with the movies) and to play without CD!
And for the fans of String Data References :


E) Thanks:

Greetz:

ACiD BuRN, ArthaXerXès, Black Check, cdkiller (ProtectionID), CyberBob Jr, ^DAEMON^, Dark-Angel, DecOde12, diablo2oo2, Duelist, El-Caracol, EliCZ, Elraizer, evlncrn8, Fravia+, +Frog's Print, KeopS, Gádix, GRim@, G-RoM, Iczelion, kilby, Laxity, Lorian, LutiN NoIR, MackT, MrOcean, NeuRaL NoiSE, Neutral AtomX, Ni2, Nody, [NtSC], +ORC, Pedro, Peex, PEiD (snaker, Qwerton, Jibz), Psyché, Pulsar, +Pumqara, Ricardo Narvaja, Skuater, +Spath, +splaj, Stone, TeeJi, The Owl, tHeRaiN, TaMaMBoLo, +Tsehp, Tola, woodmann, +Xoanon, [yAtes], yoda... and all those which I forgot and who contribute actively to the scene by their tutorials, tools and others…

all the icedump TEAM, ARTeam, CracksLatinos, DREAD, FRET, ShmeitCorp, UCF2000, UNPACKiNG GODS, TMG, all game groups…

All +HCU Students
All ppl of RCE Messageboard

these great sites:
http://207.218.156.34/krobar/index.html
http://arteam.accessroot.com/
http://tuts4you.com/
http://www.woodmann.net/forum/index.php
http://www.woodmann.net/yates/index.htm

Special Greetz:

Christal: Thank you for all that you did for the French scene and your so great implication. My best regards :)
Laserlock: Thank you to the developers of this protection, for the few recreation hours (too few …)
+Frog's Print & +Spath: Thank you for FrogsIce :-)
GRim@: Thank you for your "Beginner" tutorials, with which I started…
R!SC: Thanks, Master, for your tuts about CD-ROM commercial protections, like Safedisc, SecuROM, VOB ProtectCD, etc…: -)
All members of FFF ;-)

Message to TomRipley : Plz, come back !!!

Final words:

I hope that you enjoyed reading this tutorial.

If you want to study this protection, I can upload these tutorial targets. So, mail me at :
dWx5c3NlMjAwOV9mckB5YWhvby5mcg==
(base64 encoded)

I tried to make an original presentation "cracking"/"reversing" to show that it was possible to crack commercial protections with a minimum of knowledge and without be aware of all the various anti-cracking techniques of protection…
A vague idea of these various techniques is largely enough as you have seen…
It is nevertheless much more interesting to reverse these techniques and it highly facilitates the attack ;)
But, the boundary between these two concepts tends to be currently erased.
Reality is always much more complex than a simple dichotomy…

Concerning Tennis Masters Series 2003, I would say that it is one of the best (more complete) games of tennis, on PC, with the Top Spin series …
It is very far from the poor/terrible level of the Roland Garros game on PC!!!

"If you like a game, Buy it !"


uLysse, on 27 / 02 /07

"There is a crack, a crack in everything... That's how the light gets in."

For any critical comments, suggestions, informations about the latest Laserlock protections, feel free to contact me at :
dWx5c3NlMjAwOV9mckB5YWhvby5mcg==
(base64 encoded)
Any crack request will be ignored !!!

Copyright © uLysse / FFF