TUTORIAL sur Laserlock SPEEnc (le jeu Tennis Masters Series 2003) :



Protection commerciale : Laserlock SPEEnc v 2 (http://www.laserlock.com/)
Editeur : Microïds
Date de sortie : FR 01 novembre 2002
http://www.jeuxvideo.com/articles/0000/00002557_test.htm
Niveau requis en cracking : [ ] facile    [x] intermédiaire    [x] confirmé    [ ] expert
Il est préférable d'avoir déjà cracké des protections de jeu de type Safedisc/SecuROM avant de lire ce tutorial (+ des connaissances sur le PE, manual unpacking, anti-debugging et imports rebuilding) et peut-être d'avoir mon précédent tutorial sur Laserlock :p

Outils nécessaires :
Softice 4.01
Icedump
Procdump / LordPE
Hiew / Hex Workshop
W32Dasm v8.93
Adump
Masm v8

Vous devez posséder le jeu original ou un clone fonctionnel (il y a un profil Laserlock dans Alcohol 120%), pour pouvoir appliquer ce tutorial...
De plus, il s'agit de la version française du jeu Tennis Masters Series 2003...
Ici, l'exécutable protégé est "Tennis Masters Series 2003.exe", que l'on appellera désormais tms2003.exe...

OS sur laquelle je travaille: Win98 SE.
Ce tutoriel est aisément transposable sur d'autres debuggers (OllyDbg, par exemple) et d'autres OS.


Ce tutorial est détaillé de façon suivante :

A) Introduction et généralités
B) Approche "Cracking"
1. Localiser l'OEP
2. Fixer les call Laserlock
3. Reconstruire les imports
4. Contourner le CD-check
C) Approche "Reversing"
1. Fixer les adresses "changeantes"
2. Etude du code polymorphe
3. Etude du code en général
4. Localiser facilement l'OEP
5. Etude des anti-debugging tricks
6. Vérifications d'intégrité
7. Etude des couches de cryptage
8. Faille au niveau de la vérification du CD original
D) Perspectives et conclusion
E) Remerciements

A) Introduction et généralités :

Laserlock est une protection commerciale créée par MLS LaserLock INC.
Elle est caractérisé par un dossier Laserlok à la racine du CD (il est caché -> ils nous prennent pour des cons).
[Le CD est d'ailleurs caractérisé par la présence d'un anneau bien visible au centre...]
S'ils croient qu'en mettant l'attribut caché à des fichiers "sensibles", on ne voit pas leur petit jeu... -> "une technique pur lamerz" :p
Ce dossier Laserlok contient 5 fichiers laserlok.in, laserlok.o10, laserlok.o11, laserlok.o12 et laserlok.o13, tous cachés (pour un poids de 92.9 Mo !!!) ...

La protection repose sur ces fichiers "incopiables" (en tout cas de façon conventionnelle ).
Il ne reste alors à la protection, qu'à vérifier la présence de ces fichiers pour déterminer s'il s'agit d'une copie ou non.

Quant à la protection au niveau de l'exécutable, elle est aisément détectable en éditant celui-ci à l'aide d'un éditeur hexadécimal :



Ils sont gentils ; ils nous donnent même la version du SPEEnc (ici, il s'agit de la version 2).

Enfin, sur leur site (copie disponible datant de Septembre 2003), on est averti (au secours Maman, j'ai peur :p) :


LaserLock consists of the following successful combination:

Actually, it is this powerful combination that makes LaserLock protection system so secure, unique and reliable, 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 software and the devices of the global market
- The most compatible copy protection system worldwide (CD-Rom and DVD-Rom drives)
- Totally transparent to replicators and end-users, no passwords, no extra devices.
- Of low cost and high efficiency.
Alors là, je ne sais vraiment pas quoi dire :o

Protections mises en place :

L'exécutable du jeu est packé :
Packed by SPEEnc V2 Asterios Parlamentas
\=-SPeEnc loader rutine d02-07-01r by Asterios Parlamentas\=-

Redirection au niveau des APIs de TMS2003.exe ( call/jmp API transformés en call Laserlock ).
Redirection de l'API GetProcAddress au niveau de l'IAT.
Les protections précédentes sont assurées par l'exécution préalable d'une routine le SPEEnc (contenue dans l'exécutable du jeu)...
Celle-ci permet une variabilité des adresses, l'introduction de code polymorphe en son sein, mais aussi diverses techniques d'anti-debugging (anti-bpx, etc...), du décryptage par blocs au fur et à mesure de son exécution, des vérifications d'intégrité, etc...

Les différentes étapes de la protection :

1. Mise en place des adresses changeantes
2. Mise en place du SPEEnc (le SPEEnc dispose de différentes techniques anti-cracking telles que du code polymorphe, du code anti-debugging, etc...)
3. Décryptage au fur et à mesure de blocs de code exécutable du SPEEnc
4. Puis on a la protection proprement dite (lecture de la structure physique du CD, mise en place par la protection).



Si l'authentification du CD a échoué, on a la boîte suivante :



5. Le SPEEnc effectue quelques vérifications d'intégrité (et notamment sur lui-même)...
6. Le SPEEnc décrytpe alors l'exécutable tms2003.exe, puis saute sur son OEP
7. Les APIs sont détournées vers une routine du SPEEnc, qui calcule et retourne la bonne adresse de l'API détournée

B) Approche "Cracking":

1. Localiser l'OEP pour unpacker l'exécutable :

Après deux petits jump après l'OEP, on arrive en 0040117B et d'après le code, qui suit, on peut déjà se douter que l'exécutable est packé... (cf. le pushad en 0040119F).



Pour arriver à l'OEP "réel", testons d'abord les bpx APIs classiques (par exemple, bpx GetVersion)...
Baooom, le PC explose... lol... Nan, juste un crash... :p
Il est donc inutile de poser tout bpx à cause des anti-bpx...
Comment alors arriver à l'OEP de notre exécutable unpacké ?
En posant un bpr 402000 650000 R (memory breakpoint).
Pourquoi 402000 ? Parce que cela permet d'éviter de retomber sur les instructions de la protection (de 4010D1 à 40192A) avant le ret en 0040157C (qui permet d'arriver dans le code "aux adresses changeantes").
Pensez à mettre un "range" assez grand, car bon nombre de jeux n'ont pas leur OEP aux alentours de 401000 (contrairement à beaucoup d'exécutables de sharewares)...
Un 1er break nous amène sur l'instruction LODSB en 00BA73FE :



On désactive le bpr par un bd 0 et l'on met un bpx 00BA7417 pour sortir de la boucle...
Zut : faut pas utiliser de BPX !!! Dans ce cas, on crashe en 00BA21FA...
Il faut donc préférer un bpm 00BA7417 X (hardware breakpoint).
On réactive ensuite le bpr par un be 0 et l'on relance pour breaker ensuite sur l'instruction REPZ MOVSB en 00BA5078 :



