Crack de Awave v5.0
By CyberBobJr - 20/04/y2k-1



 
Introduction


Hi everybody ! Bein vi, me revoili, de quoi allons-nous parler aujourd'hui ? D'un bête programme ininteressant, mais alors vraiment sans aucun intérêt (enfin tout du moins pour moi), un truc de bidouille audio. Le seul truc qui m'a brancher dans ce logiciel c'est la protection, et à ce propos j'aimerai remercier 3 personnes pour ce tut :
- Xose qui, sans le savoir, m'a eclairé  le chemin.
- Ethan, qui à eu une idée géniale sur FruityLoop (allez choper le tut sur mon site).
- Razzia, grâce à son tut "crippled programs" j'ai pu mener à bien ma "mission" ;)

Tu peux trouver Awave sur le CD Pro PCTeam N° 44, rubrique sharewares ... ou http://hem.passagen.se/fmj/fmjsoft.html

Le proggy n'a même pas besoin d'être installé, tu peux le lancer en direct.

Quand tu l'execute la première fois, tu as le classique nag-screen de démarrage à 3 balles :(
Tu as également quelques fonctions désactivées, mais apparemment pas de limitation dans le temps.
 



 
Etape Une : Analyse dead-listing


Bein là si tu y arrives, tu es très très fort !!! la version distribuée sur le CD PCteam est crypted, alors IDA te donneras que dalle, et Wdasm encore moins !!!

Solution de secours : ProcDump v1.4 ... pô de bol, le code de compression n'est pas reconnu :(

Bein, quand c'est comme ca, tu es plutôt mal barré ... il te reste quoi ?

Ton cerveau banane !!!!

Voilà mon raisonnement :
" Bon, ok, ce programme fait iech, tu peux pas le patcher sur disque, tu vas pas faire un patcher mémoire pour un programme à 2 balles, cracke le déja en mémoire, et pis après on trouvera une solution adéquate"... Alors avec mes petites mains, j'ai lançé ProcDump v1.4 pour dumper le process sur le disque. J'expliqe la procédure pour les durs de la feuilles qui n'ont pas encore utilisé ProcDump (shame on U !) :

