ASPROTECT 1.23 UNPACKING

 

 

INTRODUCTION :

 

Bonjour à tous !

Nous allons aujourd’hui nous essayer au manual unpacking d’Asprotect 1.23.

Pour commencer nous allons nous attaquer au notepad protégé par Asprotect et trouver une méthode très simple pour l’unpacker. Nous étudierons ensuite cette protection dans un cas plus concret en unpackant le logiciel Advanced File Organizer 2.3 disponible sur le site http://www.softprime.com/index.htm .

Ce tutorial n’a bien entendu aucune prétention, la partie technique du packer ne sera pas abordée en profondeur.

Il a simplement pour but de vous familiariser avec Asprotect. D’autres tutoriaux très techniques traînent déjà sur la toile et je ne suis pas là pour faire du copier coller ! J

Enfin j’ai choisi d’employer Olly plutôt que Softice (à contre cœur) afin qu’un maximum de personnes puissent suivre ce tutorial.

 

Logiciels employés :

 

 

C’est bon vous avez tout ce qu’il faut? Alors nous pouvons commencer !

 

PREMIERE PARTIE : NOTEPAD UNPACKING 

 

C’est parti !

On ouvre le Notepad avec OllyDbg, on va dans Plugins -> IsDebugPresent -> Option.

Une boîte de dialogue s’ouvre, vous cochez AutoHide , cliquez sur Save et fermez la fenetre.

Ce plugin a pour effet de cacher le debugger lorsque l’api IsDebuggerPresent est appelée. De cette manière la fonction renverra toujours False, ce qui nous arrangera bien lorsque le loader fera appel à cette api pour savoir si un debugger est chargé. J

 

Ce qui est assez marrant dans le loader d’Asprotect, c’est qu’il génère des exceptions sensées nous déstabiliser mais il se trouve que l’on va justement s’en servir pour arriver tranquillement à l’Entry Point.

Alors maintenant nous allons arriver à l’entry point du NotePad très facilement à coups de Shift + F9 !

 

Il faut faire précisément 27 Shift+F9 pour arriver jusqu’au nagscreen du Notepad précisant qu’il a été packé avec une version non enregistrée d’Asprotect (sans blague ! il veut des sous en plus !).

Lorsque le nag apparaît on clique sur OK et le Notepad se lance.

 

Note au passage :

Si une boîte de dialogue vous signale la présence d’un debugger, vérifiez bien que le plugin IsDebugPresent est bien activé. Si c’est le cas, supprimez le fichier NotePad.udd présent dans le repertoire d’Olly et réessayez.

 

« Mais euh si le Notepad se lance, c’est qu’on a dépassé l’entry point ! » me direz vous !

Et oui ! C’est pour cela que nous n’allons effectuer que 26 Shift+F9 afin de breaker dans le loader un peu avant l’OEP original du notepad !

 

00AD3033   3100             XOR DWORD PTR DS:[EAX],EAX ; On breake ici

00AD3035   64:8F05 00000000 POP DWORD PTR FS:[0]

00AD303C   58               POP EAX

00AD303D   833D 847EAD00 00 CMP DWORD PTR DS:[AD7E84],0

00AD3044   74 14            JE SHORT 00AD305A

00AD3046   6A 0C            PUSH 0C

00AD3048   B9 847EAD00      MOV ECX,0AD7E84

00AD304D   8D45 F8          LEA EAX,DWORD PTR SS:[EBP-8]

00AD3050   BA 04000000      MOV EDX,4

00AD3055   E8 6EDAFFFF      CALL 00AD0AC8

00AD305A   68 30200000      PUSH 2030

00AD305F   A1 A463AD00      MOV EAX,DWORD PTR DS:[AD63A4]

00AD3064   50               PUSH EAX

00AD3065   A1 A063AD00      MOV EAX,DWORD PTR DS:[AD63A0]

00AD306A   50               PUSH EAX

00AD306B   6A 00            PUSH 0