On désactive à nouveau le bpr (bd 0) et l'on exécute l'instruction REPZ MOVSB en 00BA5078 par un F10 (Step Over)...
On réactive alors une dernière fois le bpr (be 0) et l'on relance pour enfin breaker 1 min. après, sur l'OEP de tms2003.exe unpacké ;)

Note : Une méthode plutôt moyenne pour "trouver" l'OEP de l'exécutable unpacké consiste à le dumper en cours d'exécution (il est alors décrypté / décompressé), puis à désassembler ce dump et à chercher dans le code :
push ebp
mov ebp, esp
Elle peut constituer un moyen de vérification tout au plus (car il y a plusieurs occurences)...

2. Fixer les call Laserlock

Si l'on regarde attentivement le code au niveau de l'OEP, on a ceci :



On s'aperçoit déjà que les call API (mais aussi les JMP API) sont tous remplacés par des call dword ptr [00BA7760].
Il s'agit donc d'une redirection des APIs.
(On les appelera les "call Laserlock").

Important : Gardez à l'esprit que toutes les adresses du style 00BAxxxx sont variables d'une exécution à l'autre ("adresses changeantes"). Il en va ainsi pour les "call Laserlock". Ici, je les ai fixé pour faciliter les explications (voir la 2ème partie du tutorial, pour plus de détails...).

Voyons ce qu'il y a, à l'intérieur...



Cette routine calcule donc l'adresse de l'API à retourner, en fonction de l'adresse du "call Laserlock", mise sur la pile lors de l'appel à la routine Laserlock...
Toujours avec l'exemple du call dword ptr [00BA7760] en 0064697D, traçons cette routine en step over (F10) jusqu'en 00BA6FAD. En exécutant le ret, on arrive dans l'API GetVersion (Kernel) situé à l'adresse BFF92F1B... (adresses, qui varient selon la version de l'OS).



Un petit F12 nous ramène juste après notre call Laserlock en 00646983.
Pour trouver l'adresse de cette API dans l'IAT, il suffit juste de regarder dans le registre eax, lorsque l'on est en 00BA6F8E, juste sur le MOV EAX, [EAX].
On trouve alors l'occurence en 00903938 (section .idata).

On doit donc remplacer call Laserlock par call API...
Ici, il faut remplacer FF156077BA00 par FF1538399000.
e 0064697F 38,39,90,00.
Et voila, on a fixé un call.

Il nous reste plus qu'à automatiser ce que l'on vient de faire manuellement par une petite routine (un "call fixer").
Ceci constitue une protection anti-dump, dans la mesure où si l'on ne fixe pas ces calls et que l'on dumpe, l'exécutable "voudra aller" dans des zones mémoires, qui n'existent plus (et qui étaient initialisées avec la protection), entraînant irréversiblement un crash du programme...

Vous souvenez peut-être du "Call-fixer" de la version précédente de Laserlock (la version 5 de Laserlock, par exemple Desperados : Wanted Dead Or Alive) ?
Eh bien, il suffit de garder le même pour fixer tous nos Call Laserlock de cette version (il n'y a que très peu de choses à modifier).
Si vous voulez plus d'explications sur le fonctionnement de cette routine, je vous renvoie à mon tutorial précédent :p

Rem : - Par rapport à la version précédente (version 5), il n'y a plus de checksums effectués sur la routine, qui calcule l'adresse de redirection des "call Laserlock", ni d'ailleurs sur l'exécutable proprement dit, lors de l'appel à ces call. Ne nous ne privons donc pas de modifications du code si nécessaire (et c'est ce que j'ai fait en patchant à l'adresse 00BA6F8E par un jmp edi !!! ).
- La faille, présente à la version 5, qui consistait à patcher elle-même les call Laserlock par les call/jmp APIs à partir de la 50ème API et qui permettait de détourner la vérification du CD, a été corrigée...


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

En tapant r dans adump, on obtient l'adresse où l'on peut charger notre routine...
On assemble et on charge cette routine en mémoire par la commande l d'adump.

Note : Adump était juste un utilitaire, qui allouait de la mémoire afin d'y charger des routines (ou n'importe quoi), sous Softice.
Sous OllyDbg, il suffit de copier cette routine juste après le PE. On peut également allouer de la mémoire, dédiée à cette tâche sous OllyDbg (Alt+M pour avoir le Memory map, suivi d'un click droit > Allocate Memory).

On breake donc à l'OEP de tms2003.exe et l'on modifie l'eip pour exécuter notre routine (chargée dans Adump).

Note : Il suffit d'avoir tapé la commande i3here on pour breaker sur l'int 03 de la routine, qui nous indique la fin de son travail...
Une fois la routine terminée, on retourne à l'OEP, par un r eip OEP.

Tous les call ont été correctement fixés :)

Maintenant, examinons l'IAT (elle commence en 00903704 et finit en 00903CEC).
Vous aurez certainement remarqué dans cette IAT, une "valeur anormale" comme adresse, au niveau des imports Kernel...




En effet, l'adresse 009038D8 pointe non pas vers une adresse BFxxxxxx, comme cela devrait être le cas, mais en 00BA6EC7...
Il s'agit en fait d'une redirection de l'API GetProcAddress. Cette redirection se fait par modification au niveau de l'IAT, contrairement aux call Laserlock, où la redirection se fait par un appel à une routine spécifique, chargée du calcul de l'adresse à retourner (ce qui nécessite de transformer dans le code, tous les call/jmp API en call Laserlock...).

Voici la routine en question :



C'est l'instruction call ds:[ebp+048B5992] à l'adresse 00BA6F20, qui correspond à un call GetProcAddress.
Vous n'avez juste à remplacer dans l'IAT (en 009038D8), la valeur 00BA6EC7, par l'adresse de l'API GetProcAddress (pour moi, ça sera BFF76DA8).
Ca y est : on peut dumper l'exécutable :)
Maintenant, il ne reste plus qu'à créer une nouvelle Import Table ou bien à réparer celle que l'on a (et que Laserlock a partiellement détruite)...

3. Reconstruire les imports :
• The easiest way : créer une nouvelle Import Table :
Il suffit de lancer une boucle infinie au niveau de l'OEP de tms2003.exe, puis de lancer ImpRec, de rentrer les bonnes valeurs de l'IAT et celui-ci va "attacher" à la fin de l'exécutable (le dump obtenu précedemment), la toute nouvelle Import Table créée (il le fait en ajoutant une section).



On obtient ainsi un dump fonctionnel, qui marche également sur XP...

Note : On doit donner l'OEP de l'exécutable unpacké. Ainsi ImpRec corrige également l'OEP au niveau du PE, ce qui nous évite de le faire manuellement avec LordPE.

• The hardest way : réparer l'Import Table originale :
Pour des questions de facilité, j'ai dumpé de façon à avoir les VO égaux aux RO...
L'Import Table est aisément localisable (généralement, elle est au-dessus de l'IAT) :