- Lance ton programme Awave
- Lance ProcDump
- Clique avec le bouton droit sur le process Awave (dans ProcDump, hein, on s'était bien compris ? ;)
- Clique sur Dump Full
- Donne un nom bidon, genre awave_dump.exe
- Desassemble le tout avec IDA
- Profite aussi pour desassembler le code d'Awave compresser, ca va être utile

Et là, on peut déja avoir une base pour bosser correctement, l'objectif étant de patcher en mémoire sous Sice le prg.

A partir de ce moment, je te conseille de lire le tut de Ethan sur FruityLoop, au risque de ne pas tout comprendre ...
 



 
Etape deux : Font chier ces compacteurs d'exe


Lorsque tu desassemble le code d'Awave avec IDA, tu te retrouve içi :

¦CODE:004403C6 start           proc near
¦CODE:004403C6                 jnz     short $+2
¦CODE:004403C8                 jmp     loc_0_4DF000
¦CODE:004403C8 start           endp

Alors pourquoi içi et pas ailleurs ??? pourquoi pas en 00401000 comme la plupart des EntryPoint dans les prog Win 32 ? Et bien, tout simplement, toujours avec ProcDump, lance un PE Editor, et selectionne ton programme Awave.exe, ProcDump te donne comme Entry Point 000403C6 avec comme Image Base 00400000, soit un entry point égal à 000403C6+00400000 = 004403C6.

Mais bon, continuons :
Un jmp en loc_0_04DF000 t'amène içi :

.data:004DF000 loc_0_4DF000:                           ; CODE XREF: start+2j
.data:004DF000                 pusha
.data:004DF001                 call    $+5
.data:004DF006                 pop     ebp
.data:004DF007                 sub     ebp, offset unk_0_4398AE
.data:004DF00D                 mov     eax, offset unk_0_4398A8
.data:004DF012                 add     eax, ebp
.data:004DF014                 sub     eax, dword ptr ss:unk_0_439D18[ebp]
.data:004DF01A                 mov     dword ptr ss:aI2v[ebp], eax
.data:004DF020                 cmp     byte ptr ss:a9josNlq[ebp], 0
.data:004DF027                 jnz     short loc_0_4DF03E
.data:004DF029                 inc     byte ptr ss:a9josNlq[ebp]
.data:004DF02F                 call    sub_0_4DF051
.data:004DF034                 call    sub_0_4DF2AC
.data:004DF039                 call    sub_0_4DF348
.data:004DF03E
.data:004DF03E loc_0_4DF03E:                           ; CODE XREF: .data:004DF027j
.data:004DF03E                 mov     eax, dword ptr ss:(a9josNlq+2)[ebp]
.data:004DF044                 add     eax, dword ptr ss:aI2v[ebp]
.data:004DF04A                 mov     [esp+1Ch], eax
.data:004DF04E                 popa
.data:004DF04F                 jmp     eax

Voilà une chose bizarre, que Ethan nous avait déja fai remarqué dans FruityLoop, un jmp eax louche ... on va vite être fixé, lance le loader de Soft-Ice, puis lance Awave, problème, le loader ne te rend pas la main, pô grave, place un BPX dialogboxparamA, de tel sorte que Sice te rende la main lorsque le programme affichera son nag-screen, une fois que tu seras sous Sice, fait un F12 pour sortir de l'API dialogboxparamA, tu te trouveras dans le code de Awave, fais maintenant un "u 004DF04F", Sice t'affichera le code que tu vois plus haut, c kewl, place maintenant un "bpm 004df04f x" et relance ton programme (n'oublie pas si tu veux pas être embeté de supprimer le breakpoint sur dialogboxparamA).
Logiquement, après avoir relancé le loader tu te trouvera à l'adresse 004DF04F, et eax contiendra la valeur 00401000, nous savons maintenant ou se situe notre point d'entrée dans le programme. Reste maintenant à trouver les bytes à patcher pour faire croire à Awave que nous sommes enregistré. Maintenant nous allons voir des choses plus "classiques" :
 



 
Etape trois : Et crie t'il : "Sus à l'ennemi !"


IDA nous est hyper utile à ce niveau, Wdasm ne comprends rien à ce qui se passe, je suis sur qu'en bidouillant un peu nous aurions pu arranger ca, mais bon, utilisons ce merveilleux outil qu'est IDA, tout d'abord n'oublie pas que cette fois, nous desassemblons l'exe dumpé par ProcDump.
Lorsque tu as lançé Awave et que tu avais posé un bpx sur DialogboxparamA tu as surement noté l'adresse de l'appel, non ? si c'est le cas, tu te trouvera içi :

CODE:00405A7A loc_0_405A7A:                           ; CODE XREF: sub_0_4059C8+18j
CODE:00405A7A                 push    0
CODE:00405A7C                 push    offset loc_0_405698
CODE:00405A81                 push    ebx
CODE:00405A82                 push    22h
CODE:00405A84                 mov     eax, ds:dword_0_4B2B28
CODE:00405A89                 push    eax
CODE:00405A8A                call    sub_0_48B6AE <- Appel de DialogBoxparamA
CODE:00405A8F
CODE:00405A8F loc_0_405A8F:                           ; CODE XREF: sub_0_4059C8+9Fj
CODE:00405A8F                                         ; sub_0_4059C8+B0j
CODE:00405A8F                 pop     edi
CODE:00405A90                 pop     esi
CODE:00405A91                 pop     ebx
CODE:00405A92                 mov     esp, ebp
CODE:00405A94                 pop     ebp
CODE:00405A95                 retn    4
CODE:00405A95 sub_0_4059C8    endp

Cette routine est appelée en sub_0_4059C8+18 zyva pour voir :

CODE:004059D1                 mov     ebx, [ebp+arg_0]
CODE:004059D4                 push    offset unk_0_48DAA7
CODE:004059D9                call    sub_0_409258 <- Call bizarre
CODE:004059DE                 test    al, al <- Test encore plus bizarre
CODE:004059E0                 jz      loc_0_405A7A <- Le saut provient d'içi
CODE:004059E6                 mov     [ebp+var_50], 28h
CODE:004059ED                 xor     eax, eax

Donc première conclusion, l'affichage de la boite de dialogue provient de du call en sub_0_409258, rentrons à l'intérieur de cette routine (double clic sur l'appel à la fonction), nous arrivons içi :

CODE:00409258                 push    ebp
CODE:00409259                 mov     ebp, esp
CODE:0040925B                 push    ebx
CODE:0040925C                 push    esi
.
. Code blabla ...
.
CODE:00409297                 push    esi
CODE:00409298                call    sub_0_401304 (içi sub_0_401304 = 00401305)
CODE:0040929D                 test    eax, eax <- eax=0 ?
CODE:0040929F                 setz    al <- Position al à 01 si eax=0
CODE:004092A2                 and     eax, 1 <- et logique entre eax et 01, donc eax=01 si eax=00 à la sortie du call
CODE:004092A5
CODE:004092A5 loc_0_4092A5:
CODE:004092A5                 pop     edi
CODE:004092A6                 pop     esi
CODE:004092A7                 pop     ebx
CODE:004092A8                 pop     ebp
CODE:004092A9                 retn    4
CODE:004092A9 sub_0_409258    endp

En fait, al est testé à la sortie de cette fonction, or al provient du code en 004092a2, qui lui-même prend la valeur dans le call sub_0_401304.
On va faire l'essai sous Sice de placer un "bpm 00401305 x", histoire de voir si le retour de cette fonction est important ...

Effectivement, lors du démarrage du programme, tu as du breaker plusieurs fois sur cette fonction, par F12 tu es sorti de la fonction, et à chaque fois eax est différent de 0 (genre eax=888 ou autres), et si tu forces EAX à 0, tu pourras remarquer que ton programme est enregistré. J'en déduis donc que la fonction commençant en 00401305 détermine si nous sommes enregistrés ou non, il suffit donc de patcher dans cette fonction, plus exactement, je serais de patcher à cet endroit :

CODE:004013E6                 mov     eax, ebx <- IçI, le programme fixe eax avec la valeur en ebx
                                                  et ebx est le résultat d'enregistrement
CODE:004013E8
CODE:004013E8 loc_0_4013E8:
CODE:004013E8                 pop     esi
CODE:004013E9                 pop     ebx
CODE:004013EA                 mov     esp, ebp
CODE:004013EC                 pop     ebp
CODE:004013ED                 retn    14h

Le code en 004013E6 est toujours executé, il nous est façile de patcher cet endroit et de remplacer

    mov eax, ebx
par
  xor eax,eax

de cette façon eax sera toujours égal à 0 ...

Patche en mémoire sous Sice, tape "A 004013E6" et tape le code suivant : "XOR EAX,EAX", lançe ton programme et voilà !!! le programme fonctionn à merveille, met toi sur about, pas de problème, met toi sur les fonctions désactivées, pas de problèmes, va sur le menu "options -> program setup" et boum ! le programme se termine net, sans messages d'erreurs, sans rien ... alors après analyse, j'en ai déduis qu'apparemment le programme aurait un bogue :
En effet, si tu n'es pas enregistré le setup fonctionne à merveille, sinon, si tu es enregistré, ca kill le process, pourquoi ??? je ne sais pas, la seule chose que j'ai constaté c'est la différence du code lors du retour des précedentes fonctions, on avait quelque chose comme ca (cf plus haut) :

CODE:0040929D                 test    eax, eax <- eax=0 ?
CODE:0040929F                 setnz    al <- Position al à 01 si eax=0
CODE:004092A2                 and     eax, 1 <- et logique entre eax et 01, donc eax=01 si eax=00 à la sortie du call

or là, pour le "setup program" on a quelque chose comme ca :

CODE:0040929D                 test    eax, eax <- eax=0 ?
CODE:0040929F                 setz    al <- Position al à 01 si eax=01
CODE:004092A2                 and     eax, 1 <- et logique entre eax et 01, donc eax=01 si eax=01 à la sortie du call

Ce qui est assez étrange, si le programme est enregistré, il se considère comme non enregistré !!! Je pense que c'est un bogue, mais si quelqu'un à une idée ...

Enfin bref, nous allons modifier ce setnz en setz, nous aurons donc 2 patchs à appliquer, je les résumes :

un patche en 004013E6 de ce type :

8BC3    MOV EAX, EBX
en
33C0     XOR EAX, EAX

et un patche en 0040929F de ce type :

0F94C0    SETZ AL
en
0F95C0    SETNZ AL

Problème : comment patcher le programme sachant que le fichier est compressé/crypté ??? Le truc serait de patcher le programme en mémoire juste avant le fameux saut "JMP EAX" ...
 



 
Etape quatre : La fin est proche, courage


Arrivé à ce niveau, il est nécessaire de savoir comment fonctionne (vaguement ;) le format PE ...
Il faut savoir que ton programme est divisé en sections, et chaque section possède une entrée dans le PE Header, ca veut dire que notre code de décryptage possède une section dans le PE Header, ProcDump nous permet de savoir les détails de cette section :
 
 

 
Virtual size
Virtual Offset
Raw size
Raw Offset
.data  00002000 000DF000 00001400 00050A00

La taille virtuelle de notre code est 2000, ce qui veut dire qu'en RAM, la mémoire allouée pour notre code est de taille 0x2000 octets, ce qui toujours un multiple de la page (en particulier içi 0x1000), en effet, la mémoire allouée doit toujours être multiple de l'offset virtuel de la section CODE.
L'offset virtuel de notre code est de 000DF000, additionné à l'image de base (00400000), ca nous donne une adresse virtuelle de 004DF000 (et comme par hasard, cette adresse nous mène droit vers l'EIP du programme).
La taille sur disque (Raw Size) est de 0x1400, ce qui veut dire que le code n'utilise que 0x1400 octets dans le fichier .exe.
L'offset sur disque (Raw Offset) est de 00050A00, autrement dit le code s'étale sur le disque de l'offset 0050A00 jusqu'a (0050A00+1400)=0051E00.

Si la taille doit toujours être un multiple, ca veut dire que le système lors de la compilation d'un programme doit "boucher" les trous pour obtenir la taille exigée, ca doit faire de la place libre ca non ??? limite qu'on pourrait exploiter non ??? vous me voyez venir ? ;)

Je te conseille de regarder après les informations de versions, tu trouveras tout plein de "00" à remplir ;) de plus fais bien gaffe avec ce genre de technique, il faut prendre en considération deux points très importants :
 - Toujours bien vérifier que le code que tu va écrire fait toujours parti de la section dans laquelle tu veux rajouter ton code
 - Cherche des endroits avec pleins de zéros, je sais c'est aléatoire, mais j'ai constaté que l'écrasement de certaines données, même si elles sont totalement inutiles et situées à des endroits "insolites" peuvent être utilisées dans un programme.

Apparemment l'adresse virtuelle 004DFBB7 me parait être un endroit approprié, apparemment nous sommes arrivés à la fin du code. Il ne nous reste plus qu'a taper notre code tout beau sous Hiew, maintenant vient la partie du calcul de l'offset sur le disque :

Offset sur le disque = (00DFBB7 - offset virtuel) +  Raw Offset
soit (00DFBB7-00DF000) + 00050A00 = 000515B7

Nous plaçerons donc Hiew en 000515B7 et nous allons écrire le code suivant :

mov     [esp+1Ch], eax
popa <- Pourquoi ce code ??? tout simplement parce que nous avons besoin de plus de 2 octets en 004DF04F pour effectuer notre saut dans cette partie du code ...donc nous allons écraser le code avant 004DF04F pour le placer içi, ce qui revient au même.
push eax             ; sauvegarde du registre eax
mov edi, 004013E6    ; on place l'adresse des premiers patches en edi
mov eax, C033        ; eax = C033
stosw                ; [edi] = eax
mov edi, 004092A0    ; edi = adresse du 2eme patche
mov ax,95            ; eax = 95
stosb                ; [edi] = ax
pop eax
jmp eax

Et voilà, occupons nous maintenant du point d'entrée içi :

.data:004DF04A                 mov     [esp+1Ch], eax
.data:004DF04E                 popa
.data:004DF04F                 jmp     eax

Et remplaçons ce code par celui-çi :

jmp 004DFBB7

L'adresse du jmp eax se trouve en (00DF04F-00DF000)+50A00 soit 00050A4F, or le jmp 004DFBB7 occupe plus de 2 octets, nous allons donc écraser le code en 004DF04A (le code présent n'a pas d'importance puisque nous l'avons ajouté dans notre routine perso), l'adresse 004DF04A sous Hiew correspond à 00050A4A, rajoutons donc jmp 004DFBB7.
 

et voilà, relançer votre programme, et normalement vous devriez avoir un programme enregistré qui se patche lui-même !!! ;)