00AD306D   E8 5E21FFFF      CALL 00AC51D0                            ; JMP to USER32.MessageBoxA

00AD3072   FF75 FC          PUSH DWORD PTR SS:[EBP-4]

00AD3075   FF75 F8          PUSH DWORD PTR SS:[EBP-8]

00AD3078   8B45 F4          MOV EAX,DWORD PTR SS:[EBP-C]

00AD307B   8338 00          CMP DWORD PTR DS:[EAX],0

00AD307E   74 02            JE SHORT 00AD3082

00AD3080   FF30             PUSH DWORD PTR DS:[EAX]

00AD3082   FF75 F0          PUSH DWORD PTR SS:[EBP-10]

00AD3085   FF75 EC          PUSH DWORD PTR SS:[EBP-14]

00AD3088   C3               RETN

 

 

 

On breake en AD3033 (les adresses peuvent varier). On pose maintenant un BP sur la ligne juste en dessous en AD3035.

Pour cela, on clique sur la ligne et on appuie sur F2.

Maintenant que notre BP est posé, on peut appuyer sur Shift+F9 pour se dégager de l’exception et stopper directement sur la ligne où l’on a posé notre BP.

Le call en AD306D affiche le nagscreen d’Asprotect. On continue à tracer jusqu’au ret (F8).

Une fois que le ret est passé, nous allons utiliser la commande magique de la Command Line qu’est TC (Trace Condition) !

Pour cela sous Olly faites Plugins -> Command line -> Command line.

Une boîte de dialogue s’ouvre alors, tapez : TC EIP>1000000 && EIP<2000000

Appuyez sur Entrée et vous pouvez distinguer dans la fenêtre d’Olly en bas à droite « Tracing ».

 

Explication sur la commande TC :

TC EIP>1000000 && EIP<2000000 veut dire que l’on veut tracer le programme de manière automatique et breaker quand l’eip courant sera supérieur à 1000000 ET inférieur à 2000000. J’avoue que là on a un peu triché car on sait que l’oep du Notepad est 1006420… Bon on a compris pourquoi EIP>1000000 mais pourquoi EIP<2000000 ? Parce que si on oublie cette condition, la commande TC nous fera breaker dans les dlls windows et nous on veut pas !

D’une manière générale, il faudra faire TC EIP<900000 car la plupart des OEP sont du style 4XXXXX mais nous aurons l’occasion de voir ça dans la seconde partie de ce tutorial !

 

Suite a cette commande, le debugger breake ici :

 

01006420   . 55             PUSH EBP

 

C’est notre Entry Point ! Nous allons maintenant pouvoir effectuer notre dump !

On lance LordPE, on recherche notepad.exe dans les processus actifs et on fait clic droit puis dump full.

Il faut maintenant modifier l’Entry Point. Donc sous LordPE, on clique sur PE Editor et on ouvre le dump que l’on vient de faire et dans la case Entry Point vous changez 1000 en 6420, vous fermez et on en a fini avec LordPE.

 

Il va maintenant falloir reconstruire l’IAT ! Cette tache autrefois ardue (il fallait coder un call fixer) est devenue simplissime grâce à ImpREC (Merci MackT !), alors si on utilise en plus le plugin pour Asprotect…

Allons-y !

On lance ImpRec 1.6 et on choisit notepad.exe comme processus. On met 6420 à la place de 1000 comme OEP et on clique sur IAT autosearch puis Get Imports. Certains imports n’ont malheureusement pas été résolus alors on clique sur Show Invalid pour les afficher. On fait clic droit sur les imports en question puis Trace level 1 et la plupart des imports sont résolus sauf 2 qui résistent encore ! C’est là qu’intervient le plugin asprotect d’ImpRec, on clique a nouveau sur Show Invalid et on fait un clic droit sur l’import non résolu puis selectionnez Plugin tracers -> AsProtect 1.22. Les 2 fonctions étaient en fait GetModuleHandle et GetProcAddress… A priori tous les imports ont été résolus !