Pour la localiser, il suffit de chercher un pointeur vers le nom d'une .dll (imports), par exemple KERNEL32.dll, USER32.dll, etc...
Il faut bien sûr travailler avec les VO (enlevez l'image base des adresses mémoires) et tenir donc compte des alignements possibles des sections (pas ici)...
Ici, l'IT commence en 503000 et se termine en 5030F0. Elle inclut 10 words nuls, indiquant comme il se doit la fin de l'Import Table (taille = 0F0).
Maintenant, on rectifie les valeurs de l'IT dans le PE, en l'éditant avec LordPE (PE Editor -> Directories -> Import Table).
Quant à l'IAT, mettez la RVA et la Size à 00000000, pour ne pas avoir de problèmes...
L'IAT est de toute façon écrasée à l'exécution du programme (par les adresses physiques des imports de l'OS en question...).

On lance maintenant l'exécutable ainsi modifié et l'on a l'erreur suivante :



lol... Super comme erreur ;-)
On va donc vérifier les valeurs dans l'Import Table, mais avant un rappel (je sais, j'ai déjà ressorti ça au tutorial précédent, mais c'est tellement concis et clair :p)


Format de l’Image Import Descriptor ou Import Table  (lire « peering inside the PE » de Matt Pietrek !) :

Une entrée (une DLL et l’ensemble de ses fonctions) dans l’Image Import Descriptor est constituée de 5 Dword.

Dword 1 - Characteristics (hint name array)
Ce dword est un pointeur vers le premier élément d’un tableau de pointeurs.
Chaque pointeur de ce tableau pointe vers le hint name suivi du nom d’une fonction.

Dword 2 - TimeDateStamp

Dword 3 - ForwarderChain

Dword 4 - DLL’s name
Ce dword est un pointeur vers le nom de la DLL (null terminated ascii string)

Dword 5 - Import Address Table
Ce dword est un pointeur vers le premier élément d’un tableau d’adresses.
Ce tableau d’adresses fonctionne en parallèle avec celui des pointeurs vers les hint names (noms des fonctions).

tiré de Import Function tutorial.doc / Import-Function in section RDATA.doc de El.CaRaCoL.
Merci à lui ;-)


Tout semble pourtant normal dans l'Import Table, sauf au niveau de tous les Dword 4 (souligné en rouge)...
En effet, il pointe vers une chaîne nulle au lieu de pointer vers le nom d'une .dll (importée).
Cependant, ils pointent au bon endroit (au beau milieu de noms de fonctions).
Laserlock a donc détruit partiellement l'IT, en effaçant les noms de .dll...
Comment retrouver alors les noms manquants de ces .dll ?
Et bien, ce n'est pas si dur que cela n'y paraît...

Pour une entrée du tableau, on cherche le Dword 5 (souligné en vert) correspondant au Dword 4 de la même librarie (souligné en rouge). On y trouve un pointeur vers les adresses physiques des fonctions de cette .dll et la 1ère fonction de ce tableau d'adresses nous permet de retrouver le nom de la librairie (par exemple, sous Softice, en tapant u, suivi de cette adresse). On peut bien-sûr suivre ce raisonnement avec le Dword 1 (souligné en bleu) et retrouver le nom de la librairie à l'aide du nom de l'une de ses fonctions...
Il ne reste donc plus qu'à patcher là où il faut par les noms des librairies...





Et voici un tableau récapitulatif :



Une fois toutes ces modifications faites, on relance et là, un double message d'erreur... (encore mieux :p)





Sans blague, on ne s'en était pas aperçu ?!!

La 1ère chose que j'ai faite, c'était de m'assurer que le tableau d’adresses (Dword 5 - Import Address Table) concorde avec celui (Dword 1) des pointeurs vers les hint names (noms des fonctions), pour la librairie KERNEL32.dll.
Ainsi le tableau d'adresses (Dword 5) pour cette librairie commence en 005037E4.
Le tableau (Dword 1) de pointeurs vers les noms de fonctions pour la même librairie commence en 005031D0.

En 005037E4, on trouve l'adresse BFF92B8F, qui correspond à celle de l'API SetEvent, fonction (sa chaîne), qui se trouve être pointée en 005031D0.
En 005037E4+F0, on trouve l'adresse BFFA1C7C, qui correspond à celle de l'API CompareStringA, fonction (sa chaîne), qui se trouve être pointée en 005031D0+F0.
En 005037E4+F4=005038D8, on trouve l'adresse BFF76DA8, qui correspond à celle de l'API GetProcAddress, alors qu'en 005031D0+F4 se trouve un pointeur vers la fonction (sa chaîne) CreateSemafore !!!

Hum... ça doit être ici le problème. D'ailleurs, c'est quoi cette fonction et pourquoi est-elle là ?

Déjà en regardant dans Win32 Programmer's Reference, on s'aperçoit qu'il y a une API de ce style, mais s'écrivant CreateSemaphore et non CreateSemafore !!!
Ensuite, impossible de ne pas remarquer que les chaînes "CreateSemafore" et "GetProcAddress" sont de taille identique (14 caractères) !!!
Laserlock a donc remplacé le nom de l'API GetProcAddress par une chaîne de caractères de taille identique...
Il nous suffit donc de patcher ceci (remplacer par la bonne API, càd GetProcAddress) :





Vous pouvez également, même si c'est moins propre, modifier le pointeur vers la chaîne "CreateSemafore", pour qu'il pointe vers "GetProcAddress" (par exemple celui, qui se trouve non loin du PE et que Laserlock a détourné pour son propre fonctionnement...).



Dans ce cas, il faut mettre en 005032C4, un pointeur vers 000004A2 au lieu de 005046D2... (Il faut pointer en fait, 2 bytes avant le nom de la fonction, pour pointer sur l'ordinal ).

Voilà le jeu se lance sans problème et beaucoup plus vite aussi ;-)
De plus, il est compatible XP.
Note : Vous pouvez éventuellement ajouter l'ordinal de GetProcAddress (que l'on peut facilement retrouver dans ImpRec), mais de toute façon, le jeu cracké se lance sans problème sous un autre OS, si vous ne l'ajoutez pas...

Enfin, il reste un CD-check, mais celui-ci est indépendant de la protection commerciale Laserlock et a été implémenté par l'éditeur (et n'est donc pas bien dur à cracker).

4. Contourner le CD-check :

Si vous voulez cracker le jeu afin de pouvoir jouer sans le CD, assurez-vous d'abord que le jeu est en installation complète (maximale).
On lance le jeu, en ayant préalablement enlevé le CD. Une boîte du style : "Please insert the game CD" apparaît...



Il s'agit d'un CD-check classique (comme 90% des CD-checks), qui détermine d'abord le type de lecteurs que l'on a par l'API GetDriveTypeA, puis lorsqu'il rencontre une lettre de lecteur correspondant à un lecteur de CD, il détermine le volume du CD éventuellement inséré, par l'API GetVolumeInformationA et enfin compare le volume à celui qui correspond au jeu... *