Voilà une technique qui peut être intéressante en cas d'absolue nécessité, et oui, ProcDump ne peut quelque fois pas tout décompacter, et il peut être utile de patcher en mémoire, en cas de vérif' checksum par exemple ...
 



 
The End



 

C'est fini, j'espère avoir été clair, pour ceux qui en désire plus, je leur conseille d'aller sur mon site :
 


http://technopole.le-village.com/cyberbobjr


 


Tu y trouveras de nombreux liens sur d'autres sites de cracking (all in french ;), avec les forums de +Frog's Print (notre maître à tous) et celui de la Main Rouge, ou de nombreux 'tits gars se réjouiront de t'aider. Pour ma part malheureusement, je n'aurais pas le temps de te répondre, faute de temps, je préfère te prévenir afin que tu ne te vexe pas si je ne répond pas ;)

Et maintenant les GreetZ :

Tout le monde ... sauf les cons ...
ils se reconnaitront ;)
Mais spécial dédicace quand même à :
+ORC
+Fravia
+Frog's Print
+Spath
All Ozer +HCU Students
Artex
Psyché
Pass Partout
Xose
Acid Flag
Nody
Elraizer
The_Iceman
MacroBio
Acid Nitric
Alsindor
Votan
BlueWin
Lïou-jungle
Enkil
Simon tête creuse
sfm
Ethan
[BamA]
Jordan_Jr
Tous les membres de fusion
[Jacques Chirac/CC]
[Jean Gabin/CC]
Tous les membres de [CC]
Cyberghost
TaZ
Jozio
The Ben
Koba Yashi/Rico
Razzia
Anonymous/MisterX
MovAx1st
Le_Magicien
La_crapule
Hug's 2000
Et tous mes potes que je n'ai pas cités (oubli involontaire) et tous ceux avec qui j'ai passé des semaines et des semaines à apprendre l'art du cracking, tous mes potes du Forum de +FP et de la Main Rouge, merci à vous tous ...

RDV A dieu.