On clique sur Fix Dump et on choisit notre dump de tout à l’heure. On ferme tout, on n’oublie pas de terminer le processus du notepad gelé en mémoire et on lance notre dump pour voir s’il est fonctionnel.

 

Ca marche !!!!

 

C’était pas si compliqué ! Enfin heureusement qu’on avait les bons tools !

Ainsi s’achève la première partie de ce tutorial, nous allons maintenant nous attaquer à un cas plus concret pour parfaire nos connaissances sur Asprotect.

 

 

SECONDE PARTIE : ADVANCED FILE ORGANIZER 2.3

 

Cette fois ci nous allons étudier Asprotect en situation réelle car il faut avouer qu’avec le Notepad on a un peu triché!

En effet nous connaissions à l’avance l’Entry Point et si stolen bytes il y a avait eu ça n’aurait pas été bien dur non plus.

De plus nous allons dans cette partie nous passer du plugin IsDebugPresent d’Olly ainsi que du plugin Asprotect 1.22 d’ImpRec…

 

 Logiciels employés :

 

 

Allez on se lance !

On ouvre aforg.exe avec Olly et on se tape 26 Shift+F9 pour arriver a l’endroit qui suit :

 

00DB39EC   3100             XOR DWORD PTR DS:[EAX],EAX ;On breake ici

00DB39EE   64:8F05 00000000 POP DWORD PTR FS:[0]

 

Remarque :

Bien que je n’utilise plus le plugin IsDebugPresent, le loader ne semble pas détecter la présence d’Olly…

Cela dépend sûrement des diverses options qu’offre Asprotect. On ne va pas s’en plaindre !

 

Une fois qu’on a breaké en DB39EC, on pose un BP sur la ligne d’en dessous en DB39EE (F2) et on se refait un dernier Shift+F9. Une fois qu’on a breaké en DB39EE, on trace F8 jusqu’au ret et on dégaîne la Command line et on tape TC EIP<900000 et on presse Entrée.

On arrive ici :

 

0048D017   ? FF15 34634C00  CALL DWORD PTR DS:[4C6334]

 

C’est notre Entry Point !!! Euh pas vraiment en fait ! Le loader a subtilisé les premières instructions dans le but de faire planter notre dump. On les appelle souvent les stolen bytes ! Notre véritable OEP se trouve donc un peu plus haut, regardons un peu au dessus d’ailleurs :

 

0048CFF0  \. C3             RETN

0048CFF1     00             DB 00

0048CFF2     00             DB 00

0048CFF3     00             DB 00

0048CFF4     00             DB 00

0048CFF5     00             DB 00

0048CFF6     00             DB 00

0048CFF7     00             DB 00

0048CFF8     00             DB 00

0048CFF9     00             DB 00

0048CFFA     00             DB 00

0048CFFB     00             DB 00

0048CFFC     00             DB 00

0048CFFD     00             DB 00

0048CFFE     00             DB 00

0048CFFF     00             DB 00

0048D000     00             DB 00

0048D001     00             DB 00

0048D002     00             DB 00

0048D003     00             DB 00

0048D004     00             DB 00

0048D005     00             DB 00

0048D006     00             DB 00

0048D007     00             DB 00

0048D008     00             DB 00

0048D009     00             DB 00

0048D00A     00             DB 00

0048D00B     00             DB 00

0048D00C     00             DB 00

0048D00D     00             DB 00

0048D00E     00             DB 00

0048D00F     00             DB 00

0048D010     00             DB 00

0048D011     00             DB 00

0048D012     00             DB 00

0048D013     00             DB 00

0048D014     00             DB 00

0048D015     00             DB 00

 

Humm quelque chose me dit que notre OEP serait plutôt en 48CFF1, le loader aurait donc remplacé les instructions originales par une suite d’octets nuls. Mais alors comment récupérer ces maudits stolen bytes ? Eh bien il y a plusieurs manières car en fait bien souvent le loader les exécute juste avant de passer la main au programme et si ce n’est pas le cas ils sont émulés !