L'introduction des CD-checks correspond aux débuts d'Internet et leurs buts n'étaient que d'empêcher l'exécution de jeux distribués par Internet.
La démocratisation des graveurs de CD a rendu leur utilisation totalement obsolète.
Qui n'a pas de graveurs CD actuellement ? De plus, il suffit de graver un CD-RW ayant juste le même label que le jeu pour contourner ceux-ci, à moins qu'il n'y ait d'autres vérifications (présence d'un fichier quelconque, taille du CD, etc.)...
Ces CD-checks ne sont donc là que pour embêter le monde et n'empêche nullement le piratage intensif des jeux...
(Les protections commerciales ont déjà bien du mal à lutter, alors encore moins eux...).
Et croyez-vous que les éditeurs de jeux, insèrent un CD de jeu, quand ils développent, testent leur jeu, qui n'existe pas encore ?
Il faut arrêter de croire et d'exécuter à la lettre tout ce que disent les éditeurs & co, avec leurs inutiles CD-checks impératifs du style "vous devez absolument insérer le CD"....

Pour localiser la routine en question, il suffit de désassembler avec W32Dasm l'exécutable dumpé et reconstruit précédemment...
On n'a plus qu'à faire une recherche du côté des APIs GetDriveTypeA et GetVolumeInformationA.
On trouve 4 occurences pour l'API GetDriveTypeA, mais celle qui correspond au CD-check est en 0045EC43, où l'on trouve le fameux cmp eax, 00000005 juste après l'appel à l'API...
Pour l'API GetVolumeInformationA, on a 2 occurrences et bien évidemment c'est celle en 0045EBE2, qui importe...

* Voici la routine en question :






Cette routine peut-être appelée par 5 endroits différents dans le code. Elle commence par déterminer si une lettre de lecteur correspond bien à un lecteur CD par l'appel à l'api GetDriveTypeA en 0045EC43.
Si ce n'est pas le cas, on saute en 0045EC86, où al (lettre désignant un lecteur) est incrémenté, puis l'on retourne à la boucle précédente (en 0045EBF5) jusqu'à trouver un lecteur CD ou à défaut à arriver à lettre z...
Si la routine tombe sur un lecteur CD, on effectue alors un appel à l'API GetVolumeInformationA (en 0045EC70). Si un CD est inséré dans ce lecteur, cette API nous retourne le volume de ce CD, volume, qui est tout de suite comparé à la chaîne "CDTMS2003" en 0045EC82.
Si le bon CD est inséré, la lettre du lecteur où est inséré le CD est finalement stockée en mémoire pour pouvoir être testée plus loin...
S'il n'y a pas de CD ou si ce n'est pas le bon CD qui est inséré, on recommence en boucle les tests avec incrémentation de al (lettre du lecteur à tester) jusqu'à la lettre z...

Comme on l'a vu, la routine précédente peut être appelée 5 fois.
L'appel à cette routine, en 0045DC77 est celui, qui détermine ou non l'affichage de la boîte de dialogue (qui se fait par le call ebx en 0045DCDA) :



La boucle commençant en 0045DC86, est exécutée à chaque fois que l'on clique sur Réessayer et qu'il n'y a pas ou un mauvais CD d'inséré (test en 0045DCE7).
Si l'on contourne juste cette 1ère vérification, on tombe sur ceci, en lançant une partie :



Il s'agit de la vérification en 005EC431. Vous ne quitterez pas ce message tant que vous n'aurez pas inséré le CD du jeu...
Ainsi, pour cracker définitivement le jeu, il est plus propre de forcer le saut en 0045EC84 (au niveau de la comparaison entre le volume et la chaîne "CDTMS2003"), plutôt que de forcer les 5 sauts suivant les appels à la routine de vérification (en 0045DC77, 0045DCE7, 0045EA06, 0045EADC et 005EC431).


C) Approche "Reversing" :

1. Fixer les adresses "changeantes" :
Le premier problème, ce sont ces adresses changeantes : on n'a jamais les mêmes valeurs à chaque lancement...
Ce que l'on sait, c'est que l'on a des adresses de type 00BAxxxx où xxxx varie à chaque fois...
On lance tms2003.exe via le Symbol Loader, on arrive à l'OEP du programme packé :



Après exécution du call en 00401358, on a eax = 00B90000.
Après exécution du call en 0040141A, on a eax = 00BA0000. Tiens donc...

Et voici, en traçant un peu, le code, qui fixe la nature "aléatoire" des adresses dans la protection :



La variabilité des adresses est déterminée par la valeur changeante / "aléatoire" contenue dans eax. Ell est calculée par la routine située en 004015D6, appelée en 00401447 par le call 004015D6.
Pour supprimer toute variabilité, il suffit de taper r eax 0, après exécution du call 004015D6.
Vous aurez ainsi les mêmes instructions de la protection toujours aux mêmes adresses. Cela nous enlève une sacrée épine du pied...
Comment cette valeur "aléatoire" est-elle calculée ?
Tout simplement à partir des résultats des APIs GetLocalTime et GetSystemTime...



Quittons cette dernière routine en exécutant le ret en 00401649 et continuons de tracer le programme jusqu'à arriver en 004014D5 :



Que fait la routine appelée en 004014D5, appelée par le call 004018EF ?
Elle décrypte justement le début du code "aux adresses changeantes"...
Ici, il s'agit d'un bloc commençant en 00BA0000 (esi) et d'une taille de 7B9D (ecx)...



Une fois le bloc d'instructions décrypté, il ne reste plus qu'à sauter sur ce dernier...



Remarquez que le saut ne se fait pas en 00BA0000 (ebx) , mais en 00BA0000+048B5AC0-048B5930 = 00BA0190 (ebx + esi), calculé par les instructions en 0040155A, 0040155F et 00401565...
Finalement, on arrive alors après exécution du ret précédent, en 00BA0190 (début du code "aux adresses changeantes") :



càd du code truffé de code polymorphe et autres types de code d'obfuscation (interleaved jumps, junk code), censés pourrir la vie aux crackers...
Voici un autre exemple de ce type de code :



Rem : Si vous voulez traçez dans ce code, vous avez intérêt à faire du Step Into (F8) à cause des "call eip+8" présents un peu partout dans ce code...

2. Etude du code polymorphe :

Avant d'aborder le code polymorphe du SPEEnc, voici un petit rappel à ce sujet de Pulsar (Merci à lui) :


Les codes Polymorphes ou l' overlapping:

Il peut arriver que le traçage dans SoftIce soit gêné par des Codes Changeant d'Apparences (CCA):
Softice désassemble une instruction d'offset EIP (disons que le nombre de bytes qu'elle fait est appellé NBI), puis l'instruction positionnée à EIP+NBI....
Il est donc assez facile de faire du CCA.
Imaginons la séquence suivante:

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

En mémoire vous aurez quelque chose comme :

EB01
E8
8B004042

mais E8 est le byte, où commence un opcode du style "call offset", donc ce code, s'il est désassemblé par adresses croissantes donnera :

EB01 jmp @1
E88B004042 call adresse

