CD QUICKCACHE 3.21 / KeyGen
par Alsindor / ATP Team
Bonjour tous le monde...
Voici donc ma réponse au défi du mois d'août de la main rouge.
Je vais essayer de vos décrire quels furent mes raisonnements lors du crack...
Il y a donc la réponse au défi, mais aussi (et surtout?) mes erreurs...:)
Ce n'est donc pas forcément un tut au sens strict du terme...
Avant de commencer, je tiens à remercier Nody pour son défi et Frog's Print+ pour avoir répondu
à mes questions. Et enfin un petit bonjour à Pass Partout avec qui nous avons échangé qq points
de vue...;)
Pour ceux qui aiment bien avoir un plan pour tout...Voici comment est organisée cette page...
1 - Byte Patch (qq idées)
2 - Comment trouver la routine du SERIAL
3 - Le Keygen
Voili, voilà....
Donc...on installe le prg, il nous demande de rebooter afin qu'il puisse prendre effet....
Hum...j'ai d'abord envie de voir de quoi çà cause...:)
Je réponds donc "NON"...Qu'est-ce qu'il y a dans le répertoire...2 fichiers EXE...Hum...
CDTEST n'a pas l'air d'être le prg en question...Je lance alors QuickMon.EXE.
Il se lance sans pb...je trifouille un peu...pas de limitations apparante...Pas de possibilité
de s'enregistrer...Bref, pas de matière à travailler...:(
Je décide alors de relancer mon ordi pour voir ce qui change...
Et là, surprise un zoli Nag apparait....Cool...on peut s'enregistrer...:)
Je commence toujours par le SERIAL, mais afin que vous lisiez ce texte jusqu'au bout, je vais
commencer par l'approche du BYTE PATCH qui m'a permise d'apprendre différentes choses...
Je n'ai pas approfondi cette méthode, car je n'avais pas bcp de temps, et d'autre part,
la méthode du SERIAL est quand même relativement simple pour ne pas avoir à patcher.
Aussi, je ne traiterai pas du time limit, car je n'ai pas eut le temps de vérifier si le patch
fonctionnait aussi pour ce dernier.
Donc....J'ai ce foutu Nag sous les yeux...Je vais donc essayer de breaké dessus.
Sous soft-ice, je liste toutes les TASKS qui sont en cours....Je trouve alors QuickMon.
Hwnd Quickmon ne me donne pas grande satisfaction....
Car il n'y a pas de 'dialog' (dans la colonne Class Name), et quand même, le nag que j'ai devant
moi ressemble bcp à une dialogbox.
Bref, après avoir réfléchi un peu...Après tout, soft-ice, lui ce qu'il veut, c'est le handle
de la fenêtre...Donc, je lance Win_frog, ou n'importe quel autre analyseur de fenêtres qui
affiche les caractéristiques d'une fenêtre choisie, et surtout dans notre cas, son Handle.
Une fois que vous avez ce numéro magique, HWND HANDLE sous soft-ice nous donne une réponse
plutôt sympathique....Puisque cette fois-ci nous avons comme CLASS un 'dialog' :)
Bref, on place un BMSG NUMéRO_HANDLE WM_COMMAND afin de breaker quand on appuie sur CONTINUE.
On clique, après qq F12 on attérie dans un fichier qui se nomme VCDQD32 !!
Hum....On laisse continuer le prg. Une petite recherche sur notre HD permet de trouver ce fichier
qui est en fait une DLL dans le répertoire SYSTEM de Windows.
Mais si vous avez fait tourner FILEMON avec QuickMon, vous avez du vous apercervoir que QuickMon
ne fait pas appel à cette DLL :(
Mais bon, gardons espoir...
On désassemble vite fait cette DLL, avec WDASM32 par ex.
Un petit tour rapide du côté des strings ref permet de comprendre qu'il s'agit là de notre
fichier. C'est lui qui semble gérer la protection du Nag.
Mais alors, quickmon dans tout çà?
Et bien comme le dit si bien la doc:
"CD-Quick Cache's QuickMon utility lets you monitor and control
the operation of CD-Quick Cache. Running QuickMon is completely
optional, the cache will run the same with or without it."
DONC....il faut lire la doc...:)
Bref...On laisse tomber QuickMon. En revanche, CDTEST se révèle être un précieux ami, car
en fait c'est lui qui va nous permetre de savoir si les patchs sont corrects ou pas.
Je vous conseille donc de le lancer sans aucune modifications de votre part, pour voir comment
le prg se comporte. Ainsi, vous pourrez plus facilement vous rendre compte si ce que vous
proposez est correct ou pas.
Dans les strings Refs, on aperçoit qq chose de TRES intéressant !!
\\.\VCDQD.VXD
Ah...Le prg utiliserait un VxD? Ce qui en fait parait logique pour un prg de sa nature...
Puisqu'il gère les acces aux fichiers de manière assez "basse", et donc, qui d'autre à part un
VxD pouvait avoir accès à ce genre de niveau.
Donc voilà un nouveau candidat pour nos futures analyses...
De plus, il existe des fonctions exportées...c'est à dire utilisables par d'autres prg, le VxD
par exemple... ;-)
L'une d'entre elle s'appelle SplashWindow... Etrange non ?
Sinon, si vous avez eut la bonne idée d'analyser cette DLL avec un éditeur de resources...
Vous y trouverez le zoli Nag :)
La question alors est de savoir qui fait quoi entre ces deux fichiers...?
Sont ils nécessaires tous les 2?
Remarque: Je n'ai pas trouvé de moyen de refaire apparaître le nag sans redémarrer...:(
J'ai utilisé le FPLoader, mais sans succès.
Si vous savez comment faire merci de m'envoyer un mail....:)
A première vue, le VxD charge la DLL en mémoire et utilise certaines de ses fonctions comme
ce charmant SplashWindow :)
Afin de tester si le VxD est indispensable, il suffit de l'enlever du répertoire
windows\system\iosubsys
En effet, tous les VxD qui s'y trouvent sont exécutés lors du lancement de Windows.
Relancement de la machine, mais on nous indique que QuickCache n'a pas été chargé correctement.
Replacement alors du VxD à sa place et on change le nom de la DLL. Mais là encore on nous signale qu'il y a un problème.
Une petite tentative afin de se débarasser de ces avertissements donne:
-Pour éviter que l'abscence du VxD soir notifier, on regarde dans QuickMon comment cela se passe.
C'est un CreateFileA sur VCDQD.VXD. On change le résultat mais, cela plante plus tard
car il ne trouve pas certains fichiers tampons. Bref, on laisse tomber. De plus, vu ce qu'il y a dans la DLL il y a fort à parier que sa présence ne soit pas forcément nécessaire....
-Pour l'abscence de la DLL, on désassemble le fichier VxD avec IDA. Et oui...:)
Car sinon WDASM32 s'y perd complètement....
On fait une recherche de texte sur VCDQD32.DLL, et on trouve la phrase qui est affiché
au démarrage de l'ordi quand la DLL n'est plus là.
Hum...on remonte (en cliquant sur la location)...
On y trouve qq chose comme:
CALL1
TEST
JZ
CALL MESSAGE D'ABSCENCE
Le CALL1 n'est pas appelé par d'autres endroits...C bon signe...
On affiche le code en hexa, ce qui permet de faire une recherche sous votre éditeur HEXA
préféré. On change donc le saut et on y place un JMP.
Donc, on change le nom de la DLL (ce qui évite de l'effacer elle aussi) et on reboot.
Pas de message qui nous indique qu'il manque quoi que ce soit. En revanche, cette méthode
ne passe pas le cap du CDTEST :(
Bon, peut être alors que la DLL est nécessaire, mais que cette fonction SplashWindow ne l'est pas.
On place alors au tout début de cette fonction un RET ou encore C3 en HEXA.
Mais là encore, ce n'est pas la bonne solution.
Il va donc falloir procéder autrement...:)
Une dialogbox, pour qu'elle s'affiche, on doit faire appel à des API...Hum...
Un petit tour du côté des fonctions Importées du VCDQ32.DLL nous permet de trouver une API
bien sympathique...CreateDialogBoxIndirectParamA...De plus, il n'y a qu'une seule occurence...
Niark...Niark....:)
Voici le 'code snippet' correspondant:
:10012F0B 33C0 xor eax, eax
:10012F0D EB0B jmp 10012F1A
:10012F0F 8D4DBC lea ecx, dword ptr [ebp-44]
:10012F12 E961500000 jmp 10017F78
:10012F17 8B401C mov eax, dword ptr [eax+1C]
:10012F1A 6A00 push 00000000
:10012F1C 68922B0110 push 10012B92
:10012F21 50 push eax
:10012F22 FF7508 push [ebp+08]
:10012F25 FF7510 push [ebp+10]
:10012F28 FF15A8A80210 Call CreateDialogIndirectParamA
:10012F2E 8945D8 mov dword ptr [ebp-28], eax
Un petit tour du côté de votre win32.hlp, permet de remarquer que si la fonction échoue,
EAX=0.... En 10012f0D il y a un JMP qui saute au tout début du passage de paramètres de la boîte
de dialogue, pourquoi ne pas le changer pour qu'il pointe après...En :10012f2E par exemple...:)
Et voilà...plus de nag!! :)
Bon....mais comme je vous le disais ci-dessus...Ce n'est pas vraiment la méthode que j'ai
utilisé. On va donc maintenant passer au SERIAL...:)
Bon, on se trouve devant le nag, on clique sur "ENTER KEYCODE"...
On rentre comme d'hab n'importe quoi...
Sous soft-ice, on place alors notre filet....GetDlgItemTextA et GetWindowTextA...
La première ne break pas, et la deuxième break tout le temps et surtout sous Quickmon....:(
Hum....on va donc utiliser quelque chose d'autre...BPX HMEMCPY...
On remarque alors qu'il break 2 fois...:) Lors du deuxième break, F12 nous permet d'attérir ici:
:100199F2 FF15C0A80210 Call GetWindowTextA
:100199F8 6AFF push FFFFFFFF On arrive ici...:)
:100199FA 8B4D10 mov ecx, dword ptr [ebp+10]
:100199FD E8F5D4FFFF call 10016EF7
:10019A02 EB0B jmp 10019A0F
:10019A04 8B4510 mov eax, dword ptr [ebp+10]
:10019A07 FF30 push dword ptr [eax]
:10019A09 56 push esi
:10019A0A E8F3F6FFFF call 10019102
:10019A0F 5F pop edi
:10019A10 5E pop esi
:10019A11 5D pop ebp
:10019A12 C20C00 ret 000C
On trace donc afin de trouver qq chose d'interessant....
Après le RET en :10019A12 on arrive en :10001151 puis en :10015AF4 puis :10013434.
A cette adresse, il y a un CALL/TEST/Jxx mais il ne semble pas être le seul dans les parages...
En effet, plus on trace et plus il y a des sauts conditionnels dans tous les sens...
Ce n'est donc pas comme çà qu'il va falloir procéder....
Petit rappel....
Quand on crack, plus on se trouve AU DEBUT de la protection MIEUX c'est...
Evidemment, pas la peine de se situer tout au début du prg...'indeed !!'
Autre rappel... quand on demande un SERIAL, voici comment en gros cela fontionne:
1:Demande du SERIAL
2:Vérification
3:Affichage
a:Si mauvais SERIAL->retourne à l'étape 1
b:Si bon->termine la routine du serial, et passe en mode 'registered'
Donc, la majorité du temps, quand on pose des BP tels que GetDlgItemTextA, c'est que l'on
essaye de se placer juste avant l'étape 2.
MAIS....MAIS....on peut procéder différemment...En effet, on peut breaker sur l'affichage
du Mauvais SERIAL, puis tracer petit à petit, pour retourner à l'étape 1.
Comme ca on se place TOUT EN HAUT de la routine du SERIAL !!
Et si on continue à tracer, on arrivera FORCEMENT à l'étape 2 !!!
Car c'est vraiment elle qui nous intéresse (surtout pour le calcul du SERIAL).
Cette technique fonctionne essentiellement quand après vous avoir indiqué que votre SERIAL
n'était pas bon, il réaffiche la Reg.Box.
Maintenant la pratique...:)
Quand on clique sur "OK" et que l'on ne possède pas (encore!) le bon code, une fenêtre appartait
nous informant que ce n'est pas correct.
On va donc essayer de breaker au moment de l'affichage. On commence par le plus simple...
BPX MessageBoxA Yep...Yep...Ca fonctionne....:)
On arrive ici...:
:100028D9 E843740100 call 10019D21 Après MessageBoxA
:100028DE C645FC00 mov [ebp-04], 00
:100028E2 E89A000000 call 10002981
:100028E7 EB35 jmp 1000291E
...
:1000291E 8D8D7CFFFFFF lea ecx, dword ptr [ebp+FFFFFF7C]
:10002924 E8AE070100 call 100130D7 Affiche Reg.Box
:10002929 83F801 cmp eax, 00000001
:1000292C 0F8445FFFFFF je 10002877
:10002932 C745FCFFFFFFFF mov [ebp-04], FFFFFFFF
:10002939 E86F000000 call 100029AD
:1000293E 8B45F4 mov eax, dword ptr [ebp-0C]
:10002941 8BE5 mov esp, ebp
:10002943 64A300000000 mov dword ptr fs:[00000000], eax
:10002949 5D pop ebp
:1000294A C3 ret
Donc....en :10002924 on trouve l'affichage de la registration box, l'étape 1 de tout à l'heure.
On saute ensuite en :10002877...
:10002877 8D45DC lea eax, dword ptr [ebp-24]
:1000287A 8B4DE0 mov ecx, dword ptr [ebp-20]
:1000287D 50 push eax
:1000287E E8FA430100 call 10016C7D
Hum....quand on édite EAX on tombe sur un chiffre étrange....
Je vous conseille de configurer votre fenêtre DATA sous soft-ice pour qu'il affiche en
DWORD. Pour cela taper DD puis refaire la même chose.
Vous obtenez alors un truc du style 0061231C...Hum...Cela ne vous dit rien?
Personellement je trouve que cela ressemble à une adresse mémoire...:)
Donc, pour savoir ce qu'il se trouve à cette adresse vous pouvez taper D 0061231C
ou taper D *EAX, ce qui revient au même.
On apperçoit alors notre NOM....!! De même pour ECX....
Nous sômmes donc maintenant à l'étape 2, au tout début...L'endroit idéale....:)
Voici la routine:
:10002883 8D45D8 lea eax, dword ptr [ebp-28] NAME
:10002886 8B4DE4 mov ecx, dword ptr [ebp-1C] NAME
:10002889 50 push eax
:1000288A E8EE430100 call 10016C7D ??
:1000288F 8B45E0 mov eax, dword ptr [ebp-20]
:10002892 8B08 mov ecx, dword ptr [eax]
:10002894 8379F800 cmp dword ptr [ecx-08], 00000000 Nom=0 ?
:10002898 750F jne 100028A9
:1000289A 8B45E4 mov eax, dword ptr [ebp-1C]
:1000289D 8B08 mov ecx, dword ptr [eax]
:1000289F 8379F800 cmp dword ptr [ecx-08], 00000000
:100028A3 0F8489000000 je 10002932
:100028A9 8B4DF0 mov ecx, dword ptr [ebp-10]
:100028AC E86D010000 call 10002A1E CALL
:100028B1 85C0 test eax, eax TEST
:100028B3 0F8C92000000 jl 1000294B Jxx Le trio infernal...:)
:100028B9 752E jne 100028E9
:100028BB 68DC340210 push 100234DC
:100028C0 8D4DE8 lea ecx, dword ptr [ebp-18]
:100028C3 E82A430100 call 10016BF2
:100028C8 6A10 push 00000010
:100028CA 8B4DF0 mov ecx, dword ptr [ebp-10]
:100028CD C645FC01 mov [ebp-04], 01
:100028D1 68D4340210 push 100234D4
:100028D6 FF75E8 push [ebp-18]
:100028D9 E843740100 call10019D21 Affiche Nag si Mauvais SERIAL
:100028DE C645FC00 mov [ebp-04], 00
:100028E2 E89A000000 call 10002981
:100028E7 EB35 jmp 1000291E
Bon...qu'est-ce qu'on apprend de cet extrait de code...?
Et bien qu'apparemment, c'est le CALL 10002A1E en :100028AC qui jouerait un rôle important...:)
En effet, les deux sauts conditionnels qui suivent sautent le CALL en :100028D9 qui affiche
la MessageBoxA.
On va donc l'étudier un peu plus en profondeur....
Voici où l'on attéri...:
:10002A1E B8882A0010 mov eax, 10002A88
:10002A23 E8A42E0000 call 100058CC Rien de bien intéressant...
:10002A28 83EC10 sub esp, 00000010
:10002A2B 56 push esi
:10002A2C 8BF1 mov esi, ecx
:10002A2E 8D4DE4 lea ecx, dword ptr [ebp-1C]
:10002A31 E8A3000000 call 10002AD9 Vérifie la présence du VxD
:10002A36 33C0 xor eax, eax
:10002A38 8945FC mov dword ptr [ebp-04], eax
:10002A3B 3945E4 cmp dword ptr [ebp-1C], eax
:10002A3E 7435 je 10002A75
:10002A40 FFB694000000 push dword ptr [esi+00000094] SERIAL
:10002A46 FFB698000000 push dword ptr [esi+00000098] NAME
:10002A4C 8D4DE4 lea ecx, dword ptr [ebp-1C]
:10002A4F E8C1000000 call 10002B15 intéressant....:)
Quelques petits détails....
Pour le premier CALL, quand je dit inintéressant, c'est que ca ne rentre pas en compte dans mon
explication....:)
Sinon, pour la vérification du VxD, c'est très classique...En dernier argument on PUSH le nom
du VxD et on CALL CreateFileA.
Bon, passons maintenant à une routine importante...Celle du CALL 10002B15 dont voici des
extraits de code:
:10002B2C FF750C push [ebp+0C] SERIAL
:10002B2F 51 push ecx DESTINATION
:10002B30 897DFC mov dword ptr [ebp-04], edi
:10002B33 FF156CA60210 Call lstrcpynA
:10002B39 FF7508 push [ebp+08] NAME
:10002B3C 8D957AFFFFFF lea edx, dword ptr [ebp+FFFFFF7A]
:10002B42 52 push edx DESTINATION
:10002B43 FF1578A70210 Call lstrcpyA
:10002B49 57 push edi
:10002B4A 8D4E04 lea ecx, dword ptr [esi+04]
:10002B4D 51 push ecx
:10002B4E 8D7DFC lea edi, dword ptr [ebp-04]
:10002B51 6A04 push 00000004
:10002B53 8D8574FFFFFF lea eax, dword ptr [ebp+FFFFFF74]
:10002B59 57 push edi
:10002B5A 6886000000 push 00000086
:10002B5F 50 push eax SERIAL/NAME
:10002B60 6A10 push 00000010
:10002B62 FF36 push dword ptr [esi]
:10002B64 FF15E4A60210 Call DeviceIoControl
Bon...Analysons un petit peu...
Le prg fait d'abord une première copie du SERIAL puis il duplique le NAME, pour
enfin les envoyer en paramètres au Vxd.
Hum....Il les envoie au Vxd....Mais pourquoi est ce qu'il les copie avant....?
S'il les copie c'est qu'il doit avoir une bonne raison non?
Pour en être sûr....bah BPM sur l'adresse de DESTINATION, pour le NAME et le SERIAL.
Une fois que vous steppez sur l'API DeviceIoControl, soft-ice break
autre part...le nom de la fenêtre est KERNEL32, F12, et on tombe dans VCDQ, mais il semblerait
que ce ne soit pas la DLL...Evidemment... C'est le VxD !!! :)
C'est logique puisque l'on a steppé sur DeviceIoControl et que cette
fonction permet d'envoyerdes paramètres au VxD que l'on désire, plus de détails dans votre guide
des API...
On a alors le code ci-dessous...:
00004E1F E8 EC E1 FF FF call sub_3010
00004E24 83 C4 08 add esp, 8 On arrive ici après F12
00004E27 85 C0 test eax, eax
00004E29 B8 01 00 00 00 mov eax, 1
00004E2E 75 18 jnz short loc_4E48
00004E30 53 push ebx SERIAL/NAME
00004E31 56 push esi NAME
00004E32 E8 A9 E2 FF FF call sub_30E0 intéressant non ??
00004E37 83 C4 08 add esp, 8
Il semblerait que le CALL sub_30E0 soit interessant...Non ??
ET bien non...!!! Il ne l'est pas...En effet malgrés les arguements qui sont PUSHéS sur la pile
juste avant, je vous rappelle que l'on attérit en 4E24 après le break de soft-ice....
DONC....!! C'est que l'on a touché à notre NAME ou SERIAL AVANTcette adresse....Donc dans
le CALL sub_3010 !!!!!
En voici qq extraits...:
sub eax, eax
...
mov edi, edx
repne scasb
not ecx
Ces quatre instructions permettent de connaitre la taille d'une chaine de caractères.
En locurrence, ici il s'agit de la taille du SERIAL (le zéro qui termine la chaine est lui
aussi compté).
mov esi, edi
lea edi, [esp+90h+var_80]
repe movsd
Recopie le SERIAL à une autre adresse mémoire pointée par EDI...
mov ecx, eax
and ecx, 3
repe movsb
Permet de terminer par un 0 pour former une chaine asciiz.
push eax
call sub_31A
mov bp, ax
Ce CALL permet d'obtenir le SERIAL dans AX, mais il permet aussi de faire différentes
vérification en ce qui concerne les espaces et autres caractères...
Puis le SERIAL est placé dans BP...Pourquoi ? Un peu de patience...
Ensuite il y a calcule de la taille du NAME, puis le recopie à un autre emplacement mémoire...
Tout comme le SERIAL....
loc_3090:
movsx ecx, byte ptr [esp+esi+90h+var_80]
inc esi
call sub_32A0
mov [esp+esi+90h+var_81], al
mov al, byte ptr [esp+esi+90h+var_80]
test al, al
jnz short loc_3090
Cette boucle permet de convertir le nom en majuscules....
push eax
call sub_31F0
On PUSH le nom que l'on vient de majusculiniser, et en ressortant on obtient le NAME à l'envers.
push eax
call sub_3260
xor ax, 0B375h
add esp, 4
cmp ax, bp
pop ebp
setz bl
Hum....Dernier CALL avant le RET....De plus il y a un autre trio infernal....CALL/CMP/SETx...
De plus, vous vous souvenez, le SERIAL que l'on a tapé se trouve dans BP, et là il est
comparé à AX....Hum...J'espère que vous sentez que l'on se rapproche petit à petit de la routine
de calcul du SERIAL....Bref...Allons regarder ce CALL sub_3260 de plus près....:)
00003260 push esi
00003261 33 C0 xor eax, eax
00003263 33 F6 xor esi, esi
00003265 8B 4C 24 08 mov ecx, [esp+arg_0]
00003269 38 01 cmp [ecx], al
0000326B 74 1C jz short loc_3289
0000326D
0000326D loc_326D:
0000326D 0F BE 11 movsx edx, byte ptr [ecx]
00003270 03 F2 add esi, edx
00003272 41 inc ecx
00003273 81 FE FF 00 00 00 cmp esi, 0FFh
00003279 72 06 jb short loc_3281
0000327B 81 EE FF 00 00 00 sub esi, 0FFh
00003281
00003281 loc_3281:
00003281 03 C6 add eax, esi
00003283 8A 11 mov dl, [ecx]
00003285 84 D2 test dl, dl
00003287 75 E4 jnz short loc_326D
00003289
00003289 loc_3289:
00003289 B9 FF 00 00 00 mov ecx, 0FFh
0000328E 2B D2 sub edx, edx
00003290 F7 F1 div ecx
00003292 66 C1 E2 08 shl dx, 8
00003296 66 0B D6 or dx, si
00003299 5E pop esi
0000329A 66 8B C2 mov ax, dx
0000329D C3 retn
Hum....Afin de mieux percevoir ce qu'il se passe je vous conseille de tracer pas à pas dans
cette routine...Et c'est aussi pour cela que je ne la détaille pas....:)
En gros, le prg prend chacune des lettres du NAME (pointé par ECX), place le code HEXA dans ESI
Si ESI est supérieur à FFh alors on retranche ESI de FFh.
Dans tous les cas ESI est ajouté par la suite à EAX.
Et enfin, quelques opérations afin d'avoir le vrai SERIAL dans DX qui est ensuite placé
dans AX.
Bon, mais n'oubliez pas qu'il y a encore une opération à faire sur le serial qui vient
d'être calculé avec la routine ci-dessus...En effet quand on ressort de ce CALL, on a un
xor ax, 0B375h...
Voilà, et bien après cette instruction, il ne vous reste plus qu'à regarder AX et de noter
sa valeur....Vous avez alors le SERIAL pour votre NAME.
Bon....Pour ceux qui veulent absolument un Byte Patch....Vous pouvez toujours modifier
le SETZ BL en SETNZ BL....:)
Nous arrivons maintenant à la troisième partie de cette page...
Le keygen.... !!! :)
Bon, je tiens à dire que je suis TOUT A FAIT D'ACCORD avec NODY en ce qui concerne les keygens.
Tout le monde devrait les écrire en ASM32...!!! (et pas en visual C++ 6.0 ...Hein Artex....;) )
Il y a suffisament d'Xcellents tuts sur le net pour que TOUT le monde puisse s'y mettre...!!!
De plus je pense que pour s'améliorer en CRACKING il faut programmer...
C'est peut être dur pour certains, mais malheureusement à un certain niveau crack et programming
se recoupent.
Bref...C'est votre vie, et si vous voulez cracker des CALL/TEST/Jxx toute votre vie c'est vous
que cela regarde...
Pour les autres bah il suffit de lire...;-)
Le keygen qui suit n'est pas écrit en TASM32 mais en MASM32.
Ca reste de l'assembleur, mais certaines choses diffèrent notamment au niveau de l'organisation
du prg et de la déclaration des API utilisées....De plus, il n'y a pas vraiment de grosses différences dans le code source qui suit.
Si vous désirez vous mettre à programmer en MASM32 je ne pourrais que vous recommender les
Xcellents tuts d'ICZELION !
Bon...Bref...continuons....
Vous trouverez ci-dessous le listing en ASM32 du keygen.
Quelques petites remarques au paravant....
1)j'ai décidé de commenter le code source, mais aussi d'expliquer le pourquoi du comment de
chaque ligne...C'est pour cela qu'il y a BCP de commentaires...
L'autre alternative aurait été de découper le listing en petits bouts pour expliquer
puis de remettre tout le listing en entier sans commentaires.
Mais bon, je pense que ce tut est assez long comme ca....:)
2)En ce qui concerne la création de la DialogBox avec un éditeur de resources...
En ce qui me concerne j'utilise Symantec Resource Studio 1.0.
Et je sauvegarde le tout en .RES puis je transforme le .RES en .OBJ grâce à CVTRES qui est
fournit avec MASM32.
Quand vous créez vous resources, le prg leur donnent d'abord un nom (genre IDC_blabla)
Mais bon, pour MASM, le nom lui il s'en fout...ce qu'il veut c'est une valeur.
Donc, pour se faire, sauvegarder votre chef d'oeuvre (toujours en .RES) puis réouvrez le, vous
verrez alors que tous les noms sont devenus des valeurs....:)
Ce sont ces valeurs que vous trouvez au début du listing dans la section .const
Ma DialogBox est composé de 3 bouttons: ABOUT, GENERATE et QUIT ainsi que d'un champ de saisie.
3)Une fois que vous avez votre .RES transformé en .OBJ, il ne vous reste plus qu'à linker
les deux ensembles....
Voici les lignes de commandes que j'ai tapé pour créer le fichier EXE:
ml /c /coff /Cp %1.asm
-> Afin de transformer le listing .ASM en .OBJ
%1 = votre nom de fichier pour le listing du prg en ASM32
link /subsystem:windows /libpath=d:\masm32\lib %1.obj %2.obj kernel32.lib user32.lib
-> Afin de linker les 2 .OBJ ainsi que les librairies pour les API.
%1 et %2 sont les deux noms de fichiers .OBJ
4)En ce qui concerne l'adaptation de la routine de CD Quick Cache, j'ai effectué plusieurs
modifications...
En effet, le prg convertie le NAME saisi en majuscules, on peut éviter cela en précisant quand
vous créez votre DialogBox sous votre éditeur de resources, que le champ de saisie est en
majuscules.
Pour la routine de calcul du SERIAL j'ai fait un copié/collé.
Mais la routine elle opère sur le NAME qui a été inversé, j'ai zappé cette routine et adapté
la routine du SERIAL pour qu'elle prenne le NAME à l'envers.
C'est parti....:)
;------------------------------------- CODE COMPILABLE ------------------------------------
;Keygen pour CDQUICKCACHE 3.21
;Codé en MASM32 par ALSINDOR / ATP Team
;1999
;
;Un petit coucou et merci à ARTEX, car nous avons fait
;la routine d'affichage du SERIAL ensemble ;-)
;J'attends ta version du keygen en Visual C++ 6.0 de 300Ko...:)
;
.386 ;Début habituel
.model flat, stdcall
option casemap:none
include d:\masm32\include\windows.inc
;------------------------- Liste des APIs utilisées ----------------
GetModuleHandleA proto :DWORD
ExitProcess proto :DWORD
DialogBoxParamA proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
MessageBoxA proto :DWORD,:DWORD,:DWORD,:DWORD
EndDialog proto :DWORD,:DWORD
GetDlgItemTextA proto :DWORD, :DWORD, :DWORD, :DWORD
;---------------------------------------------------------------------
.data
Boutton1Text db "Keygen pour CD QUICKCACHE 3.21 par Alsindor",0 ;Txt du boutton ABOUT
AppName db "CD QUICKCACHE KEYGEN",0 ;Nom de la MessageBoxA
Msg db "Votre Sérial est: ",0 ;phrase pour afficher
;le SERIAL
;Rmq:Des espaces ont été laissés afin de pouvoir écrire la clé directement dans cette chaine
;de caractères
.data?
hInstance HINSTANCE ? ;permet de sauvegarder le Handle du prg
Buffer LPTSTR ? ;permet de stocker le nom récupéré de la diaglogbox
.const
BT_ABOUT equ 3003 ;ID du boutton ABOUT
BT_GENERATE equ 3002 ; GENERATE
BT_QUIT equ 3004 ; QUIT
ID_DIALOGBOX equ 100 ;ID de la dialogbox
ID_EDIT equ 3001 ;ID du champ de saisie
;Ce sont donc ces valeurs que Resource Studio vous donne.
;Evidemment elles peuvent varier, il faut donc que vous les notiez... ;-)
.CODE
start:
;------------------------------------- Partie Principale du prg --------------------
invoke GetModuleHandleA, NULL ;on récupère le Handle du programme
mov hInstance,eax ;qu'on stocke car utilisé par la prochaine ligne...
invoke DialogBoxParamA, hInstance, ID_DIALOGBOX, NULL, ADDR DlgProc, NULL
;on affiche la dialogbox, avec comme paramètres principaux:le handle du prg et l'adresse de
;la routine qui s'occupe de gérer les msg qui lui seront envoyés.
invoke ExitProcess,eax ;on se casse...En sortant de la routine de la diaglogbox, EAX=0
;-------------------------------------------------------------------------------------
;------------------------------------ Les Routines -------------------------------------
DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lPARAM:LPARAM
;C'est cette routine que Windows appelera quand il y aura des évènements à prendre en compte,
;comme par exemple quand vous appuyez sur un boutton.
.IF uMsg==WM_COMMAND ;Si on a appuyé sur un Boutton, alors MSG=WM_COMMAND....
mov eax,wParam ;on récupère l'ID du boutton....
.IF eax==BT_ABOUT
invoke MessageBoxA ,NULL, OFFSET Boutton1Text, ADDR AppName, NULL
;on affiche la MessageBoxA avec le texte...
.ELSEIF eax==BT_QUIT
invoke EndDialog , hWnd, NULL
;on se casse....
.ELSEIF eax==BT_GENERATE
mov eax,hWnd ;le Handle de la dialogbox est un paramètre utilisé dans la
CALL Generate ;procédure Generate, mais n'est pas accéssible.
;on sauvegarde donc ce numéro de handle...:)
.ENDIF ;fin pour les choix de bouttons
.ELSEIF uMsg==WM_CLOSE ;dans le cas où l'utilisateur décide de fermer la diaglogbox
;autrement que par le boutton QUIT. La croix en haut à droite
;par Ex.
invoke EndDialog , hWnd, NULL
.ELSE
mov eax,FALSE ;si on a pas traité de msg, alors en sortie de cette routine
ret ;EAX DOIT être égal à 0
.ENDIF ;pour le wm_command
mov eax,TRUE ;si on a traité un msg, alors EAX DOIT être égal à 1
ret
DlgProc endp
Generate proc
;C'est cette routine qui est exécutée quand on appuie sur le boutton GENERATE.
;C'est elle qui fait tout....:)
;Récupération du NOM, calcul du SERIAL et affichage...
invoke GetDlgItemTextA, eax, ID_EDIT, OFFSET Buffer, 50h
;on récupère ce qui a été tapé dans le champ de saisie.
;Par défaut on dit que cela ne fera pas plus de 50 caractères max.
xor edx,edx ;sert pour garder le serial
xor eax,eax ;sert pour qq opérations
xor ecx,ecx ;sert pour le nombre de tours effectués dans la boucle
;on va d'abord calculer la longueur du NOM
;pour cela on va faire pareil que le prg...:)
mov edi,OFFSET Buffer ;on place l'addresse du message d'annonce du serial dans EDI
dec ecx ;on sait que ECX=0 donc si -1 alors ECX=ffffffffh :)
repne scasb ;permet de connaitre la taille de Buffer
not ecx ;permet de récupérer la taille+1 de la chaine..
dec ecx ;on corrige pour obtenir la vraie taille = sans le zéro de fin de chaine.
;mov edi, offset Buffer ;EDI a changé avec le repne scasb de ci-dessus...
;on le replace alors au bon endroit pour la suite...
; ; J'ai laissé cette routine car au début c'est comme cela que je faisais avant d'avoir
; ; découvert avec ARTEX la petite case 'Uppercase'....:)
;on va convertir le nom en majuscule....
;pour cela, on test si le code hexa est compris entre la lettre 'a' et 'z' si c'est le cas,
;on soustrait 32d afin de passer en majuscules...
;on sait que EDX = 0 et qu'il servira pour le compteur....
;debut_boucle:
;cmp byte ptr [edi], 97 ;lettre "a"
;jl not_good
;cmp byte ptr [edi], 122 ;lettre "z"
;ja not_good
;sub byte ptr [edi], 32 ;permet de passer de min en maj
;not_good:
;inc edi ;on passe à la lettre suivante
;inc edx ;on augmente le compteur
;cmp edx,ecx
;je fin_maj
;jmp debut_boucle
;fin_maj:
mov ebx,ecx ;sauvegarde la longueur...:)
dec edi ;On sait que EDI est à la fin de la chaine, mais il est positionné
dec edi ;APRES le zéro, on le replace alors sur la dernière lettre du NAME
mov ecx,edi ;on place l'adresse du NAME dans ECX
xor esi,esi ;doit être remis à zéro car on passe maintenant à la routine du
;calcul du serial. Et ESI est un accumulateur, donc s'il y a
;une valeur initiale, tout est faussé....
xor edx,edx ;idem
xor eax,eax ;idem
;petit rappel =>EBX = longeur du NAME
boucle_serial:
movsx edx, byte ptr [ecx]
add esi, edx
dec ecx ;avant c'était un INC ECX
cmp esi, 0FFh
jb trop_grand
sub esi, 0FFh
trop_grand:
add eax, esi
; mov dl, [ecx] ;c'était pour savoir si c'était terminé...
; test dl, dl
dec ebx ;fait la même chose...:)
jnz boucle_serial
mov ecx, 0FFh
sub edx, edx
div ecx
shl dx, 8
or dx, si
xor dx,0b375h
;quand on arrive ici, on a alors le SERIAL qui correspond au NAME dans DX
;On va alors placé chacun des caractères de ce SERIAL dans la chaine Msg qui sera ensuite
;affichée grâce à une MessageBoxA....
xor esi,esi ;sert pour le masque...
mov edi, offset Msg ;récupère l'adresse de la chaine asciiz...
add edi,18 ;place EDI au bon endroit dans la chaine...
mov cx, 4 ; 4 fois la boucle car serial de 4 'lettres'
mov bx,3 ;mais seulement besoin que de 3 déplacements puisqu'on commence
;par ca dans la boucle...
mov si, 0f000h ;masque qui sera bientôt utilisé
toto:
push DX ;savegarde le serial sur la pile pour le récupéré à la fin...
push CX ;sauvegarde la position car CX = numéro de la lettre du SERIAL
and dx, si ;on garde le premier caractère...
;Le AND sert pour MASQUER une partie du registre.
;Par ex. on a 7456, si on ne veut que le 7 on masque avec F000h
;Car DX = 7 4 5 6
; SI = F 0 0 0
; ------------
; AND= 7 0 0 0
;Après le 'AND DX, SI' on a DX = 7000 (par ex.) et nous on veut DX = 0007
;on effectue alors un décalage vers la droite...
;mais il est proportionnel du caractère que l'on traite....
;donc pour savoir on utilise le compteur CX qui lui reflète le numéro du caractère traité
mov ax,24h ;on multiplie par 24h pour décaler d'une unité le serial
push DX ;sauvegarde le résultat obtenu car DX=reste pour l'opération MUL
dec cx ;Pour le 4eme caractère il y a 3 décalages à faire, donc ECX-1
mul cx ;on obtient alors le nombre de décalages qu'il faut dans AL
mov cl,al ;on place AL dans CL, car SHR seulement avec CL
pop DX ;on récupère le sérial
shr dx,cl ;on décale...
pop cx ;récupère la position
;Prenons un exemple..On va dire que le SERIAL est 0A0A
;on a alors dans DX 0, c'est un chiffre, et le code ascii pour 0 est 48
;on ajoute alors à tous les chiffre 48.
;Pour A, on sait que A en héxa vaut 10 et aussi que le code ascii de A vaut 65...
;donc on ajoute 55.
;petite remarque: 55-48=7 :)
;donc au-lieu de traiter de manière bien distincte les chiffres et les lettres
;on ne cherche à savoir que si c'est un chiffre (CMP DX,9) si c'est le cas on ajoute que
;48, si c'est une lettre on commence à ajouter 7 et ensuite 48...
;Ca évite les redondances...:)
;Rappel=>EDI pointe dans la string Msg là om il y a les espaces...
cmp dx, 9
jbe chiffre
add dx, 7d
chiffre: add dx, 48d ;cx=valeur en hexa du code ascii du serial
mov word ptr [edi], dx ;on met les valeurs dans la chaine
inc edi ;incremente le pointeur de la chaine
shr si, 4 ;on modifie le masque
pop dx ;on reprend le serial initial
loop toto
;On affiche le tout....:)
invoke MessageBoxA ,NULL, offset Msg , ADDR AppName, NULL
ret
Generate endp
end start
; ------------------------------------- FIN DU CODE -------------------------------------
Voili, voilà....
Ceci est la fin de ce compte rendu....Qui a dit enfin ? :)
Je passe un petit bonjour à tous ceux que je connais, comme ca je ne risque pas d'oublier du
monde...:p
Si vous avez des questions/remarques/etc....bah n'hésitez pas...
ALSINDOR(arobase)Yahoo(point)Com
ou
HTTP://WWW.CITEWEB.NET/ATPTEAM
HAVE PHUN !