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 !