Lorsque vous tracerez en sautant le jump, vous tombez au milieu de l'opcode du call, et softice re-désassemblera cette instruction ce qui donnera l'impression que le code change d'apparence -> CCA
Vous avez sûrement compris qu'il est donc très facile de faire ce style de code en ajoutant différents types de bytes. Au lieu de E8h on peut ajouter 0CDh,020h qui correspond à une int 20h -> VMMJump qui utilise le DWORD suivant l'opcode... et SoftIce affichera donc un truc du style :

int 20 VXDJump XXXX,XXXX
avec XXXX,XXXX la valeur contenue dans le DWORD suivant l'int 20....

Au cas où vous ne l'auriez pas compris, ce type de codage est particulièrement long, pénible, et fatiguant à tracer (pour ne pas dire….), et demande à être tracé TRES doucement, puisque vous ne voyez pratiquement jamais quelle va être la VRAIE instruction suivante.
Pour avoir déjà rencontré ce type de codage, a peu près TOUS les Call adresse doivent être tracés Step Into (F8).
Une solution pour tracer les CCA est de le faire "à l'ancienne" en regardant les adresses mémoires sur la gauche de l'écran, et dès qu'il y a un saut assez conséquent vous saurez que le programme a passé la main et que le packer a finit son travail.

Un autre inconvénient majeur des CCA est la difficulté de poser des BreakPoints on eXecution, SoftIce n'acceptant pas de poser ses INT3 au milieu d'un code. Les BPM adresse X donnent de bons résultats, mais sont limités à quatre.   Pulsar (tiré d'un texte traitant d'anti-debugging)


Occupons-nous du code polymorphe du SPEEnc, maintenant ;)
Pour pouvoir se débarrasser au mieux de celui-ci, il convient d'étudier en détail sa structure de base :





On repère donc un schéma de base avec une alternance entre 2 types de blocs (le 1er et le 2ème) avec des variations portant sur la nature du registre.

Note : Il ne s'agit pas vraiment du listing tel que l'on obtient après désassemblage... J'ai modifié celui-ci pour le rendre "dynamique" et donc plus compréhensible...
Par exemple, au niveau du 2ème bloc, après l'exécution du MOV EBX,D82407EB en 00BA01C3, on effectue le POP EBX (en 00BA01C3+5=00BA01C8) et non le (JMP 00BA01CD) "contenu" dans l'instruction MOV EBX,D82407EB, jump auquel on arrive par le JMP 00BA01C4...
Il faut faire attention aux call eip+8, qui constitue "l'anti-tracing" du programme, dans la mesure où un Step Over (F10) dans un de ces calls déclenche le lancement du programme... Il faut donc tout tracer en Step Into (F8), ce qui combiné au code polymorphe, devient vite très pénible...

Les instructions "réellement" effectuées au final sont celles indiquées par un tiret <- (ce sont celles que l'auteur a voulu dissimuler, celles présentes avant l'introduction du code polymorphe et finalement sont les instructions sensibles de la protection...).
Le junk code est toutefois conséquent : sur 100 instructions, 90 environ concernent ce dernier... Le code "réel" ne représente donc à peine 10% de cette routine :(
Si l'on raisonne en place occupée par les instructions de ce junk code, on a environ 80 octets occupés par celui-ci sur un total de 120 octets, soit 2/3 environ...
L'importance relative (en poids) de ce junk code, dans le code de la protection est donc importante !!!
Mais la faille de ce code polymorphe vient du fait qu'il est générique ; sa structure de base est aisé à retrouver. Il est donc facile de le détruire :)
Dommage pour les protectionnistes... Peut-être pour une autre fois ?

Le code polymorphe étant disséqué, nous pouvons maintenant le détruire à l'aide de cette 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


Vous n'avez qu'à mettre en _TextStart, l'adresse du début du code / routine "polymorphé" et en _TextEnd, son adresse de fin...
Il ne reste plus qu'à assembler et à charger dans adump.
La routine va alors nous nopper toutes les instructions inutiles pour ne laisser que celles d'utiles et d'intéressantes ;).
Il ne reste plus alors qu'à dumper le code "dépolymorphé"... (/DUMP 00BA0000 7B9D C:\SPEEnc.dat sous SI).

3. Etude du code en général :

Bon voilà, on peux maintenant étudier tranquillement le SPEEnc...
On peut déjà dire, juste à l'aide d'un éditeur hexadécimal, que ce SPEEnc est principalement du code exécutable mêlé à des datas, des commentaires et même des imports !!!










Effectivement, avoir un "cerveau infecté", ça n'aide pas à faire de bonnes protections ^^ (je déconne bien sûr :p).

Pour l'étude du code, j'avais utilisé W32Dasm (encore lui :p)...
Comme je suis un gars pressé, je n'ai ni le temps d'attendre l'analyse d'IDA, ni de commenter son listing pour le rendre plus compréhensible. De plus, le code polymorphe étant enlevé, W32Dasm n'a aucun problème à le désasssembler...
Pour faire correspondre les adresses dans W32Dasm et celles en mémoire (celles fixées comme précédemment), vous n'avez juste qu'à ajouter l'adresse de base (ici 00BA0000h).

4. Localiser facilement l'OEP :

Lorsque l'on est sur l'OEP de tms2003.exe et que l'on regarde du côté de la pile (esp=B7FE3C), on a quelque chose du style :



Ainsi, non seulement, le code polymorphe ne sert à rein (il est générique et peut être facilement supprimé), mais il constitue en plus une faille, dans la mesure où les call eip+8 répétés peuvent constituer des "marqueurs" au niveau de la pile...
Ceci nous permet donc de remonter aux instructions, qui "sautent" vers l'OEP...

Ceci (remonter à ces instructions) est intéressant pour deux raisons :
- Maintenant, il est bien plus facile d'arriver à l'OEP (un bpm 00BA6D87 X suffit).
- Les 2 dernières instructions (FINIT / RET) et celles d'après (ce qui est encore mieux), permettent d'avoir une signature de ce packer. Ceci facilite donc grandement la vie et celle des tracers / unpackers, que vous pourriez coder...



La routine du dessus (en 00BA5FFB) permet de calculer l'OEP où le SPEEnc doit sauter...

ebp+048BD074 vaut 00BA7744, qui comporte la valeur 9B6D10DB.
ebp+048B596E vaut 00BA003E, qui comporte l'OEP "codé" : 9B917A32. (en rouge, ici)
ebp+048B5972 vaut 00BA0042, qui comporte l'Image Base (400000h). (en vert, ici)

L'Image Base est en clair dans le SPEEnc depuis le début...
Image Base, qui est initialisé (au début de la protection), par ce code :

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

Quant à l'OEP, il est juste "codé" et une simple soustraction permet de le retrouver facilement !!!
OEP (VO) = 9B917A32h - 9B6D10DBh = 00246957h

5. Etude des anti-debugging tricks :

A priori, on pourrait dire qu'il n'y a aucun anti-debugs.
En effet, le jeu se lance sans problème avec SoftIce chargé en mémoire. On n'a aucun message d'avertissement, crash, sortie brutale ou autres...
Il n'y a donc pas de détection directe d'un debugger.
C'est dès que l'on met des bp / bpm (hardware breakpoint), que l'on s'aperçoit qu'il y a bel et bien des anti-debugs...

