Hard Disk Sleeper v1.55
Tutorial de Lucifer48 [Immortal Descendants]
(23 juillet 1999)
Target Program: | Hard Disk Sleeper v1.55 |
Location: | http://www.mwso.com/ |
Protection: | Name/Serial |
Level: | Beginner (3/10) |
L'obtention d'un serial n'est pas difficile (le code en C est propre), mais requiert quand même un
petit peu de temps. Comme d'habitude, on remplit les cases Name & Serial... Lorsque l'on appuie
sur le boutton OK, il y une courte comparaison:
XXXX:00413A24 MOV EAX,[004205D0] ;checksum calculé à partir du nom et du serial
XXXX:00413A29 CMP EAX,[004205C0] ;comparaison avec la bonne valeur (19Eh)
XXXX:00413A2F JZ 00413A6C ;no jump = mauvais cracker!
Le calcul de la constante en [004205D0] est re-effectué à chaque pression d'une touche.
XXXX:004139DC CALL USER32!GetWindowTextA
XXXX:004139E1 CMP EAX,08 ;le serial doit comporter 8 caractères
...
XXXX:00413A08 CALL 00413C94 ;fabrication de 8 octets
...
XXXX:00413A10 LEA EAX,[EBP-0C] ;nos 8 précieux octets (C1, C2, ..., C8)
XXXX:00413A13 PUSH EAX
XXXX:00413A14 CALL 00413D13 ;calcul du checksum (résultat eax)
XXXX:00413A19 POP ECX ;add esp,4
XXXX:00413A1A MOV [004205D0],EAX ;savegarde pour comparer plus tard
Ces 8 octets (C1, C2, ..., C8) sont calculés à partir du nom et du serial.
Voilà (en pseudo code, mi-chemin entre le C et le Pascal) ce que fait le call 00413D13 avec ces 8
octets:
x={ C1, C2, C3, C4, C5, C6, C7, C8 }
checksum=0;
for i:=0 to 6 do
checksum:=checksum + ( (x[i]+i) mod $A ) * ( (x[i+1]+i+1) mod $A );
Il faut qu'à la fin de la boucle checksum=0x19E Comment faire ?
Une brute force attack ?? Pas question 8 variables de 0 à FF c'est beaucoup trop. On va plutôt
ce servir de la présence des modulos, en effet on ne peut pas dépasser 9*9 (et au pire 0*0) pour
une boucle. Donc on va dans un premier temps chercher à trouver ces 8 nombres entre 0 et 9.
J'explique autrement, si vous préférez, on effectue un changement de variable; D1= (C1 + 0) mod 0xA,
etc... donc la formule avec le checksum peut s'écrire (formellement parlant):
y={ D1, D2, D3, D4, D5, D6, D7, D8 }
checksum=0;
for i:=0 to 6 do
checksum:=checksum + y[i] * y[i+1];
et plus simplement, cela est équivalent à:
checksum = D1*D2 + D2*D3 + D3*D4 + D4*D5 + D5*D6 + D6*D7 + D7*D8
A ce moment là, la "brute force" est tranquille (8 variables, allant de 0 à 9, seulement (10^8 =)
100 millions de possibilités, de la rigolade...).
Voilà ma source en C:
/*********************************************************/
#include
void main()
{
signed char x1, x2, x3, x4, x5, x6, x7, x8;
long a;
for(x1=0; x1<=9; x1++)
for(x2=0; x2<=9; x2++)
for(x3=0; x3<=9; x3++)
for(x4=0; x4<=9; x4++)
for(x5=0; x5<=9; x5++)
for(x6=0; x6<=9; x6++)
for(x7=0; x7<=9; x7++)
for(x8=0; x8<=9; x8++)
{
a=0;
a= x1*x2 + x2*x3 + x3*x4 + x4*x5 + x5*x6 + x6*x7 + x7*x8;
if (a==0x19E)
printf("%x %x %x %x %x %x %x %x\n",x1,x2,x3,x4,x5,x6,x7,x8);
} /* end of for */
}
/*********************************************************/
On trouve des tonnes de solutions (2919 exactement) en quelques secondes. Voici les dernières:
a b c d e f g h
9 9 9 9 9 4 6 5
9 9 9 9 9 4 9 2
9 9 9 9 9 5 5 4
9 9 9 9 9 5 9 0
9 9 9 9 9 6 3 6
9 9 9 9 9 6 4 3
9 9 9 9 9 6 6 0
9 9 9 9 9 7 3 2
9 9 9 9 9 8 2 1
9 9 9 9 9 9 1 0
Si je prend le dernier exemple; ca veut dire que (en regardant la source du programme):
Boucle1: (C1 + 0 + 0) mod 10 = 9 et (C2 + 0 + 1) mod 10 = 9
Boucle2: (C2 + 1 + 0) mod 10 = 9 et (C3 + 1 + 1) mod 10 = 9
Boucle3: (C3 + 2 + 0) mod 10 = 9 et (C4 + 2 + 1) mod 10 = 9
Boucle4: (C4 + 3 + 0) mod 10 = 9 et (C5 + 3 + 1) mod 10 = 9
Boucle5: (C5 + 4 + 0) mod 10 = 9 et (C6 + 4 + 1) mod 10 = 9
Boucle6: (C6 + 5 + 0) mod 10 = 9 et (C7 + 5 + 1) mod 10 = 1
Boucle7: (C7 + 6 + 0) mod 10 = 1 et (C8 + 6 + 1) mod 10 = 0
On enlève les doubles et on obtient les conditions suivantes:
(C1 + 0) mod 10 = 9 (= a)
(C2 + 1) mod 10 = 9 (= b)
(C3 + 2) mod 10 = 9 (= c)
(C4 + 3) mod 10 = 9 (= d)
(C5 + 4) mod 10 = 9 (= e)
(C6 + 5) mod 10 = 9 (= f)
(C7 + 6) mod 10 = 1 (= g)
(C8 + 7) mod 10 = 0 (= h)
Il est donc facile de générer nos 8 précieux octets (C1, C2, ..., C8). S'en est fini pour le
call 00413D13.
Remarque: N'oublions pas que ces huits octets proviennent directement du nom et du serial.
On sait comment obtenir 8 bons octets (C1...C8), maintenant, étudions la façon dont on arrive
à ces 8 octets (en encodant le nom et le serial). Ca se trouve dans le CALL 00413C94 (en
XXXX:00413A08). Posons S1, S2, ..., S8 les huits caractères du serial définitif.
Mon nom (Lucifer48) est codé comme ceci (84 = 4C + 38) sur 8 octets:
XXXX:0068F464 84 75 63 69 66 65 72 34 .ucifer4
N1 N2 N3 N4 N5 N6 N7 N8
Le procédé d'encrytion (c'est un bien grand mot) est le suivant:
C1 =S1 - [ (N1 mod 1Ah) + 41h ]
C2 =S2 - [ (N2 mod 1Ah) + 41h ]
...
C8 =S8 - [ (N8 mod 1Ah) + 41h ]
Si Ck (k={1,2,...8} ) est négatif (compris entre 7F et FF), alors Ck += 1Ah.
Chaque caractère du serial est indépendant des autres. Donc on va pouvoir résoudre succéssivement
8 équations. En "retournant" le problème, on obtient:
S1 = C1 + [ (N1 mod 1Ah) + 41h ]
S2 = C2 + [ (N2 mod 1Ah) + 41h ]
...
S8 = C8 + [ (N3 mod 1Ah) + 41h ]
A ceci s'ajoute la condition: si on suppose que Sk > [ (Nk mod 1Ah) + 41h ]
(afin d'écarter le problème de la retenue (+1A) ).
Pour mon nom:
S1 = C1 + 43
S2 = C2 + 4E
S3 = C3 + 56
S4 = C4 + 42
S5 = C5 + 59
S6 = C6 + 58
S7 = C7 + 4B
S8 = C8 + 41
Pour trouver C1, C2, ..., C8 je fais:
C1 = 3*Ah + 9 - 0 = 27
C2 = 3*Ah + 9 - 1 = 26
...
C7 = 3*Ah + 1 - 6 = 19
C8 = 3*Ah + 0 - 7 = 17
Je prend ce 3 car c'est une constante idéale qui nous permet d'avoir des caractères
du serial printables. J'otiens ça:
6A ; 74 ; 7B ; 66 ; 7C ; 7A ; 64 ; 58 (soit: "jt{f|zdX")
Le serial marche mais il y a deux caractères pas super ;)
En fait le 3 n'est pas si formidable que ça ! on va prendre 2 et là ca sera mieux !
(même démarche que ci-dessus):
C1 = 2*Ah + 9 - 0 = 1D
C2 = 2*Ah + 9 - 1 = 1C
...
C7 = 2*Ah + 1 - 6 = 0F
C8 = 2*Ah + 0 - 7 = 0D
J'obtiens:
60 ; 6A ; 71 ; 5C ; 72 ; 70 ; 5A ; 4E (soit: "`jq\rpZN")
Youpi, ca marche encore !! Cette constante 2 n'est vraiment pas mieux !
Finalement, je me résoud à mixer les deux serials pour obtenir ma registration:
Name/ Lucifer48
Serial/ jjqfrzdX
Greetings: All ID members (Volatility, Torn@do, ...), Eternal Bliss, ACiD BuRN,
people on #cracking4newbies, french crackers, etc.
(c) Lucifer48. All rights reversed