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 :
PUSH EBP
MOV EBP,
ESP
ADD ESP,
-0C
MOV EAX,
XXXXXXXX
558BEC83C4F4B8XXXXXXXX
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