IORIOR iorior.cjb.net iorior@altavista.com |
CrackMe Gold de CoOlViPeR | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
URL du crackme: http://coolviper.fr.st outils: Softice, icedump, Ida, éditeur hexa style: packed, anti-Softice, anti-procdump, cca, keygen "malin" Date: 11/03/2000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
CoOlViPeR nous a tellement parlé de son crackme que je me suis senti obligé de le cracker. Son aide.txt précise "Vous devez uniquement faire un keygen". | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I Dump Avec gettyp, on a: [C:\FICHIERS\CRAC\CRACME\CRACKMEG\CrackMe.exe] ----- DOS executable file - 11414 bytes Portable executable (starting at 11036 for 378 bytes) Packer: UPX 0.81 - 0.84 [PE] (?) Packer: UPX 0.89.6 - 1.02 [PE] Calculated entrypoint: 9264 / 00002430h (RVA: 0000A030h) Required CPU type: 80386 Requires Win 95 or NT 4 Flags: Relocation info stripped from file File is executable Line numbers stripped from file Local symbols stripped from file 32 bit word machine Linker version: 5.12 Objects (object align = 00001000h): Name Virt size RVA Phys size Phys Ofs 00007000h 00001000h 00000000h 00000400h 00003000h 00008000h 00002200h 00000400h 00001000h 0000B000h 00000600h 00002600h Found 150 bytes overlay Absolute position: 11264 of 11414 (= 98.7%) Zero padded (29 bytes) Overlay type: unknown (0070h) - Files identified: 1 of 1 (100.00%) - Total time: 270.0 ms (50.0 ms/file) (220.0 ms lost)Mais impossible d'utiliser upx pour décompresser, le PE ayant été changé. On peut faire un dump manuel. On charge le crackme avec Symbol Loader, on descend de 6 pages dans la fenêtre du code, jusqu'à trouver un popad, sur lequel on met un bpx:
On trace ensuite jusqu'au popad suivant:
on retient l'entry point: 00401000 Si on lance le dump, une fenêtre dos s'ouvre. Si on essaie de le regarder avec PE editor de Procdump, celui ci plante. Qu'à cela ne tienne! Regardons cela avec un éditeur hexa. L'adresse du début du PE-Header se situe toujours en 0x3C, donc ici le PE Header est sensé commencer en 0x00002B1C, adresse à laquelle il n'y a rien (dans le dump). Pas besoin de chercher bien loin, le bon PE Header se situe en 0x000000C0. En 0x3C, on change donc le dword 1C2B0000 en C0000000. Changeons maintenant l'entry point: en 0xE8 (C0+28), on met 00100000 à la place de 30A00000 Il faut maintenant changer la taille des sections. La première (section .code sans doute) ne débute apparemment pas en 0x400 mais en 0x1000, sa taille est de 0x7000. La deuxième section débute en 0x8000 et sa taille est de 0x3000. On change aussi la dernière section, toujours en alignant la raw offset sur les voffsets, elle débute en 0xB000 et sa taille est de 0x1000 ça y est! on a un dump fonctionnel! Mais on n'a toujours pas vu à quoi ressemblait la fenêtre de ce crackme à cause de l'anti-Softice... II L'anti-Softice J'avoue que je n'ai pas tout étudié à fond. On a une message box "Numega Softice detected" même quand on utilise frogsice, et même quand on utilise TRW! il appelle un exception par une division par 0 en 0040116A Là encore icedump se révèle être un outil précieux. Il existe une excellente commande /protect : ----------------- /PROTECT [ON|OFF] ----------------- control access to critical system resources such as the GDT and the System VM's IDT and LDT which are normally left accessible under win9x to normal (ring-3) apps. when on, winice will be brought up at any read/write attempt to the GDT and the System VM's IDT, or a write attempt to the System VM's LDT, or whenever a win32 thread attempts to change its own CPL to ring-0 via context manipulation (typically by putting a DPL=0 code selector into its own CS register). when invoked without parameters it will print out the current status (on/off).On tapes donc /protect on et on lance le crackme. On break en 004017DB
Il doit y avoir aussi un meltice puisqu'on trouve \\.\SICE dans les données, je ne l'ai pas localisé. En fait les anti-Softice deviennent inutiles, certains l'ont d'ailleurs compris: Il n'y a plus d'anti softice depuis la version 1.1 d'ASProtect, par contre il y a du cca <- Notez la qualité des transitions dans ce tutorial ;o) III Le cca (code changeant d'apparence) Je vous conseille vivement ida plutôt que win32asm, et surtout quand il y a du cca, ida ne le craignant pas. Généralement, quand on a du cca, ce sont toujours les mêmes octets qui reviennent. Ici, on a: 00401000 jmp short loc_401005 00401000 ; --------------------------------------------------------------------------- 00401002 db 0CDh, 20h, 0C7hou: 0040100C jmp short loc_401011 0040100C ; --------------------------------------------------------------------------- 0040100E db 0E9h, 21h, 47hou encore: 0040102A jmp short loc_401030 0040102A ; --------------------------------------------------------------------------- 0040102C dd 0EB20CDEBhon va enlever tout ça. On prends notre éditeur hexa et on utilise la fonction "remplacer" pour changer EB03CD20C7 en 9090909090 partout. On fait la même chose pour EB04EBCD20EB, et pour tous les autres octets. On a maintenant un prog propre que l'on peut keygenner. IV La recherche d'un serial Il y a un vieux truc connu: anti-bpx getdlgitemtexta (on regarde si le 1er byte est CC, si c le cas, il y a un bp). Pour contourner ça, il suffit de taper dans softice: u getdlgitemtexta puis on place un BP après l'adresse où il est placé normalement quand on fait bpx getdlgitemtexta On désassemble le prog sans cca avec ida. Je vous conseille de changer les noms en "nom" et "serial" pour y voir plus clair. 00401450 push 100h 00401455 push offset nom 0040145A push 69h 0040145C push ds:dword_403070 00401462 call j_GetDlgItemTextA 00401467 nop 00401468 nop 00401469 nop 0040146A nop 0040146B nop 0040146C nop 0040146D push 100h 00401472 push offset serial 00401477 push 6Ah 00401479 push ds:dword_403070 0040147F call j_GetDlgItemTextABon j'explique l'algorythme: en ecx se trouve le nombre de caractère du nom ( push offset nom call j_lstrlen xchg eax, ecx) quand on arrive ici: 004014D6 mov esi, offset nom 004014DB 004014DB loc_4014DB: ; CODE XREF: seg000:004014EA.j 004014DB nop 004014DC nop 004014DD nop 004014DE nop 004014DF lodsb 004014E0 nop 004014E1 nop 004014E2 nop 004014E3 nop 004014E4 add ebx, eax 004014E6 nop 004014E7 nop 004014E8 nop 004014E9 nop 004014EA loop loc_4014DB ; somme_nomen ebx sort de la boucle la somme des caractères ascii du nom ensuite 004014F1 mov eax, ds:serial_plus_5 ; car6789 004014F6 nop 004014F7 nop 004014F8 nop 004014F9 nop 004014FA nop 004014FB add ebx, eax 004014FD nop 004014FE nop 004014FF nop 00401500 nop 00401501 nop 00401502 mov eax, ds:aa 00401507 nop 00401508 nop 00401509 nop 0040150A nop 0040150B nop 0040150C mul ebx 0040150E nop 0040150F nop 00401510 nop 00401511 nop 00401512 nop 00401513 mov ds:dword_401563, eax -autopatchA la somme des caractères du nom est ajoutée les caractères 6,7,8,9 du serial, ensuite une multiplication est effectuée avec 582105F5h. Le résultat donné est mis en 00401563 (autopatch). Ma première idée était de foncer tête baissée et de chercher ce qu'il faut pour que le résultat soit 90909090h La somme des caractères de iorior est de 294h ( somme du nom + car6789 ) * 582105F5h = 90909090h ( 294h + car6789 ) * 582105F5h = 90909090h Ici on peut faire un brute force dans softice: on met ebx à 0 En 004014FD, on met inc ebx En 0040150E, on met cmp eax, 90909090 jne 004014FD Et on place un BP après le jne. 025f6450h * 582105F5h = 90909090h 025f6450h - 294h = 025F61BCh <- caractere 6,7,8,9 du serial pour iorior Sauf que on a 1 test de edx après: 00401563 dword_401563 dd 909002EBh ; DATA XREF: seg000:00401513.w 00401567 ; --------------------------------------------------------------------------- 00401567 nop 00401568 nop 00401569 nop 0040156A nop 0040156B nop 0040156C mov eax, ds:serial 00401571 nop 00401572 nop 00401573 nop 00401574 nop 00401575 nop 00401576 nop 00401577 cmp eax, edx 00401579 nop 0040157A nop 0040157B nop 0040157C nop 0040157D jnz loc_40166E 00401583 nop 00401584 nop 00401585 nop 00401586 nop 00401587 nop 00401588 call near ptr dword_4016AF 0040158D nopPour éviter ça, on peut essayer de ne pas obtenir un résultat de 90909090h mais de 90902AEBh, on aura donc un saut (EB2A) qui évitera les tests. On fait donc la même chose: ( 294 + car6789 ) * 582105F5h = 90902AEB En brute force, on trouve 3785015Fh 3785015Fh * 582105F5h = 90902AEB 3785015Fh - 294 = 3784FECB <- caractere 6,7,8,9 du serial pour iorior en ascii: Ëþ„7 Remarquez qu'on aurait pu se désintéresser complètement de la suite de l'algorithme en faisant faire un saut en 00401643, on aurait pu aussi faire un saut en 00401592, pour éviter le xor edx, edx qui pose problème en 004015CD 2eme partie Le 2eme patch est beaucoup plus simple 00401597 mov eax, ds:nom 0040159C nop 0040159D nop 0040159E nop 0040159F nop 004015A0 nop 004015A1 and eax, 0F0F0F0Fh 004015A6 nop 004015A7 nop 004015A8 nop 004015A9 mov ebx, dword ptr ds:byte_403081 004015AF nop 004015B0 nop 004015B1 nop 004015B2 nop 004015B3 sub ebx, eax 004015B5 nop 004015B6 nop 004015B7 nop 004015B8 nop 004015B9 nop 004015BA mov ds:dword_4015C4, ebx -autopatchEn 403081, on a les caractères 10,11,12,13 du serial Pour éviter le saut en 004015D2, j'ai chercher à incrémenter edx, donc à trouver 90904290h pour le dword autopatché. Les 4 premiers caractères de mon nom ont pour code ascii: 696F7269 696F7269h and 0F0F0F0Fh = 090F0209h 090F0209h + 90904290h = 999F4499h Soit en ascii: ™ŸD™ 3 eme partie un dernier contrôle: 004015EC mov esi, offset serial 004015F1 nop 004015F2 nop 004015F3 nop 004015F4 nop 004015F5 nop 004015F6 mov ecx, edx 004015F8 nop 004015F9 nop 004015FA nop 004015FB nop 004015FC add ecx, 5 004015FF nop 00401600 nop 00401601 nop 00401602 00401602 loc_401602: ; CODE XREF: seg000:0040160F.j 00401602 lodsb 00401603 nop 00401604 nop 00401605 nop 00401606 nop 00401607 nop 00401608 add ebx, eax 0040160A nop 0040160B nop 0040160C nop 0040160D nop 0040160E nop 0040160F loop loc_401602 00401611 nop 00401612 nop 00401613 nop 00401614 and bx, 0F0F0h 00401619 nop 0040161A nop 0040161B nop 0040161C nop 0040161D nop 0040161E nop 0040161F ror bx, 2 00401623 nop 00401624 nop 00401625 nop 00401626 nop 00401627 nop 00401628 add bx, 3030h 0040162D nop 0040162E nop 0040162F nop 00401630 nop 00401631 cmp word ptr ds:byte_403081+4, bx 00401638 nop 00401639 nop 0040163A nop 0040163B jnz short loc_40166EÉtant donné que l'on a incrémenté edx, ecx est égal à 6 en 004015FF. En 403081+4, se trouvent les caractères 14 et 15, pour iorior, 3060h. Ce qui en ascii fait: `0 voici donc un des nombreux serials possibles pour iorior: 12345Ëþ„7™ŸD™`0 On peut passer au keygen, sur les mêmes principes. V Le keygen Il existe beaucoup de possibilités, j'ai pris le parti d'obtenir les auto-patchs 90902AEBh et 90904290h, mais on peut en choisir d'autres... Voici donc mes sources: dans .data : buffer db 100 dup (0) serial db 31h,32h,33h,34h,35h,8 dup (33h) ,0,0,0 key db 4 dup (0)et donc: pushad lea EAX, buffer ; le nom push eax call lstrlen ; longueur du nom dans eax cmp EAX, 4 jng trop_court xor ebx, ebx mov ecx, eax ;longueur du nom dans ecx (compteur) mov esi, offset buffer @@1: lodsb add ebx, eax ; somme des caracteres du nom loop @@1 mov eax, 3785015fh ;à 3785015fh on soustrait la somme des caractères sub eax, ebx mov ecx, offset serial+5 mov [ecx], eax mov ecx, offset buffer mov al, [ecx] ; routine de merde pour que mov byte ptr [key+3], al ; les bytes soient dans le bon ordre mov al, [ecx+1] mov byte ptr [key+2], al mov al, [ecx+2] mov byte ptr [key+1], al mov al, [ecx+3] mov byte ptr [key], al mov eax, dword ptr [key] and eax, 0F0F0F0Fh adc eax, 90904290h ; ça c'est du reverse d'algorithme! ; y avait un sub, je mets un adc ;) mov ecx, offset serial+9 mov [ecx+3], al ror eax,8 mov [ecx+2], al ror eax,8 mov [ecx+1], al ror eax,8 mov [ecx], al ror eax,8 mov ecx, 6 mov esi, offset serial ; ensuite c'est du rip ;) xor ebx, ebx xor eax, eax @@3: lodsb add ebx, eax loop @@3 and bx, 0F0F0h ror bx, 2 add bx, 3030h mov ecx, offset serial+13 mov [ecx], bx popad jmp bravoCoolviper a dit que c'était pas ce qui était prévu (le 909020EBh), et que j'avais exploité une faille dans l'algorithme. Et bien s'il ne veut pas que j'exploite des failles, une seule solution: il n'en laisse pas. ;o) Voilà, c'est tout. A+ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Mes remerciements vont à: (Greets to:) Amante4, Christal, +DaFixer, Demonaz, El.CaRaCoL, Eternal Bliss, Falcon, F@t@lity, +FP, H@lloWin___HiA, Iczelion, Lancelot, La main rouge (PP), Lutin Noir, Morgatte, Muad'Dib, MrPhilex, Pulsar, r!sc, St Thomas, +Spath, SyntaxError, Tamambolo, Teeji, Tornado, The Analyst, The Egoiste, +Tsehp, Volatility, et tous les autres... iorior © 2001 |