Amusons-nous avec l'assembleur .... (ACDSee v2.xx)
Par Nody
Logiciel : ACDSee 2.xx (la 2.22 est utilisée ici)
Source : très facilement trouvable
Type de crack : méthode brutale pour choper un s/n
Niveau : apprenti
Outils : Soft-Ice, éditeur hexa pour sauver le boulot, du temps, un peu de connaissance de l'asm
Intro.
ACDSee est un logiciel de visualisation d'images que tout le monde connait, et utilise, ne serait-ce que pour mater les images XXX illégallement importées d'Internet.
Il y a une Dialog Box qui se pointe de temps en temps et qui nous demande de nous enregistrer.
Cracker cette Dialog Box est assez simple, et ça a été développée dans d'autres tuts. de mes confrères cracker. Nous on va faire autre chose : choper le bon s/n.
Attention !!!
Ce texte que vous lisez est un COURS, pour tenter de mieux comprendre l'assembleur. Si vous pensez avoir devant les yeux une méthode rapide et simple pour avoir votre s/n personnel pour ACDSee, c'est raté, allez plutôt sur un site warez, et cherchez-y un générateur, ou mieux encore, achetez-le...
Reverse enginering d'ACDSee.
Tout d'abord, démarrez ACDSee, et allez jusqu'à la Dialog Box de saisie du nom et du s/n.
Mettez le nom que vous voulez (j'ai mis "Nody CFC") et le reg. code de votre choix. Mettez un "bpx getwindowtexta" sous Soft-Ice et appuyez sur OK : on tombe 2 fois sous SI.
Comme je suppose que vous savez tracer un prog. (ou au moins l'utilisation des commandes "d" et "?" sous SI), je vous donne la source :
Il y a les commentaires à côté :
:00405C68 56 push esi
:00405C69 FFD7 call edi ; edi = GetDlgItemTextA
:00405C6B 8D44247C lea eax, dword ptr [esp+7C];eax = reg code
:00405C6F 8D4C243C lea ecx, dword ptr [esp+3C];ecx = nom
:00405C73 50 push eax ;sauvegarde du nom et du
:00405C74 51 push ecx ;regcode sur la pile
:00405C75 E846F8FFFF call 004054C0 ;routine de vérification
:00405C7A 83C408 add esp, 00000008 ;décale la pile de 8
:00405C7D 85C0 test eax, eax ; eax = 0 ?
:00405C7F 7E6B jle 00405CEC ; si oui on saute (bad boy)
:00405C81 8D54247C lea edx, dword ptr [esp+7C]
:00405C85 8D44243C lea eax, dword ptr [esp+3C]
:00405C89 52 push edx
:00405C8A 50 push eax
:00405C8B E8D0F9FFFF call 00405660
:00405C90 8B0D18A94A00 mov ecx, dword ptr [004AA918]
:00405C96 83C408 add esp, 00000008
:00405C99 85C9 test ecx, ecx
:00405C9B 7405 je 00405CA2
:00405C9D 8B11 mov edx, dword ptr [ecx]
:00405C9F FF5208 call [edx+08]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405C9B(C)
|
:00405CA2 8B0D14A94A00 mov ecx, dword ptr [004AA914]
:00405CA8 85C9 test ecx, ecx
:00405CAA 7405 je 00405CB1
:00405CAC 8B01 mov eax, dword ptr [ecx]
:00405CAE FF5014 call [eax+14]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405CAA(C)
|
* Possible Reference to String Resource ID=00001: "View"
|
:00405CB1 6A01 push 00000001
:00405CB3 56 push esi
* Reference To: USER32.EndDialog, Ord:00B4h
|
:00405CB4 FF15B8FB4A00 Call dword ptr [004AFBB8]
:00405CBA 6A00 push 00000000
:00405CBC 6810574000 push 00405710
:00405CC1 56 push esi
* Reference To: USER32.GetParent, Ord:011Dh
|
:00405CC2 FF15BCFB4A00 Call dword ptr [004AFBBC]
:00405CC8 8B0D1CA94A00 mov ecx, dword ptr [004AA91C]
:00405CCE 50 push eax
:00405CCF 68E4000000 push 000000E4
:00405CD4 51 push ecx
* Reference To: USER32.DialogBoxParamA, Ord:008Eh ; merci d'avoir acheter ACDSee
|
:00405CD5 FF151CFC4A00 Call dword ptr [004AFC1C]
* Possible Reference to String Resource ID=00001: "View"
|
:00405CDB B801000000 mov eax, 00000001
:00405CE0 5F pop edi
:00405CE1 5E pop esi
:00405CE2 5B pop ebx
:00405CE3 81C468020000 add esp, 00000268
:00405CE9 C21000 ret 0010
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405C7F(C)
|
* Possible StringData Ref from Data Obj ->"ACDSee 32"
|
:00405CEC 8B1524F24900 mov edx, dword ptr [0049F224]
:00405CF2 6A00 push 00000000
:00405CF4 52 push edx
* Possible StringData Ref from Data Obj ->"Your name and registration code "
->"do not match."
|
:00405CF5 688CF44900 push 0049F48C
:00405CFA 56 push esi
* Reference To: USER32.MessageBoxA, Ord:0195h ; vilain garçon
|
:00405CFB FF1538FA4A00 Call dword ptr [004AFA38]
* Possible Reference to Menu: MenuID_0082
|
* Possible Reference to String Resource ID=00130: "Total %d files (%s)"
|
:00405D01 6882000000 push 00000082
:00405D06 56 push esi
* Reference To: USER32.GetDlgItem, Ord:00F3h
|
:00405D07 FF1510FC4A00 Call dword ptr [004AFC10]
:00405D0D 50 push eax
* Reference To: USER32.SetFocus, Ord:01F5h
|
:00405D0E FF1520FC4A00 Call dword ptr [004AFC20]
* Possible Reference to String Resource ID=00001: "View"
|
:00405D14 B801000000 mov eax, 00000001
:00405D19 5F pop edi
:00405D1A 5E pop esi
:00405D1B 5B pop ebx
:00405D1C 81C468020000 add esp, 00000268
:00405D22 C21000 ret 0010 ; bye bye
Il y a donc un simple test de flag, qui nous envoie chier. Quand vous arrivez sur le test eax, eax en 00405C7D, sous SI, mettez 1 dans eax (r eax=1), et par enchantement, la version est enregistrée. Ne vous faites pas d'illusion, en redémarrant ACDSee la prochaine fois, vous verrez qu'elle n'est toujours pas enregistrée.
Nous savons que le call 004054C0 en 00405C75, a besoin de 2 paramètres placés sur la pile juste avant : c'est le push ecx qui contient le nom entré et le push eax qui contient le reg code. Si vous essayez de tracer cette routine, au début vous vous direz que c'est facile, puis après que c'est chiant, et enfin, vous irez prendre une aspirine, après vous être perdu dans le code asm.
J'ai passé pas mal de temps à essayer de choper mon s/n, mais ça m'a assez pris la tête et j'ai préféré utiliser une méthode brutale.
En fait, ACDSee ne créé pas le bon s/n en fonction du nom et le compare au s/n entré, mais il fait la démarche inverse : il chope le s/n que vous avez entré, recompose une partie du nom avec, et le compare au nom entré.
C'est parti, accrochez-vous :
:00405C6B 8D44247C lea eax, dword ptr [esp+7C];eax = reg code
:00405C6F 8D4C243C lea ecx, dword ptr [esp+3C];ecx = nom
En esp+7c, on a le s/n et en esp+3c, on a le nom. Evidement, le nom, on s'en tape pas mal. C'est le s/n qu'on va modifier à chaque passage tel que s/n := s/n + 1. Il y a un problème qui se pose d'entrée : esp+7c ne contient pas le s/n en tant que tel mais le code ASCII du s/n, donc il faudra écrire une routine en asm qui teste si le caractère est égale à ";" (code ASCII de ";" est 0x3A = 0x39+0x01 et 0x39 'est le caractère 9), et si il est égale à ";", on le remet à 0, et on incrémente le caractère à côté (par exple si on a "39", ça donnera "3;" après incrémentation du caractère à droite, et notre routine le transformera en "40" , OK ??).
Il faut tout d'abord connaitre le nombre de caratères qui compose notre s/n : on va utiliser ecx comme compteur :
(1):
: mov ecx, 0000000A ; ecx = 0x0A = 10
: dec ecx ; ecx := ecx - 1
: mov al, byte ptr [esp+ecx+7C] ; cf ci-dessous
: cmp eax, 00000000
: je (1)
Détails :
s/n : 1 2 3 4 5 6 7 8 9 0
pointe en : [esp+7c] [esp+7d] etc .....
Or [esp+7d] = [esp+7c+1], d'où l'utilisation du compteur ecx [esp+7c+ecx].
On initialise ecx à 10 (9 en fait car on a un dec ecx juste après) pour que le compteur n'aille pas au-delà de 9 caractères ie 9'999'999'999 au max. Evidemment, ce paramètre est modifiable.
Comme ça après ce premier algo, on a dans ecx le nombre de caractères qui composent notre s/n. Il reste plus qu'à l'incrémenter :
(2):
: push ecx ; sauvegarde le nbre de caract. de notre compteur sur la pile
: inc eax ; eax:=eax+1 ie incrémentation du caratère à droite
: mov byte ptr [esp+ecx+00000080], al ; le replace en [esp+7c]
: cmp eax, 0000003A ; compare le caractère à ";"
: jne bye_bye ; pas égal <=> on le renvoit dans la routine de vérif' d'ACDSee
: mov byte ptr [esp+ecx+00000080], 30 ; égal ? On le remplace par 0 (0x30 en ASCCII !!)
: dec ecx / on vérifie tous les chiffres car après 1699, on
: cmp ecx, FFFFFFFF / a 1700, donc il faut incrémenter 3 caractères !!
: je routine_3 /
: xor eax, eax /
: mov al, byte ptr [esp+ecx+00000080] /
: jmp (2) /
Attention : on a mis ecx sur la pile, ecx est un registre 32 bits donc 4 octets, donc on a déplacer la pile de 4 octets, d'où on a un mov byte ptr [esp+ecx+80] au lieu de mov byte ptr [esp+ecx+7C] !!!! (0x80 = 0x7C + 0x04)
La routine_3 est une routine spéciale qui permet de passer de 999 à 1000 par exemple :
: pop ecx ; restaure la pile
: mov [esp+ecx+7D], 30 ; met un "0" en plus à droite
: mov al, byte ptr [esp+7C] ; incrémente le chiffre le plus
: inc eax ; à gauche.
: mov byte ptr [esp+7C], al ; et le replace en [esp+7c]
: jmp vérif ; retour à la routine de vérif'.
Il y a également la routine bye_bye :
: pop ecx ;restaure la pile
: jmp vérif ; retour à la routine de vérif'.
Evidement, pas question d'écrire ça avec son pauvre éditeur hexa, Soft-Ice nous permet d'assembler notre code à l'aide de la commande "a [adresse]".
Voici la source complête du reverse enginering d'ACDSee v2.22 avec les offsets (à assembler directement sous SI !!!). En noir : le code original et en rouge les offset modifiés.
Version (à peine) modifiée d'ACDSee v2.22 (acdsee32.exe)
:00405C68 56 push esi
:00405C69 FFD7 call edi edi = GetDlgItemTextA
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00405D01(U), :00405D12(U)
|
:00405C6B 8D44247C lea eax, dword ptr [esp+7C] ; eax = reg code
:00405C6F 8D4C243C lea ecx, dword ptr [esp+3C] ; ecx = nom
:00405C73 50 push eax ; sauvegarde
:00405C74 51 push ecx
:00405C75 E846F8FFFF call 004054C0 ; vérif'
:00405C7A 83C408 add esp, 00000008
:00405C7D 85C0 test eax, eax ; teste le reg code
:00405C7F 7E0F jle 00405C90 ; saute si pas bon
:00405C81 6A00 push 00000000 ; mettre un bpx ici
:00405C83 E84278B8BF call BFF8D4CA ; call ExitProcess
:00405C88 90 nop ; = il a trouvé le bon reg
:00405C89 90 nop ; code et il est dans [esp+7c]
:00405C8A 50 push eax
:00405C8B E8D0F9FFFF call 00405660
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405C7F(C)
|
* Possible Reference to String Resource ID=00010: "Launch - Edit"
|
:00405C90 B90A000000 mov ecx, 0000000A ; début de notre routine
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405C9F(C)
|
:00405C95 49 dec ecx
:00405C96 8A440C7C mov al, byte ptr [esp+ecx+7C]
:00405C9A 3D00000000 cmp eax, 00000000 ; explication en haut
:00405C9F 74F4 je 00405C95
:00405CA1 51 push ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405CC8(U)
|
:00405CA2 40 inc eax
:00405CA3 88840C80000000 mov byte ptr [esp+ecx+00000080], al
:00405CAA 3D3A000000 cmp eax, 0000003A
:00405CAF 7560 jne 00405D11
:00405CB1 C6840C8000000030 mov byte ptr [esp+ecx+00000080], 30
:00405CB9 49 dec ecx ; explication en haut
:00405CBA 83F9FF cmp ecx, FFFFFFFF
:00405CBD 7433 je 00405CF2
:00405CBF 33C0 xor eax, eax
:00405CC1 8A840C80000000 mov al, byte ptr [esp+ecx+00000080]
:00405CC8 EBD8 jmp 00405CA2
:00405CCA 1CA9 sbb al, A9 ; pas à moi !
:00405CCC 4A dec edx
:00405CCD 005068 add byte ptr [eax+68], dl
:00405CD0 E400 in al, 00
:00405CD2 0000 add byte ptr [eax], al
:00405CD4 51 push ecx
* Reference To: USER32.DialogBoxParamA, Ord:008Eh
|
:00405CD5 FF151CFC4A00 Call dword ptr [004AFC1C]
* Possible Reference to String Resource ID=00001: "View"
|
:00405CDB B801000000 mov eax, 00000001
:00405CE0 5F pop edi
:00405CE1 5E pop esi
:00405CE2 5B pop ebx
:00405CE3 81C468020000 add esp, 00000268
:00405CE9 C21000 ret 0010
* Possible StringData Ref from Data Obj ->"ACDSee 32"
|
:00405CEC 8B1524F24900 mov edx, dword ptr [0049F224]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405CBD(C)
|
:00405CF2 59 pop ecx
:00405CF3 C6440C7D30 mov [esp+ecx+7D], 30
:00405CF8 8A44247C mov al, byte ptr [esp+7C] ; routine 3
:00405CFC 40 inc eax
:00405CFD 8844247C mov byte ptr [esp+7C], al
:00405D01 E965FFFFFF jmp 00405C6B
:00405D06 90 nop
:00405D07 90 nop
:00405D08 90 nop
:00405D09 90 nop
:00405D0A 90 nop
:00405D0B 90 nop
:00405D0C 90 nop
:00405D0D 90 nop
:00405D0E 90 nop
:00405D0F 90 nop
:00405D10 90 nop
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405CAF(C)
|
:00405D11 59 pop ecx
:00405D12 E954FFFFFF jmp 00405C6B
:00405D17 7C00 jl 00405D19 ; pas à moi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00405D17(C)
|
:00405D19 5F pop edi
:00405D1A 5E pop esi
:00405D1B 5B pop ebx
:00405D1C 81C468020000 add esp, 00000268
:00405D22 C21000 ret 0010
On sait que le jle en 0x00405C7F ne saut pas quand il a le bon s/n, c'est pourquoi juste après j'ai rajouté un call ExitProcess. Il suffit de mettre un bpx sur la ligne avant ce call ExitProcess. Pourquoi ?? Vous allez entrer votre nom et votre s/n de départ (je vous conseille de commencer à 1'000'000'000), puis à partir de ce moment, il va boucler, et boucler .... jusqu'à ce qu'il trouve le bon s/n et quand ça sera fait, le bpx posé permettra de stopper le programme et par la même occcasion vous pourrez admiré le bon s/n d'ACDSee à l'aide d'un "d esp+7c".
Je vous prévient : c'est assez long. Sur mon humble K6-2 300 avec 32 Mo de SDRam, il balance 28600 s/n par seconde, et le mien était :
nom : Nody CFC
s/n : 1130904563
Donc il a dû balancer 130'904'563 s/n, soit 1h16 avant de le chopper !!!
Evidemment, vous pouvez sauvegarder ce travail à l'aide d'un éditeur hexa en éditant une copie d'acdsee32.exe.
Ce genre de cours est assez difficile à expliquer donc si vous avez des questions à poser, faites-le !!!!
Merci à :
+Frog's Print
+Fravia
Cyberbobjr
La Main Rouge
ATP Team
le futur CFC.