Pas de chance pour nous car cette fois ils sont émulés ! Avant d’expliquer comment j’ai retrouvé les bytes manquants, je vais expliquer de quelle façon on peut les récupérer d’une manière générale.

 

Allez dans le menu View puis Run Trace pour obtenir le listing des instructions tracées avant de breaker. Une fenêtre s’ouvre, descendez tout en bas car c’est là que ça peut être intéressant ! En effet c’est la plupart du temps le meilleur moyen de mettre la main sur nos stolen bytes.

 

En bas du listing vous pouvez trouver ceci :

 

Stolen_Bytes

            Stolen_Bytes

            Stolen_Bytes

            ….

            ….

            ….

            push adresse_oep

            Ret

 

S’il n’y a pas de stolen bytes, vous trouverez alors un simple ret ou bien un jmp oep.

Mais la méthode que j’utilise consiste plutôt à les deviner soit en identifiant le compilateur utilisé pour générer le code soit en essayant d’ajuster convenablement ebp et esp et les valeurs des registres de travail.

 

Avant de nous occuper des stolen bytes, nous allons d’abord dumper notre programme. Lancez LordPE, choisissez aforg.exe dans la liste des processus, faites un clic droit dessus et sélectionnez Dump full. Toujours avec LordPE, cliquez sur PE Editor et choisissez votre dump. Entry Point aura comme valeur 1000, il faudra entrer 8CFF1 à la place (notre nouvel Entry Point), cliquez sur Save puis sur OK. Vous pouvez fermer LordPE, nous n’en aurons plus besoin.

 

Reconstruction de l’IAT :

 

Allez on se lance ! On ouvre ImpRec  et on choisit aforg.exe. On rentre notre OEP soit 8CFF1, on clique sur IAT Auto Search puis Get Imports. De nombreux imports n’ont pas été résolus alors on clique sur Show Invalid et on fait clic droit, Trace level1. Cela a pour effet d’en résoudre une bonne partie. 7 imports n’ont pas été résolus en tout, comment cela se fait-il ? Eh bien Asprotect émule certaines fonctions, il faut donc parvenir à les identifier nous mêmes ! (Pour les fainéants, utilisez le plugin d’Asprotect et ça fera l’affaire).

 

Premier import non résolu :

 

0          000C6270       ?          0000    00DB1CD8

 

Faites un clic droit dessus et sélectionnez Disassemble/HexView et voilà ce que ImpRec nous donne :

 

00DB1CD8    push 0

00DB1CDA    call 00DA51B8    // = kernel32.dll/013B/GetModuleHandleA

00DB1CDF    push dword ptr [DB7E14]    // DWORD value: 08930005

00DB1CE5    pop eax

00DB1CE6    mov eax,[DB7E24]    // DWORD value: 00133010

00DB1CEC    retn

 

Un petit D 133010 sous SoftIce nous donne (ah mince c’est pas softice désolé ! J) :

"C:\Program Files\Advanced File Organizer\aforg.exe”

 

Cette Api est en fait GetCommandLineA ! On a de la chance cette fois ci car elle est plutôt évidente à deviner. Pour la résoudre vous double cliquez sur cette ligne et vous sélectionnez GetCommandLineA dans la liste.

 

Deuxième import :

 

0          000C6304       ?          0000    00DB1CB8

 

00DB1CC0    mov eax,[DB7E20]    // DWORD value: 00000414

00DB1CC5    retn

 

Bon ce coup ci on aura du mal à deviner… Alors on met les mains dans le loader. J

On relance le programme et Memory BreakPoint on Write sur l’adresse DB7E20 et on finira par breaker ici :

 

00DB1ADB    8943 F6         MOV DWORD PTR DS:[EBX-A],EAX

 

