GRAPHE AT 1.03e
By Christal
Principe général: :004233B1 E9E760FEFF jmp 0040949D :004233B6 CC int 03 :004233B7 CC int 03 :004233B8 8B4DF0 mov ecx, dword ptr [ebp-10] :004233BB E9B15BFEFF jmp 00408F71 :004233C0 B870A44200 mov eax, 0042A470 :004233C5 E9D360FEFF jmp 0040949D :004233CA 0000 add byte ptr [eax], al :0041D026 0100 add dword ptr [eax], eax :0041D028 800000 add byte ptr [eax], 00 :0041D02B 0030 add byte ptr [eax], dh :004064B2 00000000000000000000 BYTE 10 DUP(0) :004064BC 00000000000000000000 BYTE 10 DUP(0) :004064C6 00000000000000000000 BYTE 10 DUP(0) :004064D0 00000000000000000000 BYTE 10 DUP(0)
Dans le meilleur des cas, Wdasm désassemble le fichier sans les ressources
habituelles (Strings Datas, Fonctions importées et exportées, Dialog...). - Les codes au niveau de l'Entry Point (bien éloigné de l'habituel 00401000!) ressemblent à ceci; 017F:008F4000 669C PUSHF 017F:008F4002 60 PUSHAD 017F:008F4003 E8CA000000 CALL 008F40D2 017F:008F4008 0300 ADD EAX,[EAX] 017F:008F400A 0400 ADD AL,00 017F:008F400C 0500060007 ADD EAX,07000600 017F:008F4011 0008 ADD [EAX],CL 017F:008F4013 0009 ADD [ECX],CL 017F:008F4015 000A ADD [EDX],CL 017F:008F4017 000B ADD [EBX],CL Bref! vous avez affaire à un programme compressé ou crypté. Identification du compresseur ou du crypteur:
Soit des noms de sections que vous identifierez comme étant liés à un packer/crypteur (en début de fichier, au niveau des informations du PE Header), en utilisant un Snooper pour récupérer toutes les chaînes alphanumériques du fichier, ou plus simplement un éditeur hexadécimal (avec correspondance ASCII, mais il me semble qu'ils le font tous...). ....PESHiELD........ .V.................. @...PESHiELD........ .....Z.............. @...ANAKIN98.0...... ou avec ProcDump, UPX0 00038000 00001000 00000000 00000400 E0000080 UPX1 00023000 00039000 00022600 00000400 E0000040 .rsrc 00001000 0005C000 00000C00 00022A00 C0000040 · Identifier la signature du packer/compresseur, c'est à dire le code qui permettra de reconnaître tel ou tel packer, à partir d'une suite de mnémoniques caractéristiques (ex 61 FF E0 = POPAD JMP EAX) et bien sûr situé dans une zone non compressée/packée (clean) . Dans le cas de GrapheAt, on ne retouve aucune trace de CopyRight. Pour autant ce n'est pas obligatoirement une compression maison, mais le packer n'étant pas facilement identifiable, il faudra procéder à la réalisation d'un Dump manuel. Utiliser Wdasm et SoftIce: Name Virt Size Virt Offset Raw Size Raw Offset Characteristics CODE 00062000 00001000 00033A00 00001C00 E0000060 BSS 00476000 00063000 00000000 00000000 C0000000 .idata 00002000 004D9000 00002000 00035600 C0000040 .tls 00001000 004DB000 00000000 00000000 C0000000 .rdata 00001000 004DC000 00000200 00037600 D0000040 .reloc 00007000 004DD000 00000000 00000000 C0000040 .rsrc 00010000 004E4000 000053E0 00037800 C0000040 .rsrcgr 0000D2DC 004F4000 00001800 00000400 E2000060 C'est par la section .rsrcgr que va attaquer le Soft. Or si les autres sections
ont des noms " honorables " celle ci fait louche… Vous aurez probablement remarqué que dans cet exemple, toutes les sections
ont des caractéristiques différentes ( il faut que certaines sections soient Executable, Readable,
Writable et Data! ainsi, le programme peut lire le code compressé, et le décompresser dans la même
section sans provoquer d'erreur fatale dans Windows), ce qui, normalement, vous empêche souvent de désassembler
l'exécutable, ou d'obtenir un break en passant par le Symbol Loader de SoftIce. 0x00000020 IMAGE_SCN_CNT_CODE 0x20000000 IMAGE_SCN_MEM_EXECUTE 0x40000000 IMAGE_SCN_MEM_READ OR 0x80000000 IMAGE_SCN_MEM_WRITE ----------------------------------- 0xE0000020
Header Infos Entry Point : 004F4000 Size Of Image : 005012DC Image Base : 00400000 En cliquant sur le bouton " Sections ", vous obtiendrez le tableau vu
ci dessus. 017F:008F561D 6A05 PUSH 05 017F:008F561F 59 POP ECX 017F:008F5620 F3A4 REPZ MOVSB 017F:008F5622 61 POPAD > Classique! 017F:008F5623 669D POPF 017F:008F5625 E95AC5B6FF JMP 00461B84 > OEP C'est le passage de relais vers le programme d'origine. Il est possible d'en être à peu prés certain, car on passe brutalement des adresses 008F5XXX à 00461XXX 017F:00461B84 55 PUSH EBP 017F:00461B85 8BEC MOV EBP,ESP 017F:00461B87 83C4F4 ADD ESP,-0C 017F:00461B8A 53 PUSH EBX 017F:00461B8B E86818FAFF CALL 004033F8 017F:00461B90 E88F2EFAFF CALL 00404A24 Et qu'ensuite le PUSH EBP est un classique des débuts de programmes, bien
que ce ne soit pas une règle absolue. 017F:008F4000 669C PUSHF 017F:008F4002 60 PUSHAD 017F:008F4003 E8CA000000 CALL 008F40D2 017F:008F4008 0300 ADD EAX,[EAX] Et passez à l'étape suivante. PEPack 61 POPAD > restauration FFEO JMP EAX > passe la main 8D85CE050000 LEA EAX,[EBP+000005CE] PE-ExeEnCrypter 5F POP EDI > restauration 5D POP EBP > restauration FFE0 JMP EAX > passe la main Voici une variante du POPAD, ou les registres sont récupérés
un à un: 015f:0040e090 pop ebx ------on récupère 015f:0040e091 pop ecx ------tous les 015f:0040e092 pop edx ------registres 015f:0040e093 pop esi 015f:0040e094 pop edi 015f:0040e095 pop ebp 015f:0040e096 jmp eax ----- et on saute vers le prog décrypté... VG Crypt 61 POPAD > restauration 9D POPFD 8B9A09274000 MOV EBX,[EDX+00402709] 898A09274000 MOV [EDX+00402709],ECX FFE3 JMP EBX variante du EAX! > passe la main Avec un peu d'habitude, on en sait assez: Le JMP EAX (ou plus rarement EBX) est
très couramment utilisé pour brancher vers les codes du programme original (OEP). 8945E0 mov dword ptr [ebp-20], eax (le fameux EAX!) FF7510 push [ebp+10] FF750C push [ebp+0C] FF7508 push [ebp+08] FF55E0 call [ebp-20] > passe la main à l'OEP 8945E4 mov dword ptr [ebp-1C], eax EB07 jmp 0063E4EE Là aussi, il y a des variantes: le push EAX (qui va pousser une valeur sur
la pile) et le Ret (qui récupère cette adresse sur la pile) vont simuler un retour sur call appelant. LEA EAX,[EBP+00444C37] 50 push eax C3 ret Il y a aussi les cas ou plus simplement le programme se branche sur l'Entry Point
du programme décompressé/décrypté par un tout bête JMP OEP (Original Entry Point) 61 popad E98EF7CAFF jmp 004CAD80 > jump sur l'OEP 00000000000000000000 BYTE 10 DUP(0) 00000000000000000D42 BYTE 10 DUP(0) (Il n'est pas très difficile de mettre la main sur la signature d'UPX. Toutes
les versions que j'ai pu en voir permettent de la trouver à la fin du listing désassemblé).
Dans le cas de GrapheAT, vous trouverez un cas de figure identique. 5D pop ebp 5B pop ebx E9673DFFFF jmp 00401000 > jump sur l'OEP Il y a bien sur des cas particuliers...
Mais dans le cas de GrapheAT, le codage est simple (pas d'Overlapping), et ne présente aucun problème lors du traçage. Pour obtenir une copie du programme décompressé en mémoire
on peut utiliser au choix IceDump (pagein D 400000 longeur_du_code c:\dump.exe) ou ProcDump. Dans les deux cas,
il faudra s'arréter en 008F5625. Header Infos Entry Point : 004F4000 > entry point à modifier Size Of Image : 005012DC Image Base : 00400000 Il va falloir modifier l'Original Entry Point pour que le programme puisse commencer
en 00461B84, et lui soustraire la valeur
de l'imagebase (00400000): 00461B84
(OEP) - 400000 (IB) = 61B84 (Entry
Point à entrer dans le champ de ProcDump, ou en utilisant un éditeur hexadécimal). 0000011C 00060E00 Taille de la section Code 00000120 00019200 Taille des Initialized Data 00000124 00000000 Taille des Uninitialized Data 00000128 004F4000 Entry Point (RVA) 0000012C 00001000 Base du Code 00000100 5045 0000 4C01 0800 195E 422A 0000 0000 PE..L....^B*.... 00000110 0000 0000 E000 8E81 0B01 0219 000E 0600 ................ 00000120 0092 0100 0000 0000 0040 4F00 0010 0000 .........@O..... Une fois obtenu un Dump exécutable du programme, vous aurez une copie de ce qu'il pouvait être avant de passer dans le compresseur, avec un exéctable plus gros du fait de la présence du loader dans les codes, même si celui ci a été shunté. Rien de plus facile alors que de patcher l'exécutable obtenu. Comme Cracker le programme: Après avoir entré un sérial, avec un BPX HmemCpy, on arrive presque immédiatement ici : 017F:0045115A 83F810 CMP EAX,10 > 10 caractères ? 017F:0045115D 741A JZ 00451179 > Go Away En regardant un peu plus bas dans les codes du programmes, on voit ceci : 017F:004511E3 6A00 PUSH 00 017F:004511E5 668B0D90124500 MOV CX,[00451290] snips snips ------------------ 017F:00451226 C70510917B0001000000MOV DWORD PTR [007B9110],00000001 Histoire de voir si ce que vous avez soupçonné est good, un jmp 004511E3
à la place du JZ en 0045115D, et n'importe quel sérial peut être accepté L'adresse à patcher est donc 0045EF8A, en remplaçant FFFFFFFF par 00000001
T=2000: ; temps accordé pour trouver les bytes à modifier F=grapheat.exe: ; nom du programme à patcher O=loader_grapheat.exe: ; nom du fichier exe que vous allez créer P=45EF90/FF,FF,FF,FF/00,00,00,01: ; modifications à apporter en 0045EF90 $ ; ordre de fin de script Mais les puristes vous diront que ce n'est pas encore suffisant. Il va falloir réussir
à patcher le programme compressé et/ou crypté. Pour y arriver, vous devez commencer par: 803D90EF4500FF CMP BYTE PTR [0045EF90],FF > adresse visée decompréssée? 750A JNZ 00XXXXXX > non-> continue C70590EF450001000000 MOV DWORD PTR [0045EF90],00000001 > oui -> modifie la cible E980FEFFFF JMP 00XXXXXX > retour à la normale Une fois que vous connaissez la taille du patch, il ne reste plus qu'à: 0000 ADD [EAX],AL > octets nuls 0000 ADD [EAX],AL 0000 ADD [EAX],AL 0000 ADD [EAX],AL 00FF ADD BH,BH FFFF INVALID FFFF INVALID > fin de la section Il faudra, avant tout, vous assurez qu'à aucun moment le compresseur/crypteur
ne va venir y écrire quoi que ce soit, ou l'utiliser pour Dieu sait quoi, en posant quelques BPM sur les
adresses repérées. Name Virt Size Virt Offset Raw Size Raw Offset Characteristics .rsrcgr 0000D2DC 004F4000 00001800 00000400 E2000060 La Virtual size de la section est 0000D2DC, ce qui veut dire que la mémoire
qui sera allouée pour cette section sera de 0000D2DC bytes. Le Virtual Offset de la section, et du code
appartenant au loader, est de 004F4000, additionné à l'Image base qui vaut 00400000, ca nous donne
une adresse virtuelle de 004F4000 + 00400000 = 008F4000. A l'aide de SoftIce, vous allez pouvoir contrôler qu'il y a bien une série de 00 00 (place "disponible") à la fin de la section .rsrcgr, quand le loader aura fini son travail, c'est à dire quand vous serez à l'adresse 008F5625. Un BPR sur la longeur des octets que vous voulez réserver pour votre patch va vous assurer que la zone convoitée est bien disponible, et vous pourrez vous installer en 00856B3 par exemple. Dans le projet sur les PE Packed, il est parfois impossible d'insérer un patch. Il faut alors rajouter du code ou, en d'autre terme, augmenter la grandeur d'une section, voir rajouter une section. Comme ce n'est pas le cas içi, nous en parlerons un prochaine fois. Voici le patch en lui même: :008F56B3 803D90EF4500FF CMP BYTE PTR [0045EF90],FF > adresse visée decompréssée? :008F56BA 750A JNZ 008F56C6 > non-> continue :008F56BC C70590EF450001000000MOV DWORD PTR [0045EF90],01 > oui -> modifie :008F56C6 8B86E0B50000 MOV EAX,[ESI+0000B5E0] > retauration :008F56CC E980FEFFFF JMP 008F5551 > retour à la normale
Codes d'origines: 017F:008F5543 E834ECFFFF CALL 008F417C > decompression de l'adresse visée 017F:008F5548 017D0C ADD [EBP+0C],EDI 017F:008F554B 8B86E0B50000 MOV EAX,[ESI+0000B5E0] > place à prendre?! 017F:008F5551 017DFC ADD [EBP-04],EDI Ré-adressage: 017F:008F5543 E834ECFFFF CALL 008F417C 017F:008F5548 017D0C ADD [EBP+0C],EDI 017F:008F554B E963010000 JMP 008F56B3 > jump vers le patch 017F:008F5550 90 NOP 017F:008F5551 017DFC ADD [EBP-04],EDI > retour içi Dans ce cas précis, il faudra que le patch réécrive les MOV EAX,[ESI+0000B5E0]. Après que les modifications voulues aient été faites, vous redirigerez vers l'adresse 008F5551 pour que l'application continue, comme si de rien n'était. |
Bonne Journée