CrackMe v. 1.00
by aLoNg3x


Tutorial de Lucifer48 [Immortal Descendants]
(1 août 1999)


Le crackme est en delphi... cette fichue icone...
Je remplis mon nom (Nome) et mon serial (Codice), c'est cool j'apprend l'italien :)
(j'ai préalablement mis un bpx hmemcpy), le schéma est ultra classique:
XXXX:00442C9C  CALL 004232C0		;on sort d'ici
XXXX:00442CA1  MOV  EAX,[EBP-08]
XXXX:00442CA4  LEA  EDX,[EBP-04]
...
XXXX:00442D07  MOV  EAX,[EBP-10]	;nom
XXXX:00442D0A  POP  EDX			;serial
XXXX:00442D0B  CALL 00442A3C		;vérification du serial
XXXX:00442D10  TEST AL,AL
XXXX:00442D12  JZ   00442D23            ;jump = mauvais serial
Voilà une petite traduction en Borland C++ Builder (v4.0) de ce qui ce passe dans le call 00442A3C:
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1KeyUp(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
int i, result=0;
AnsiString name;
name=Edit1->Text;               /* Edit1: edit box for the name */

if ((name!="")&&(name.Length()>5)&&(name.Length()<11))
  {
  for(i=1; i<name.Length(); i++)
    result += name[i+1]*name[i]*i;
  result = result + name.Length() - 666;
  Edit2->Text=result;
  }
else
  Edit2->Text="";               /* Edit2: edit box for the serial */
}
//---------------------------------------------------------------------------
J'obtiens la registration suivante:
Name/ Lucifer48
Serial/ 290812

Avec ça, le boutton "OK" est enablé, je click dessus et rien ! Le boutton "OK" est grayé à nouveau. J'essaye de voir ce qui se passe lorsque j'appuie sur ok, et rien d'interessant... Apparement c'est pas la vraie vérification...

La vérification du serial est faite lorsque l'on appuie sur le boutton "Cancella"; c'est exactement le même schéma (même disposition) que ci-dessus:
...
XXXX:00442EE3  MOV  EAX,[EBP-04]		;nom
XXXX:00442EE6  POP  EDX				;edx contient la valeur du serial en héxa
XXXX:00442EE7  CALL 00442AF4			;vérification
XXXX:00442EEC  TEST AL,AL
XXXX:00442EEE  JZ   00442F0C			;jump = mauvais serial
Petit tour du côté du call 00442AF4:
XXXX:00442B3A  CALL 00442A20			;EAX! i.e: je veux dire: factorielle(eax)
XXXX:00442B3F  MOV  ESI,EAX			;sauvegarde du résultat
...
XXXX:00442B4F  MOV  EDX,00000001
XXXX:00442B54  MOV  ECX,[EBP-04]		;adresse du nom
XXXX:00442B57  MOVZX ECX,BYTE PTR [EDX+ECX-01]  ;lit un à un les caractères du nom
XXXX:00442B5C  IMUL ECX,ESI
XXXX:00442B5F  ADD  EBX,ECX
XXXX:00442B61  INC  EDX
XXXX:00442B62  DEC  EAX
XXXX:00442B63  JNZ  00442B54			;boucle de la taille du nom
XXXX:00442B65  SUB  EBX,[EBP-08]		;le serial (en héxa)
XXXX:00442B68  CMP  EBX,00007A69
XXXX:00442B6E  JNZ  00442B74			;doit être égal...
Voilà une petite partie de keygen:
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1KeyUp(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
int i, f, result=0;
AnsiString name;
name=Edit1->Text;               /* Edit1: edit box for the name */

if ((name!="")&&(name.Length()>5)&&(name.Length()<11))
  {
  f=fact((name[5]%7)+2);	/* fact(n) = 1*2*...*(n-1)*n */
  for(i=1; i<=name.Length(); i++)
    result = result + name[i]*f;
  result -= 0x7a69;
  Edit2->Text=result;
  }
else
  Edit2->Text="";               /* Edit2: edit box for the serial */
}
//---------------------------------------------------------------------------
En appuyant sur le boutton "Cancella"; celui-ci disparait. On a passé une étape ! Reste encore un boutton.

J'obtiens la registration suivante:
Name/ Lucifer48
Serial/ 560503

Note: Ca ne pose pas de problème d'entrer des nombres négatifs. (exemple: Name/ L48 [ID] Serial/ -30255 )

Remarque: J'aimerais dire quelques mots concernant la façon dont delphi a compilé la fonction factorielle (petit tour du côté du call 00442A20):
XXXX:00442A20  PUSH EBX			;13 lignes de code seulement !!
XXXX:00442A21  MOV  EBX,EAX		;et rien de superflu, pour une fois !!
XXXX:00442A23  TEST EBX,EBX
XXXX:00442A25  JNZ  00442A2E
XXXX:00442A27  MOV  EAX,000000001	;
XXXX:00442A2C  POP  EBX			;condition d'arret
XXXX:00442A2D  RET			:
XXXX:00442A2E  MOV  EAX,EBX
XXXX:00442A30  DEC  EAX
XXXX:00442A31  CALL 00442A20
XXXX:00442A36  IMUL EBX			;partie récursive
XXXX:00442A38  POP  EBX			;(résultat de la multiplication EDX:EAX, avec EDX dword..
XXXX:00442A39  RET			; ..de poids fort)
On retrouve bien ce schéma avec les langages de haut niveau: Continuons le crackme, reste à enlever le boutton "OK" (exactement la même démarche que tout à l'heure).
XXXX:00442DBD  MOV  EAX,[EBP-04]		;nom
XXXX:00442DC0  POP  EDX				;serial (en héxa)
XXXX:00442DC1  CALL 004232C0			;vérification du serial
XXXX:00442DC6  TEST AL,AL
XXXX:00442DC8  JZ   00442DD7			;jump = mauvais serial
Dans le call 004232C0:
XXXX:00442C09  MOVZX EAX,BYTE PTR [ESI+EAX-01]
XXXX:00442C0E  IMUL  EAX			;EAX^2
XXXX:00442C10  MOVSX EAX,AX			;si AX>7FFF alors EAX=(EAX or $FFFF0000)
XXXX:00442C13  IMUL  ESI
XXXX:00442C15  MOV   ECX,00000019		;il aurait fallu mettre 1A pour le "Z"
XXXX:00442C1A  CDQ
XXXX:00442C1B  IDIV  ECX
XXXX:00442C1D  ADD   EDX,41
XXXX:00442C20  POP   EAX
XXXX:00442C21  MOV   [EAX],DL			;adresse du serial
XXXX:00442C23  DEC   ESI			;on part du dernier caractère du serial
XXXX:00442C24  TEST  ESI,ESI
XXXX:00442C26  JNZ   00442BF9			;boucle (de la longueur du serial)
XXXX:00442C28  MOV   EAX,[EBP-0C]		;serial "transformé"
XXXX:00442C2B  MOV   EDX,[EBP-04]		;nom
XXXX:00442C2E  CALL  00403B44			;comparaison des deux chaines
XXXX:00442C33  JNZ   00442C4C                   ;jump = mauvais serial
En regardant la boucle on voit que le nom ne doit comporter que des majuscules (de 41h à 59h, on peut même pas mettre de Z dans le nom...) Et bien sûr, le serial et le nom ont même nombre de caractères.

Trouvons (ou essayons de trouver...) un serial pour mon nom:
L  U  C  I  F  E  R
4C 55 43 49 46 45 52
Je rappelle que l'on ne peut entrer que des chiffres pour le serial.
(X7^2 * 7) mod 19 + 41 = 52   <=>   (X7^2 * 7) mod 19 = 11
(X6^2 * 6) mod 19 + 41 = 45   <=>   (X6^2 * 6) mod 19 = 04
(X5^2 * 5) mod 19 + 41 = 46   <=>   (X5^2 * 5) mod 19 = 05
(X4^2 * 4) mod 19 + 41 = 49   <=>   (X4^2 * 4) mod 19 = 08
(X3^2 * 3) mod 19 + 41 = 43   <=>   (X3^2 * 3) mod 19 = 02
(X2^2 * 2) mod 19 + 41 = 55   <=>   (X2^2 * 2) mod 19 = 14
(X1^2 * 1) mod 19 + 41 = 4C   <=>   (X1^2 * 1) mod 19 = 0B
J'ai fait un petit programme sur ma calculatrice qui essaye les 10 (unique) possibilités (de 30h à 39h):
Pour X7: j'obtiens: { 3h, 7h, 0h, 7h, 3h, Dh, Ch, 0h, 2h, 12h }
Pour X6: j'obtiens: { 18h, 6h, 0h, 6h, 18h, 4h, 15h, 0h, 10h, 13h }
Pour X5: j'obtiens: { 14h, 5h, 0h, 5h, 14h, 14h, 5h, 0h, 5h, 14h }
Pour X4: j'obtiens: { 10h, 4h, 0h, 4h, 10h, Bh, Eh, 0h, 13h, 15h }
Pour X3: j'obtiens: { Ch, 3h, 0h, 3h, Ch, 2h, 17h, 0h, 8h, 16h }
Pour X2: j'obtiens: { 8h, 2h, 0h, 2h, 8h, 12h, 7h, 0h, 16h, 17h }
Pour X1: j'obtiens: { 4h, 1h, 0h, 1h, 4h, 9h, 10h, 0h, Bh, 18h }
On voit tout de suite que X7, X4 et X2 sont impossible à résoudre ! C'est une grosse erreur de conception de l'auteur...

Caractères acceptables (toujours dans l'ordre):
Pour X7: "D","H","A","H","D","N","M","A","C","S"
Pour X6: "Y","G","A","G","Y","E","V","A","Q","T"
Pour X5: "U","F","A","F","U","U","F","A","F","U"
Pour X4: "Q","E","A","E","Q","L","O","A","T","V"
Pour X3: "M","D","A","D","M","C","X","A","I","W"
Pour X2: "I","C","A","C","I","S","H","A","W","X"
Pour X1: "E","B","A","B","E","J","Q","A","L","Y"
Avec ça, je ne peut pas faire mon nom... Je peut faire

Name/ LICQFED
Serial/ 8050150 (ou 8050350 ou...)

Ou plus simplement:
Name/ AAAAAA
Serial/ 222222

Remarque: Juste histoire d'être complet, on peut mettre un caractère "-" comme premier caractère du serial. Donc 2Dh devient "A".

Le boutton "OK" disparait à son tour...

Greetings: All ID members (Volatility, Torn@do, ...), Eternal Bliss, ACiD BuRN, LaZaRuS, Duelist, people on #cracking4newbies, ...



(c) Lucifer48. All rights reversed