On relance encore le programme pour tracer un peu dans la partie du code qui est executée entre la première et la seconde exception et on voit ici quelque chose d’interessant :

 

00DB1A9E    68 AC1ADB00     PUSH 0DB1AAC

00DB1AA3    8B05 7A51DA00   MOV EAX,DWORD PTR DS:[DA517A]

00DB1AA9  - FF20            JMP DWORD PTR DS:[EAX]                   ; kernel32.GetCurrentProcessId

 

A la suite de cet appel, un jmp puis 2 ret sont effectués pour nous ramener en DB1ADB et stocker eax en DB7E20.

Nous avons donc affaire à GetCurrentProcessId…

On double clique sur le pointeur non résolu sous ImpRec et on choisit GetCurrentProcessId.

 

Troisième import :

 

0          000C6334       ?          0000    00DB1C8C

 

(Je ne décris plus la marche à suivre sinon ça va devenir lourd ! J)

Cela nous donne :

 

00DB1C8C    push dword ptr [DB7E14]    // DWORD value: 08930005

00DB1C92    pop eax

00DB1C93    retn

 

Ici nous pouvons clairement voir qu’on met en eax le contenu de l’adresse DB7E14. Il ne nous reste plus qu’à relancer le programme et poser un Break Point Memory on write sur cette adresse. On atterrit ici après 2 Shift + F9 (encore) :

 

00DB1ADB    8943 F6         MOV DWORD PTR DS:[EBX-A],EAX

 

EBX-A = DB7E14…

La difficulté est de savoir d’où peut bien venir la valeur stockée eax étant donné que le code au dessus est blindé de CCA…

Eh bien on ne se dégonfle pas on va retracer le code apres le premier Shift+F9 pour voir quelque chose d’interessant :

 

00DB1A58    8B05 D251DA00   MOV EAX,DWORD PTR DS:[DA51D2]

00DB1A5E  - FF20            JMP DWORD PTR DS:[EAX]                   ; kernel32.GetVersion

 

Apres un jmp et un ret on se retrouve en DB1ADB où l’on stocke eax en DB7E14 . Vous l’aurez donc deviné, cet import correspond en fait à GetVersion !

Hum… On peut déjà commencer à en tirer des conclusions. Je pense que les apis émulées sont appelées les unes à la suite des autres entre la première exception et la seconde. Les valeurs de retour sont ensuite stockées dans un tableau (ebx-A pointant vers l’élément courant) pour être utilisées plus tard lors de l’appel émulé des apis en question par le programme d’origine.

 

Quatrième import :

 

0          000C6384       ?          0000    00DB1CC8

 

Cela nous donne :

 

00DB1CC8    push ebp

00DB1CC9    mov ebp,esp

00DB1CCB    mov eax,[DB7E24]    // DWORD value: 00133010

00DB1CD1    mov eax,[ebp+8]

00DB1CD4    pop ebp

00DB1CD5    retn 4

 

Alors c’est cet import là qui m’a donné le plus de soucis en fait… En effet ce bout de code ne fait rien à part renvoyer en eax l’argument qu’on lui a passé. Alors une solution était de copier ce bout de code dans le padding et de fixer le pointeur pour qu’il désigne précisément ce bout de code… Par la suite j’ai pu voir que certains affirmaient qu’il s’agissait de LockResource, ce que semble également confirmer le plugin d’ImpRec après vérification.

Il s’agit donc là de l’api LockResource.

 

Cinquième import :

 

0          000C63A8      ?          0000    00DB1C64

 

00DB1C64    push ebp

00DB1C65    mov ebp,esp

00DB1C67    mov eax,[ebp+8]

00DB1C6A    test eax,eax

00DB1C6C    jnz short 00DB1C81

00DB1C6E    cmp dword ptr [DB7AA4],400000

00DB1C78    jnz short 00DB1C81

00DB1C7A    mov eax,[DB7AA4]    // DWORD value: 00400000

00DB1C7F    jmp short 00DB1C87

00DB1C81    push eax