Tout d'abord, un petit log de FrogsIce (Merci +Frog's Print) :



• Hook de l'interruption 3 :



Laserlock détourne donc l'int 03 vers sa propre routine (située en 00BA21BC), chargée d'effacer les Debug Registers (dr0, dr1 et dr2) et par la même occasion les Hardware Breakpoints !!!
De plus, cette routine en 00BA21BC est appelée (en Ring 0) bien plus d'une fois, par l'intermédiaire d'int 03, disséminées un peu partout dans le code...
Et si vous mettez un bpx adresse/API, vous allez directement à cette routine (mais pas quand c'était prévu :p) et vous avez droit à un joli crash en 00BA21FA !!! (crash en ring 0).
Tout simplement parce que l'adresse ds:[ebp+048B5986] en 00BA21FA (1) n'est pas "valide"...
Il en est de même pour l'adresse ds:[ebp+048BD074] en 00BA231E (2), où vous arrivez si vous avez évité le 1er crash en modifiant l'eip.

Et si vous arrivez à retourner à windows après ces crashes, et bien vous aurez droit à chaque fois à un crash de l'explorer, dès vous voudrez aller autre part que sur le Bureau (Mes documents, un dossier quelconque, etc...) et même lorsque vous voudrez redémarrer...
En effet, un crash (ou une sortie) prématuré du SPEEnc laisse l'int 03 hookée (ce n'est donc pas très propre). Ce n'est pas le cas de Starforce . L'exploreur utilise apparemment l'int 03 à ses fins, lors de la navigation dans les dossiers . Si vous réduisez le jeu entre l'hook et l'unhook par le SPEEnc après un breakpoint / boucle infinie, vous aurez des crashes de l'explorer en cas de navigation dans les dossiers.

Maintenant, pourquoi ces crashes en (1) et (2) ?
A cause de la valeur "excentrique de ebp". En exécution normale du SPEEnc, ebp a une valeur bien définie.
Lorsque l'on est en (1), ebp = FC2EA6D0, donc ebp+048B5986 prend 00BA0056 comme valeur et eax = 9B6D10DB.
Lorsque l'on est en (2), ebp = ECCD9F74, donc ebp+048BD074 prend 00BA7744 comme valeur (eax a sa valeur initiale).
Donc, quand l'int 03 est appelée à un autre moment (que ceux prévus par le SPEEnc), comme par exemple lors d'un bp, on a de grandes chances de se retouver avec un accès en lecture / écriture non autorisé, à cause de la valeur différente d'ebp.

La restauration de l'IDT, au niveau de l'int 03, ne se fait que juste avant la redirection vers l'OEP de l'exécutable unpacké...

Note : L'int 03 est détournée par les instructions en 00BA1F7E et 00BA1FCF... (voir Tutorial sur Starforce pour plus de détail sur l'IDT).
Si l'on évite l'hook de l'int 03 (en évitant les instructions en 00BA1F7E et 00BA1FCF), le programme crash... (ceci est dû aux int 03, disséminées un peu partout dans le code).

• Effacement des Drx :



Enfin bon, cette routine n'est pas très efficace, puisque j'arrive à breaker à l'aide de bpm sans problèmes !!!
En effet, lorsque l'on pose un 1er bpm, SoftIce utilise le dr3 et comme celui-ci n'est pas effacé, on peut donc breaker.
Cette routine ne limite donc l'utilisation des hbp à un seul !!!
Et vous n'êtes nullement empêché de poser plusieurs bpm et de breaker sans problèmes dans le code séparant deux int 03 consécutifs...
Nopper les mov drx, eax fait planter le programme, beaucoup plus loin, à cause des vérifications d'intégrité du SPEEnc !!!
Il faut donc procéder autrement pour contourner ceci...

• Interruptions (int 03) disséminées un peu partout dans le code :

Présence d'int 03 en 00BA1BD2, 00BA1C93, 00BA205C, 00BA23CA, 00BA2656, 00BA2847, 00BA29CE, 00BA3C48, 00BA3F82, 00BA43A1, 00BA445E, 00BA4A69, 00BA4EBB, 00BA515D, 00BA55FC, 00BA6073 et 00BA66B2. Elles sont donc assez nombreuses et sont autant de possibilités de d'anti-bpx et d'anti-hbp (par effacement des drx).

Quelques exemples :

















etc...

Vous avez certainement vu ce cmp dword ptr ds:[ebp+048B59C0], 00000000 récurrent et précédant tous (sauf celui en 00BA205C) les int 03...
Et à quoi correspond ds:[ebp+048B59C0] ?
C'est là, qu'est stockée l'ancienne routine ("l' adresse") de l'int 03 hookée...
Or, comme on l'a vu, si l'on essaye seulement d'éviter l'hook de l'int 03, le programme plante... (à cause de tous ces int 03).
On essaye alors ceci :
En 00BA1F26 (stockage de l'ancienne routine de l'int 03), on met edx à 0 (r edx 0), pour qu'il sauvegarde cette valeur.
En 00BA1F7E, on évite l'instruction en faisant pointer eip sur l'instruction d'après (r eip eip+3).
En 00BA1FCF, on évite aussi l'instruction par un "r eip eip+4".
Enfin, on évite l'int 03 en 00BA205C (r eip eip+1).
Et maintenant vous pourrez placer tous les bpx / bpx API que vous voudrez :)
On a résolu d'un même coup l'anti-bpx et l'effacement des Drx...

Mais pourquoi cette présence de cmp / je ?
Parce que contrairement à win 98, XP ne permet pas pas de lire / écrire des valeurs dans l'IDT en Ring 3 (mode normal d'exécution des programmes)...
Ce code assure donc la compatibilité avec ce dernier système.

D'ailleurs, vous aurez remarqué que cette routine de hook de l'int 03 est incluse dans un SEH.
Toute tentative de lecture / écriture dans l'IDT sous XP nous ramène en (39)07A6 (SE Handler), 390000 étant l'Image base du SPEEnc...


• Restauration de l'IDT (au niveau de l'int 03) :

Juste avant le "saut" vers l'OEP de l'exécutable unpacké, l'IDT est restaurée :



• Nombreuses exceptions (SEH) :

Le SPEEnc contient de nombreuses exceptions tout au long de son code :



Ici, on est dans la routine, qui détermine s'il y a assez de mémoire disponible pour le SPEEnc.
Si ce n'est pas le cas, le saut en 00BA32DD n'est pas effectué et l'on a ce message d'erreur :



Je ne vois pas trop l'intérêt de toutes ces exceptions et SEH (présents un peu partout). Comme anti-tracing sous SoftIce, ce n'est pas très subtil...
Il faut être un sacré bourrin pour tracer l'entièreté du SPEEnc :p.

6. Vérifications d'intégrité :

Voici la routine de vérification d'intégrité du code, qui fait que vous n'avez pas trop intérêt à modifier le code, au risque d'un crash :



