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 !