00DB1C82    call 00DA51B8    // = kernel32.dll/013B/GetModuleHandleA

00DB1C87    pop ebp

00DB1C88    retn 4

 

 

Cette fois ci c’est GetModuleHandleA, vu que eax n’est pas ecrasé après l’appel à GetModuleHandleA et que le code est assez simple à interpréter.

 

Sixième import :

 

0          000C6410       ?          0000    00DB17A4

 

00DB17A4    push ebp

00DB17A5    mov ebp,esp

00DB17A7    mov edx,[ebp+C]

00DB17AA    mov eax,[ebp+8]

00DB17AD    mov ecx,[DB6484]    // DWORD value: 00DB6304

00DB17B3    mov ecx,[ecx]

00DB17B5    cmp ecx,eax

00DB17B7    jnz short 00DB17C2

00DB17B9    mov eax,[edx*4+DB63D8]    // DWORD value: 00000000

00DB17C0    jmp short 00DB17C9

00DB17C2    push edx

00DB17C3    push eax

00DB17C4    call 00DA51C0    // = kernel32.dll/0154/GetProcAddress

00DB17C9    pop ebp

00DB17CA    retn 8

 

Même remarque que pour GetModuleHandleA…

C’est l’api GetProcAddress !

 

Il ne nous reste plus que ça à résoudre:

 

FThunk: 000C6800     NbFunc: 00000001

0          000C6800       ?          0000    004D0708

 

Alors là j’ai eu beau chercher, j’ai fini par en conclure que cet import n’était pas valide.  Faites un clic droit dessus et Delete Thunk.

 

Maintenant que nous avons résolu le probleme de quel pointeur correspond à quel import, il est temps de fixer tout ça en relançant le programme et en breakant à l’adresse 48CFF1. Résolvez tous les imports comme expliqué ci dessus avec ImpRec.

Nous allons enfin pouvoir fixer notre dump ! Cliquez sur fix Dump et choisissez notre dump et vous pouvez fermer ImpRec.

En revanche ne fermez pas Olly, nous en aurons encore besoin par la suite…

 

A ce niveau là, si vous essayez d’exécuter le dump, il refusera de se lancer.. Les stolen bytes ça vous dit quelque chose ?

On ne les a pas encore injectés dans notre dump ! Bon allez un petit désassemblage du dump ne fera pas de mal.

Voyons ce qu’on a à l’Entry Point du dump :

 

0048D017                 public start

0048D017 start           proc near

0048D017                 call    ds:GetVersion   ; Get current version number of Windows

0048D017                                         ; and information about the operating system platform

0048D01D                 xor     edx, edx

 

On a donc un call GetVersion… Je ne sais pas vous mais je pose souvent un BP sur cette api pour breaker pres de l’entry point d’un prog compilé par VC++ 6.

 

Voyons d’ailleurs ce qu’il se passe vers l’OEP d’un programme écrit en Visual C++ 6 par curiosité :

 

push ebp

mov ebp, esp

push -1

push XXXXXXXX

push XXXXXXXX

mov eax, dword ptr fs:[00000000]

push eax

mov dword ptr fs:[00000000], esp

sub esp, 00000058

push ebx

push esi

push edi

mov dword ptr [ebp-18], esp

Call GetVersion

 

Héhé je crois bien qu’on a bel et bien affaire à un programme compilé par VC++ 6!

La seule difficulté sera de deviner les valeurs des XXXXXXXX poussées sur la pile. Comment va t-on faire ? Eh bien on a toujours notre programme en mémoire avec Olly, il ne nous reste plus qu’à examiner le contenu de la pile pour trouver les valeurs de nos XXXXXXXX.

 

Il faut donc examiner le contenu de la pile à partir de ebp :

 

0012FFB4   0048BA74  SE handler

0012FFB8   004D4E40  aforg.004D4E40

0012FFBC   FFFFFFFF

0012FFC0   0012FFF0

 