Cette routine est appelée plusieurs fois par le call 00BA7248, situé en 00BA722C.
Au 3ème appel, la vérification se fait sur le SPEEnc, au niveau du bloc commençant en 00BA0190 (esi) et d'une taille de 7540 (ecx).
Le résultat de l'opération est finalement stocké dans eax.



7. Etude des couches (layers) de cryptage :

• 1ère couche de cryptage :
Nous avons vu qu'elle était effectuée en 004014D5, afin de décrypter le bloc commençant en 00BA0000 (esi) pour une taille de 7B9D (ecx) (voir le chap. fixer les adresses changeantes). Mais en fait, les instructions ne sont valides, que pour le bloc commençant en 00BA0190 et terminant en 00BA04A5, d'où l'application d'une deuxième couche de cryptage...

• 2ème couche de cryptage :
Ensuite, une fois à la fin de notre 1er bloc décrypté, la routine suivante, en 00BA733F (exactement identique, d'ailleurs à la précédente, si ce n'est le code polymorphe, en plus), appelée par le call situé en 00BA0455, est chargée de décrypter le bloc commençant en 00BA04A5 pour une taille de 44F2.



Cette routine est ensuite appelée en 00BA1B32, pour décrypter un bloc commençant en 00BA9A46 pour une taille de 3421B (des datas...).
La vérification proprement dite du CD s'effectue alors...
Le call en 00BA1B32, appelle encore cette routine pour décrypter le code en 00BA4997, d'une taille de 2617 (tout le code exécutable du SPEEnc est ainsi décrypté...), puis pour décrypter un bloc de datas du SPEEnc, commençant en 00BA748C et d'une taille de 244.

Le décrytpage de l'exécutable tms2003.exe a finalement lieu, à l'aide de cette routine également (00BA733F), appelée plusieurs fois par le call en 00BA5ABC, pour procéder par blocs, en commençant à partir de la fin de l'exécutable (les relocations) et en remontant progressivement...
Reste à répondre à la question hautement existentielle : est-il possible de cracker cette version de Laserlock sans avoir le CD original ?
La réponse est oui :).

8. Faille au niveau de la vérification du CD original :

Pour déterminer où se fait la vérification (l'authentification) du CD, il suffit de poser un breakpoint sur l'API GetDriveTypeA (il ne faut pas oublier d'appliquer les dipositions précédentes pour contourner les anti-debugs). On se retrouve alors dans le module NIL32.dll .
En relançant l'exe et en mettant un breakpoint sur CreateFileA, on s'aperçoit que Laserlock crée des fichiers temporaires dans C:\Windows\TEMP, à savoir :
- nomouse
- nomouse.com
- nomouse.sp
- NIL32.dll
- SPEEnc.Dup

Ces fichiers sont ensuite effacés, lorsque le SPEEnc a terminé sa tâche et qu'il donne la main au jeu proprement dit.
Il est donc possible de récupérer NIL32.dll, en stoppant dans le code entre le moment où il est créé et le moment où il est supprimé (par exemple, en breakant sur GetDriveTypeA). Il suffit alors d'aller dans le dossier temporaire et de le copier. Il faut bien sûr éviter l'hook (interception) de l'int 03 par le SPEEnc, parce que l'explorer interfère avec ce hook (utilisation de l'int 03 par l'exploreur dans la navigation des dossiers) et entraîne un crash...
On édite alors le PE de la dll à l'aide de LordPE.
L'OEP est de 0A150 (RVA) pour une Image Base de 0x10000000.
Il suffit donc de mettre un bpm 1000A150 X pour breaker à l'OEP.



On y breake, on relance (F5) pour breaker une 2nde fois.
Le module NIL32.dll est alors unpacké (décrypté) et 1000A150 semble être également l'OEP de la dll unpackée.



Et si ce n'est pas le cas, ça n'a pas beaucoup d'importance, puisque l'on cherche à dumper cette dll, uniquement pour l'étudier en dead listing.
En parcourant le code, on aperçoit des call [00C0xxxx], correspondant aux call [API] détournés par Laserlock.
On a de nouveau des adresses changeantes à ce niveau.

On lance un call-fixer pour résoudre ce problème.
On dumpe alors à l'OEP, à l'aide de LordPE :



On crée une nouvelle table d'import à l'aide d'ImpRec :



Pour cela, on choisit le processus tms2003.exe . On clique sur Pick DLL et l'on sélectionne le module nil32.dll .
Il suffit alors d'entrer le début de l'IAT : 1E000 (RVA), sa taille : 1F4 et de cliquer sur Get Imports.



Il ne faut pas oublier de résoudre l'import correspondant à GetProcAddress pour obtenir la nouvelle table d'import (voir précédemment).

En désassemblant la dll, on s'aperçoit qu'il reste une portion de code, qui est encore cryptée (offsets allant de 0x2E66 à 0x5CED, soit une taille de 0x2E87) :



On peut mettre un bpm 10002E66 X pour breaker et dumper le code décrypté à l'aide LordPE :



On remplace alors le code décrypté dans la .dll dumpée précédemment.

On obtient une dll entièrement reconstruite. En examinant le code désassemblé, que vois-je à mon grande stupéfaction ?
Les mêmes String Data References que la dll de Laserlock v5 : "*LASERLOK* Copyright (c) 1992-1996", "Petros Skalkos **", "v5.00.607 Compile:21/3/2002".

Finalement, les protectionnistes vous ressortent toujours la même protection mais à une "sauce différente".
Ils ont repris la dll de leur ancienne protection (version antérieure) et ont "juste" implémenté le SPEEnc, comme surcouche permettant de "cacher" la dll de la protection... pour ne pas dire, "cacher la misère"...

Comment détourner l'authentification du CD ?
En mettant un bp sur l'API GetDriveTypeA, on atterit au niveau de ce code :






On a le couple classique d'APIs GetLogicalDriveStingsA (chargé de renvoyer les lecteurs présents sur le système) / GetDriveTypeA (chargé d'en déterminer le type).
L'API GetFileAttributesA renvoie l'attribut du fichier LASERLOK.IN (attribut caché). Il suffit donc d'inverser le flag à ce niveau (ou d'y mettre un nop).

On peut également rendre inconditionnel le saut en 10005620 (cela aura le même effet).



Il est donc possible de cracker Laserlock SPEEnc sans posséder le CD original.
Contourner la vérification sur l'attribut du fichier LASERLOK.IN, suffit apparemment à contourner les autres vérifications sur la protection physique,
comme le laisse supposer certaines SDR : "_*NTCD_Last5 ChkSum error*", "_*NTCD_Prev ChkSum error*", "_*NTCD_SIGN not found*",
"_*NTCDFound*", etc...

Quoiqu'il en soit, Laserlock n'atteint pas le niveau de sécurité de certaines protections, à ce niveau.
En effet, la structure physique du CD (secteurs défectueux ou autres) sert généralement à empêcher la copie, mais est aussi utilisée par certaines protections
pour extraire une clé, utilisée pour décrypter l'exécutable du jeu...
Il faut alors posséder le CD original pour pouvoir le cracker, à moins que l'implémentation de l'algorithme de cryptage soit mauvaise (failles, bruteforce, etc...).


