Keygen pour Easy CD-DA Extractor Version 3.6.0 (Build 1600)
MagTians, le 19 novembre 1999 Easy CD-DA Extractor est le programme le plus décent que j'ai trouvé pour encoder
les CD audio en mp3. Je me suis arrêté sur celui-là après avoir essayé MusicMatch
Jukebox et Audiograbber que j'ai trouvés pitoyables. L'interface de MusicMatch Jukebox est une horreur et
en essayant de cracker Audiograbber je me suis aperçu qu'il utilisait une DLL 16 bits. Lorsqu'on lance Easy CD-DA Extractor, une boîte de dialogue apparaît et demande un
code à l'utilisateur. La première chose que l'on remarque est que le bouton OK est grisé.
J'ai essayé d'entrer n'importe quoi mais tous mes efforts n'ont pas réussi à dégriser
ce bouton, d'où l'hypothèse que ceci n'arrive que lorsque que le code est correct. Une possibilité est que le code est vérifié à chaque fois que l'utilisateur
rentre un nouveau caratère du code. Sur cette idée, je me suis dit : "tain, ça change
que dalle, le prog est bien obligé de récupérer le code saisi, je va faire un ptit bpx GetDlgItemTextA
et on en parlera plus". Ben ca marche po, bpx GetWindowTextA ne marche pas non plus. bpx hmemcpy marche mais
je me suis retrouvé complètement perdu dans les DLL de Windows. En fait j'ai trouvé la fonction
de vérification du code tout à fait par hasard grâce à un bpx GetSystemTime. J'avais
vu que cette fonction était utilisée grâce à wdasm mais je ne voyais pas du tout à
quoi elle pouvait servir dans la fonction de vérification du code. Enfin, cette fonction se trouve à
4016FC, si elle retourne 1, le bouton se dégrise. Comme le programme ne demande qu'un code (pas de nom d'utilisateur) je me suis dit que faire
un générateur de clé serait hyper simple. Regardons ce qui se passe en 4016FC : Le début est clair comme de l'eau de roche, le code doit être de la forme "%08X%08X-%08X%08X",
c'est à dire quatre nombres hexadecimaux de huit caractères avec un tiret au milieu, par exemple
: 0123456789ABCDEF-89ABCDEF01234567. Le but de sscanf est de transformer une telle chaine de caractère en
quatre entier 32 bits. En C ça donne la chose suivante : La suite : Regardez bien ce code, il est totalement inutile ! Tout ce que ça fait est u1=a et u2=b.
Les programmeurs de Easy CD-DA Extractor cherchent juste à nous embrouiller la tête, mais évidemment
ça ne marche pas. Cette partie est exactement pareille que la précédente, ça fait u3=c et
u4=d. Ne perdons pas plus de temps sur ce tas d'instructions horrible et regardons la suite : Ceci semble plus intéressant, au final on a u1 = a xor c xor AAAAAAAA et u2 = b xor d
xor AAAAAAAA. Regardons la suite : Regardez rapidemment 4A9C2C, vous avez reconnu au premier coup d'oeil memcpy. On fait donc memcpy(&u5,
&u1, 8). Si on appelle [ebp-24] u6, ce memcpy est equivalent à u5=u1 et u6=u2. Pour l'instant, rien
de véritablement intéressant, le résumé en C nous montre que rien ne s'est passé
à part les XOR. La suite nous révèle quelques surprises : Voilà l'appel à GetSystemTime qui m'a fait repérer cette fonction. Il rempli
une structure SYSTEMTIME à l'adresse ebp-50, appelons la st. Regardez d'abord cette suite d'instruction en gros. Il s'agit d'un calcul fait à partir
u5 (ebp-28 et ebp-26) et u6 (ebp-24). EAX et EDX sont utilisés tout au long du calcul et sont conservé
à la fin dans [ebp-30] et [ebp-2C]. Par deux fois, ADD suivi de ADC sont utilisés. Tout ceci nous
montre qu'on travaille sur des nombres de 64 bits. Regardez rapidement la fonction 4B0D58, il s'agit tout simplement
de la multiplication de l'entier de 64 bits formé par EAX et EDX par l'entier de 64 bits formés par
les deux paramètres que prend cette fonction. Reregardez attentivement, et hop vous comprenez qu'il s'agit tout bêtement de l'instruction
__int64 r = LOWWORD(u5)*0x16D + HIWORD(u5)*0x1E + LOWWORD(u6), où r est stocké en ebp-30 et ebp-2C Je vous présente ça comme si j'avais compris tout de suite, mais en fait non. J'ai
tracé ce bloc d'instructions une bonne dizaine de fois, j'ai pris des notes fait différents essais
avec des valeurs différentes pour comprendre ce qui ce passe. Nous remarquons aussi, mais cela ne nous étonnera pas vu les horreurs que nous avons déja
vu, qu'il est totalement inutile de raisonner sur des entiers de 64 bits étant donné que le résultat
de ce calcul tient forcement sur un DWORD. La suite est du même acabi : Exactement le même calcul que le précedent, mais cette fois avec des informations
de la structure SYSTEMTIME. [ebp-50] est l'année, [ebp-4E] est le mois et [ebp-4A] est le jour. Le calcul est __int64
d = année*0x16D + mois*0x1E + jour,d étant stocké sur [ebp-38] et [ebp-34]. Lorsque j'ai vu
ça, ça a fait tilt dans ma tête. J'ai sorti ma TI-85 (vieux souvenir de terminale, ça
doit être une antiquité maintenant) et, hmm très intéressant, 16D vaut 365 et 1E vaut
30. Ceci calcule, grosso modo, un numéro de jour. Le code, ayant subi le même type de
calcul, doit aussi représenter un numéro de jour. Il est quasi certain à cette étape que ces deux numéros vont être
comparés. Je me suis dit que le code doit certainement représenter une date de fin de validité
de la license. Sur cette idée, je me suis forgé un code qui représente le 01/01/3000 mais
ça na pas marché. Regardons la suite pour comprendre pourquoi : Là, on voit que le code (après quelques manipulations) doit représenter
une date comprise entre 10 jours avant la date actuelle et 6 jours après la date actuelle. On voit aussi
que [ebp-22] (HIWORD(u6)) doit être égal à 43. Et on comprend le raisonnement vicieux des programmeurs
de Easy CD-DA Extractor. Ils se sont dit : Assez fantasmé sur la vie de programmeur de shareware, il est temps de passer à
la génération de bons codes, pour commencer, faisons un ptit exemple à la main, nous choisissons la date actuelle pour nous enregistrer,
19/11/1999 dans ce cas. 19/11/1999 en hexadécimal c'est 13/B/7CF Le C, ya que ça de vrai : Voilà, ben ma foi je trouve que le principe de la protection est pas mal du tout, même
si, au final, le générateur de clé est ridiculement court. Mes remerciments (il parait que c'est une tradition) vont à Christal (www.multimania.com/christalpage)
et à TeeJi (www.crackfr.com).
Préliminaire
Liminaire
Tentative d'embrouille ?
:004016FC 55 push ebp
:004016FD 8BEC mov ebp, esp
:004016FF 83C4B0 add esp, -50 ; 50 octets de variable locale
:00401702 8D45F0 lea eax, dword ptr [ebp-10] ; appelons [ebp-10] d
:00401705 8D55F4 lea edx, dword ptr [ebp-0C] ; appelons [ebp-0C] c
:00401708 8D4DF8 lea ecx, dword ptr [ebp-08] ; appelons [ebp-08] b
:0040170B 50 push eax
:0040170C 52 push edx
:0040170D 51 push ecx
:0040170E 8D45FC lea eax, dword ptr [ebp-04] ; appelons [ebp-04] a
:00401711 50 push eax
* Possible StringData Ref from Data Obj ->"%08X%08X-%08X%08X"
|
:00401712 6883E74C00 push 004CE783
:00401717 8B5508 mov edx, dword ptr [ebp+08] ; d ebp+08 montre qu'il s'agit du code
:0040171A 52 push edx
:0040171B E808C40A00 call 004ADB28 ; manifestement sscanf
:00401720 83C418 add esp, 00000018
int VerifieCode(char *code)
{
int a, b, c, d;
sscanf(code, "%08X%08X-%08X%08X", &a, &b, &c, &d);
:00401723 8B45F8 mov eax, dword ptr [ebp-08]
:00401726 33D2 xor edx, edx
:00401728 8D4DE8 lea ecx, dword ptr [ebp-18] ; appelons [ebp-18] u1
:0040172B 8BD0 mov edx, eax
:0040172D 33C0 xor eax, eax
:0040172F 52 push edx
:00401730 50 push eax
:00401731 8B45FC mov eax, dword ptr [ebp-04]
:00401734 33D2 xor edx, edx
:00401736 0B542404 or edx, dword ptr [esp+04]
:0040173A 0B0424 or eax, dword ptr [esp]
:0040173D 8945E8 mov dword ptr [ebp-18], eax
:00401740 8955EC mov dword ptr [ebp-14], edx ; appelons [ebp-14] u2
:00401743 83C408 add esp, 00000008
:00401746 8B45F0 mov eax, dword ptr [ebp-10]
:00401749 33D2 xor edx, edx
:0040174B 8BD0 mov edx, eax
:0040174D 33C0 xor eax, eax
:0040174F 52 push edx
:00401750 50 push eax
:00401751 8B45F4 mov eax, dword ptr [ebp-0C]
:00401754 33D2 xor edx, edx
:00401756 0B542404 or edx, dword ptr [esp+04]
:0040175A 0B0424 or eax, dword ptr [esp]
:0040175D 8945E0 mov dword ptr [ebp-20], eax ; appelons [ebp-20] u3
:00401760 8955E4 mov dword ptr [ebp-1C], edx ; appelons [ebp-1C] u4
:00401763 8B45E0 mov eax, dword ptr [ebp-20] ; eax = u3
:00401766 8B55E4 mov edx, dword ptr [ebp-1C] ; edx = u4
:00401769 81F0AAAAAAAA xor eax, AAAAAAAA ; eax = eax xor AAAAAAAA
:0040176F 81F2AAAAAAAA xor edx, AAAAAAAA ; edx = edx xor AAAAAAAA
:00401775 3145E8 xor dword ptr [ebp-18], eax ; u1 = u1 xor eax
:00401778 83C408 add esp, 00000008
:0040177B 3155EC xor dword ptr [ebp-14], edx ; u2 = u2 xor eax
:0040177E 8D45D8 lea eax, dword ptr [ebp-28] ; appelons [ebp-28] u5
:00401781 6A08 push 00000008
:00401783 51 push ecx ; regardez en 401728, ECX pointe vers u1
:00401784 50 push eax
:00401785 E8A2840A00 call 004A9C2C ; manifestement memcpy
:0040178A 83C40C add esp, 0000000C
int VerifieCode(char *code)
{
int a, b, c, d;
int u1, u2, u3, u4;
sscanf(code, "%08X%08X-%08X%08X", &a, &b, &c, &d);
u1=a; u2=b; u3=c; u4=d;
u1 ^= u3 ^ 0xAAAAAAAA;
u2 ^= u4 ^ 0xAAAAAAAA;
u5 = u1;
u6 = u2;
La surprise du chef
:0040178D 8D55B0 lea edx, dword ptr [ebp-50]
:00401790 52 push edx
* Reference To: KERNEL32.GetSystemTime, Ord:0000h
|
:00401791 E8DEB40C00 Call 004CCC74
:00401796 6A00 push 00000000
:00401798 686D010000 push 0000016D
:0040179D 0FB745D8 movzx eax, word ptr [ebp-28]
:004017A1 33D2 xor edx, edx
:004017A3 E8B0F50A00 call 004B0D58
:004017A8 52 push edx
:004017A9 50 push eax
:004017AA 6A00 push 00000000
:004017AC 6A1E push 0000001E
:004017AE 0FB745DA movzx eax, word ptr [ebp-26]
:004017B2 33D2 xor edx, edx
:004017B4 E89FF50A00 call 004B0D58
:004017B9 030424 add eax, dword ptr [esp]
:004017BC 13542404 adc edx, dword ptr [esp+04]
:004017C0 83C408 add esp, 00000008
:004017C3 52 push edx
:004017C4 50 push eax
:004017C5 0FB745DC movzx eax, word ptr [ebp-24]
:004017C9 33D2 xor edx, edx
:004017CB 030424 add eax, dword ptr [esp]
:004017CE 13542404 adc edx, dword ptr [esp+04]
:004017D2 83C408 add esp, 00000008
:004017D5 8945D0 mov dword ptr [ebp-30], eax
:004017D8 8955D4 mov dword ptr [ebp-2C], edx
:004017DB 6A00 push 00000000
:004017DD 686D010000 push 0000016D
:004017E2 0FB745B0 movzx eax, word ptr [ebp-50]
:004017E6 33D2 xor edx, edx
:004017E8 E86BF50A00 call 004B0D58
:004017ED 52 push edx
:004017EE 50 push eax
:004017EF 6A00 push 00000000
:004017F1 6A1E push 0000001E
:004017F3 0FB745B2 movzx eax, word ptr [ebp-4E]
:004017F7 33D2 xor edx, edx
:004017F9 E85AF50A00 call 004B0D58
:004017FE 030424 add eax, dword ptr [esp]
:00401801 13542404 adc edx, dword ptr [esp+04]
:00401805 83C408 add esp, 00000008
:00401808 52 push edx
:00401809 50 push eax
:0040180A 0FB745B6 movzx eax, word ptr [ebp-4A]
:0040180E 33D2 xor edx, edx
:00401810 030424 add eax, dword ptr [esp]
:00401813 13542404 adc edx, dword ptr [esp+04]
:00401817 83C408 add esp, 00000008
:0040181A 8945C8 mov dword ptr [ebp-38], eax
:0040181D 8955CC mov dword ptr [ebp-34], edx
:00401820 8B45C8 mov eax, dword ptr [ebp-38]
:00401823 8B55CC mov edx, dword ptr [ebp-34]
:00401826 2B45D0 sub eax, dword ptr [ebp-30]
:00401829 1B55D4 sbb edx, dword ptr [ebp-2C]
:0040182C 8945C0 mov dword ptr [ebp-40], eax
:0040182F 8955C4 mov dword ptr [ebp-3C], edx
:00401832 837DC400 cmp dword ptr [ebp-3C], 00000000
:00401836 7504 jne 0040183C
:00401838 837DC00A cmp dword ptr [ebp-40], 0000000A
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401836(C)
|
:0040183C 7610 jbe 0040184E
:0040183E 837DC4FF cmp dword ptr [ebp-3C], FFFFFFFF
:00401842 7504 jne 00401848
:00401844 837DC0FA cmp dword ptr [ebp-40], FFFFFFFA
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401842(C)
|
:00401848 7304 jnb 0040184E
:0040184A 33C0 xor eax, eax
:0040184C EB0D jmp 0040185B
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0040183C(C), :00401848(C)
|
:0040184E 66837DDE43 cmp word ptr [ebp-22], 0043
:00401853 7404 je 00401859
:00401855 33C0 xor eax, eax
:00401857 EB02 jmp 0040185B
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401853(C)
|
:00401859 B001 mov al, 01
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0040184C(U), :00401857(U)
|
:0040185B 8BE5 mov esp, ebp
:0040185D 5D pop ebp
:0040185E C3 ret
- Eh didon, t'as vu, ya pleins de sites qui proposent des serial pour toutes sortes de sharewares.
- Tain, ça doit être des gars qui achètent les sharewares et refilent leurs serials dans l'idée
d'obtenir un peu de gloire et de popularité, pfff bande de ptits cons va.
- Eh didon, je crois que j'ai une idée géniale !!!
- Tain, toi ! une idée géniale ! (ricanements contenus)
- Ben vi, on va faire un serial qui marche que pendant une courte période, comme ça les ptits cons
vont mettre plein de serials sur leurs sites mais quelques jours après ils seront plus bons et ils l'auront
dans l'os les ptits enculés de leur mère.
- Tain, génial génial, mais comment on va faire ça ?
- Ben facile ducon, pour le serial tu prend une date, tu fais quelques XOR, quelques trucs bidon pour que ca ressemble
plus à une date. Dans le prog, on récupère la date contenue dans le serial et on compare
avec la date actuelle pi le tour est joué
- Tain, génial excellent, on va les enculer comme des enculés les enfoirésGénération de bons codes
L'année c'est LOWWORD(u5), c'est 07CF
Le mois c'est HIGHWORD(u5), c'est 000B
Le jour c'est LOWWORD(u6), c'est 0013
HIGHWORD(u6) doit être égal à 43
On a donc :
u5 = 000B07CF
u6 = 00430013
Or,
u5 = a xor c xor AAAAAAAA et
u6 = b xor d xor AAAAAAAA
Donc,
a xor c = u5 xor AAAAAAAA = AAA1AD65
b xor d = u6 xor AAAAAAAA = AAE9AAB9
Là on peut choisir c et d au hasard, et ca nous donnera a et b. Si on choisi c=d=0, on a a=AAA1AD65 et b=AAE9AAB9
Donc notre serial est : AAA1AD65AAE9AAB9-0000000000000000
Vérifions, ça marche !!! Mais dans 10 jours il marchera plus, héhé pas si con comme
principe.//================================================================================
// GenereCode génère un code valide pour Easy CD-DA Extractor pour le jour
// courant
//
// Paramètres : c et d sont les nombres qui forme la partie du code après le tiret
// on peut mettre ce que l'on veut
//
// code est le buffer dans lequel va être écrit le code. Le buffer
// doit être de longueur 34 au moins
//================================================================================
void GenereCode(DWORD c, DWORD d, char *code)
{
DWORD u5, u6, a, b;
SYSTEMTIME st;
GetSystemTime(&st);
u5=MAKELONG(st.wYear, st.wMonth);
u6=MAKELONG(st.wDay, 0x43);
a = u5 ^ 0xAAAAAAAA ^ c;
b = u6 ^ 0xAAAAAAAA ^ d;
sprintf(code, "%08X%08X-%08X%08X", a, b, c, d);
}