Nous remplacerons donc nos 2 push XXXXXXXX par:

 

push 004D4E40

push 0048BA74

 

Il ne nous reste plus qu’à patcher tout ça avec un éditeur hexadecimal .

On se rend à l’offset 8CFF1 et on remplace les 00 par ces octets là :

 

55                

8BEC                

6AFF                   

68404E4D00             

6874BA4800             

64A100000000           

50                     

64892500000000 

83EC58       

53                 

56                   

57  

8965E8

 

Les stolen bytes sont maintenant fixés! Vous pouvez sauvegarder !

N’oubliez pas que le nouvel Entry Point de notre dump est désormais 8CFF1, si ce n’est pas encore fait alors faites la modification avec LordPE.

Nous nous sommes occupés de reconstruire l’iat puis nous avons fixé nos stolen bytes, nous pouvons donc lancer notre dump et là c’est la catastrophe ! Notre dump crashe lamentablement. Avant que l’on me pende, sachez que c’est la première fois que cela m’arrive car normalement le dump aurait du être fonctionnel. Et il le sera !

 

Débogage du dump :

 

Le message d’erreur renvoyé est :

L‘instruction à « 0x00db1ba4 » emploie l’adresse mémoire « 0x00db1ba4 ». La mémoire ne peut pas être « read ».

Merci Jean Claude !

 

Il n’y a plus qu’à lancer notre dump avec Olly pour voir à quel endroit le programme plante. Je rappelle qu’une autre occurrence d’Olly est toujours ouverte et notre exe packé est toujours en cours de debuggage.

 

1er crash à cet endroit là :

 

004016EC   > \FF15 FCF94E00 CALL DWORD PTR DS:[4EF9FC]

 

En [4EF9FC], nous avons la valeur 0DB1BA4. Ce call fait donc appel au loader d’Asprotect et vu qu’il n’est plus exécuté voilà donc pourquoi ça plante ! Posons un BP sur l’adresse 4016EC dans notre exe packé pour voir ce qu’il s’y passe :

 

00DB1BA4    833D A463DB00 0>CMP DWORD PTR DS:[DB63A4],0

00DB1BAB    75 0D           JNZ SHORT 00DB1BBA

00DB1BAD    A1 407DDB00     MOV EAX,DWORD PTR DS:[DB7D40]

00DB1BB2    8B15 447DDB00   MOV EDX,DWORD PTR DS:[DB7D44]

00DB1BB8    EB 0B           JMP SHORT 00DB1BC5

00DB1BBA    A1 A463DB00     MOV EAX,DWORD PTR DS:[DB63A4]

00DB1BBF    8B15 347EDB00   MOV EDX,DWORD PTR DS:[DB7E34]

00DB1BC5    85C0            TEST EAX,EAX

00DB1BC7    74 0B           JE SHORT 00DB1BD4

00DB1BC9    85D2            TEST EDX,EDX

00DB1BCB    74 07           JE SHORT 00DB1BD4

00DB1BCD    52              PUSH EDX

00DB1BCE    50              PUSH EAX

00DB1BCF    E8 60FDFFFF     CALL 00DB1934

00DB1BD4    C3              RETN

 

Ce call a pour seul effet de mettre les registres eax et edx à 0. Intéressant à savoir…

En effet il nous suffirait d’écrire ces 3 lignes de code quelque part :

 

Adresse_de_notre_code :

xor eax, eax

xor edx,edx

ret

 

Il n’y aurait plus qu’à mettre la valeur Adresse_de_notre_code à la place de DB1BA4 dans [4EF9FC].

Cela résoudrait définitivement le problème.

Je fais un test en passant au dessus du call et en mettant eax et edx à 0 avec le debugger.

Un autre problème se pose alors :

 

00401904   > \FF15 F8F94E00 CALL DWORD PTR DS:[4EF9F8]

 

En [4EF9F8] nous avons l’adresse DB1BD8, ce qui fera à nouveau crasher notre dump.