D) Perspectives et conclusion :

Généralisation :

Qu'est-ce qui change d'un jeu à l'autre ?
J'ai regardé un autre jeu, protégé par la même version du SPEEnc. Il s'agit de Codename : Outbreak...
Quand ils disent que Laserlock n'est pas générique, ceci me fait bien rire.

C'est exactement le même principe...
Les "variations" portent sur :
- L'image de base du SPEEnc change... On a 007A0000 au lieu de 00BA0000.
- L'OEP est toujours "décodé" par soustraction. Cette fois-ci, on retire 9F9B992D à la place de 9B6D10DB
- Les instructions du SPEEnc "fixé" ont des adresses légèrement différentes : le RET, qui fait sauter vers l'OEP est en 6C06 au lieu du 6D89 de tms2003...
Ceci doit s'expliquer par une introduction "pseudo-aléatoire" de blocs de code polymorphe dans le SPEEnc...
- L'API GetProcAddress est détournée deux fois dans l'IAT (en 50C244 et 50C3A4) au lieu d'une...
- L'IT est plus détruite que dans tms2003, puisque les pointeurs vers le nom des dlls ont également été effacés (Dword 1).
Autant dire rien de franchement fabuleux pour mériter l'appellation "non-générique" !!!

Pour infos (pour ce jeu) :
OEP = 8E3AC (VO)
IT commence en 50C000 (taille : 1D0)
IAT commence en 50C1F4 (taille : 9F0)

Voilà, vous avez assez d'informations pour faire votre propre unpacker ;-)
Créer un packer dans ce cas-ci est plus pédagogique qu'autre chose ; très peu de jeux disposant de la protection Laserlock avec le SPEEnc sont sortis... (Codename : Outbreak, Tennis Masters Series 2003, Post Mortem et Warrior Kings, en France...).

Cette protection est finalement plus facile qu'il n'y paraît ;) ...
Elle contient encore beaucoup d'erreurs de conception et est très loin d'être incrackable, comme l'assurent ses auteurs...

Vous pouvez toujours remercier l'auteur pour cette protection amusante et intéressante ; il a gentillement laissé son email...



Quant à Microïds, je suis assez déçu, qu'il ait fermé boutique et je ne comprends pas trop pourquoi...
Cette boîte française faisait de bons jeux comme Syberia 1 & 2, les Tennis Masters Series, War And Peace : 1796-1815, comparés aux merdes que sortent des studios français comme Davilex ou Cyanide, et qui tiennent eux encore le coup !!!
Ce studio a décidemment essayé toutes les protections disponibles du marché : Laserlock avec Tennis Masters Series 2003, Safedisc avec Syberia 2, Starforce avec War And Peace : 1796-1815, VOB ProtectCD avec Tennis Masters Series (le premier)... En vain...

Voilà c'en est fini des tutoriaux sur Laserlock :p



Enlever le CD-check de Codename : Outbreak :

Une fois Laserlock enlevé de Outbreak.exe, il reste un CD-check à enlever :



Le jeu se lance (sans les vidéos) et puis on accède au menu principal...
Mais les options "Jeu solo" et "Intro" sont grisés et non accessible :



De plus, un click sur "Jeu solo" provoque l'apparition du message d'erreur suivant (ce n'est pas le cas pour "Intro") :



Lol... J'hallucine, même si vous possédez l'original, vous passez en version limitée si vous n'insérez pas le CD !!!
De qui se moque-t-on ?
On va remédier à ça. On désassemble Outbreak.exe, par exemple avec W32Dasm. On cherche les APIs GetDriveTypeA / GetVolumeInformationA et on tombe sur ce code :





Cette routine de vérification du CD est très proche de celle de Tennis Masters Series 2003, excepté l'utilisation supplémentaire de l'API GetLogicalDriveStringsA...
Cette API détermine votre configuration en lecteurs de votre ordinateur, permettant de restreindre les tests par l'API GetDriveTypeA sur des lecteurs existant, et non sur ceux qui n'existent pas (comme x:\, y:\, z:\ ou autres...).
L'API GetDriveTypeA détermine pour un lecteur donné, s'il s'agit d'un lecteur CD.
Si tel est le cas, l'API GetVolumeInformationA récupère le volume du CD inséré (s'il y a).
Enfin, le volume récupéré est comparé à la chaîne "OUTBREAK"...

Cette routine est appelée par un call en 0046369B et un autre en 0048E0D8...
L'appel par le call en 0046369B n'est suivi d'aucun test, contrairement à celui en 0048E0D8 :



Vous aurez compris qu'il suffit de nopper le saut conditionnel en 0048E0DF, pour lancer le jeu (avec les vidéos) et d'y jouer sans le CD !
Et pour les fans de String Data References :


E) Remerciements :

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 ... et tous ceux que j'ai oublié et qui contribuent activement à la scene par leurs tutoriaux, tools et autres...

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 : Merci pour tout ce que tu as fait pour la scene française et ton aussi grande implication. Mes plus grands respects :)
Laserlock : Merci aux développeurs pour les quelques heures d'amusement. Bah oui, ça passe toujours trop vite :p
+Frog's Print & +Spath : Merci pour FrogsIce :-)
GRim@ : Merci pour tes tutoriaux "Beginner" avec lesquels j'ai commencé...
R!SC : Thanks, Master, for your tuts about commercial CD-Rom protections, like Safedisc, SecuROM, VOB ProtectCD, etc... :-)
All members of FFF ;-)

Message à TomRipley : On espère qu'il ne t'ait rien arrivé. Reviens !!!

Final words :

J'espère que vous aurez eu plaisir à lire ce tutorial.

Si l'étude de cette protection vous intéresse, je peux toujours vous uploader les cibles du tutorial. Il suffit pour cela de m'envoyer un mail à :
dWx5c3NlMjAwOV9mckB5YWhvby5mcg==
(base64 encoded)

J'ai essayé de faire une présentation originale "cracking" / "reversing" pour montrer qu'il était possible de cracker certaines protections commerciales avec un minimum de connaissances et sans même connaître l'existence de toutes les différentes techniques d'anti-cracking de la protection...
Un vague aperçu de ces différentes techniques suffit largement comme vous l'aurez aperçu...
Il est néanmoins bien plus intéressant de reverser ces techniques et facilite aussi grandement l'attaque ;)
Mais bon, la frontière entre les deux tend à s'effacer actuellement.
La réalité est toujours bien plus complexe qu'une simple dichotomie...

Concernant Tennis Masters Series 2003, je dirais que c'est l'un des meilleurs (des plus aboutis) jeux de tennis, sortis sur PC, avec les Top Spin...
C'est très loin du niveau médiocre / exécrable des Roland Garros sur PC !!!

"If you like a game, Buy it !"


uLysse, le 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