Voyons voir ça :

 

00DB1BD8    833D A463DB00 0>CMP DWORD PTR DS:[DB63A4],0

00DB1BDF    75 0D           JNZ SHORT 00DB1BEE

00DB1BE1    A1 407DDB00     MOV EAX,DWORD PTR DS:[DB7D40]

00DB1BE6    8B15 447DDB00   MOV EDX,DWORD PTR DS:[DB7D44]

00DB1BEC    EB 0B           JMP SHORT 00DB1BF9

00DB1BEE    A1 A463DB00     MOV EAX,DWORD PTR DS:[DB63A4]

00DB1BF3    8B15 347EDB00   MOV EDX,DWORD PTR DS:[DB7E34]

00DB1BF9    85C0            TEST EAX,EAX

00DB1BFB    74 09           JE SHORT 00DB1C06

00DB1BFD    85D2            TEST EDX,EDX

00DB1BFF    74 05           JE SHORT 00DB1C06

00DB1C01    E8 A6FDFFFF     CALL 00DB19AC

00DB1C06    C3              RETN

 

C’est une réplique du code précédent ! Il met encore une fois eax et edx à 0…

Ca nous arrange bien ! Il faudra juste changer DB1BD8 par Adresse_de_notre_code en [4EF9F8].

J’effectue toutes mes modifications en mémoire pour voir si cela suffira à réparer notre dump et bingo !

Le programme se lance et est entièrement fonctionnel !

 

Voici les modifications que j’ai effectuées en dur :

 

0050DCAC    B8 00000000     MOV EAX,0

0050DCB1    BA 00000000     MOV EDX,0

0050DCB6    C3              RETN

 

C’est l’endroit où j’ai écrit mon code.

 

Ensuite j’ai remplacé :

 

000EF9F0   0000000000000000D81BDB00A41BDB00

 

par :

 

000EF9F0   0000000000000000ACDC5000ACDC5000

 

avec l’éditeur hexadecimal.

 

On sauvegarde les modifications et miracle notre dump se lance et est fonctionnel.

Ce fût très laborieux mais nous y sommes quand même parvenus ! Je tiens quand même à en rassurer certains en précisant qu’il arrive qu’il n’y ait pas de stolen bytes, que la reconstruction de l’iat ne pose pas toujours des problèmes avec ImpRec surtout avec le plugin Asprotect et par dessus tout je tiens à dire que vous n’aurez que très rarement à intervenir dans votre dump comme nous venons de le faire !

 

 

ANNEXES :

 

Pour compléter ce tutorial, voici quelques informations supplémentaires.

 

Voici quelques signatures de divers compilateurs :

 

DELPHI

 

PUSH EBP

MOV EBP, ESP

ADD ESP, -0C

MOV EAX, XXXXXXXX

 

558BEC83C4F4B8XXXXXXXX

 

VISUAL C++ 7

 

PUSH 60

PUSH XXXXXXXX

 

6A6068XXXXXXXX

 

Pour Visual C++ 6, voir plus haut.

 

 

Voici la liste des apis émulées (pas forcément exhaustive) :

 

GetCommandLineA

GetModuleHandleA

GetProcAddress

LockResource

FreeResource

GetVersion

GetCurrentProcess

GetCurrentProcessId

DialogBoxParamA (?)

 

Le plugin Asprotect d’ImpRec permet de les résoudre facilement mais j’ai entendu dire qu’il avait des difficultés avec LockResource et FreeResource. Information à vérifier…

 

CONCLUSION :

 

Voilà ce tutorial est désormais terminé ! J’espère que vous aurez appris quelques trucs à propos de ce packer et que je n’ai pas écrit trop d’âneries héhé… Je répète une dernière fois que ce tutorial n’a aucune prétention si ce n’est d’exister.

Par ailleurs je tiens à remercier tous les crackers qui animent la scène en faisant des crackmes, tutoriaux… J

 

Kaine, Juin 2004