The Art of Shredding

oder
Wie bau ich mir einen Keygenerator?


Wie fange ich an, oder was soll das Ganze hier?

Also Leute, Ihr kennt sicher alle diese schoenen Sharewareprogramme, die irgendwelche Registrierungscodes verlangen damit sie lauffaehig sind. Soweit sogut. Habt ihr euch schonmal gefragt woher das Programm weiss welche Seriennummer nun zu welchem Namen gehoert?

Ja?

Dann seid ihr hier genau richtig, denn ich erklaere euch das mal kurz am Beispiel von Clipmate 5.1! :)

Reverse Engineering, oder wie zum Teufel komm ich an den Code?

Mhh, darauf will ich jetzt nicht naeher eingehen, da es ein viel zu komplexes Thema ist und es dazu schon viele, viele gute Tutorials im Netz gibt. Alles was ihr dazu braucht ist ein guter Disassembler/Debugger (z.b. Softice / W32DASM), ein bisschen ASM-Erfahrung und viel Zeit und Geduld. :)

Nur nochmal zur Erklaerung: Jedes Programm, das eine Seriennummer hat, muss diese ja auch irgendwie mit der von euch eingegebenen Seriennummer vergleichen. Da kein Programm saemtliche Seriennummern speichert (Hehehe... Es gibt da natuerlich wie ueberall Ausnahmen), muss es die Seriennummer mit der es eure Eingabe vergleicht ja irgendwo herbekommen. Und wie wird das gemacht? Ha, irgendwie wird sie vom Programm berechnet.

Das heisst: Wenn wir hier und da die richtigen Breakpoints setzen gelangen wir irgendwann zu der Routine die macht. Diese Routine schauen wir uns dann genau an und koennen uns mit dem Wissen einen eigenen Key-Generator fuer das Programm bauen.

Ich hab euch auf jeden Fall schonmal den Key-Generierungs-Code aus Clipmate 5.1.04 rausgezogen und weitestgehend analysiert. Also schnallt euch an und haltet euch fest, denn jetzt gehts los!

Mathematics for beginners oder was rechnet der denn da?

Erstmal muessen wir uns klar darueber werden was mit unserer Texteingabe so alles passiert bevor sie berechnet werden kann.

Clipmate macht erstmal folgendes:

1. Es kovertiert unseren Namen in Grossbuchstaben
Beispiel: Aus Sledge Hammer [Grinder] wird SLEDGE HAMMER [GRINDER]

2. Es entfernt alle Zeichen, die nicht zwischen Ascii 65 (A) und Ascii 90 (Z) liegen. (Also alle Zahlen und Sonderzeichen, Punkte, Kommas usw.)
Beispiel: Aus SLEDGE HAMMER [GRINDER] wird SLEDGEHAMMERGRINDER

3. Dann wird diese Zeichenkette (String) an das Ende kopiert, weil wir auf jeden Fall 14 Zeichen zur Berechnung der Seriennummer brauchen. (Und wenn unser String nur 6 Zeichen hat, muessen wir den String halt 2 mal ans Ende kopieren.
Beispiel: Aus SLEDGEHAMMERGRINDER wird SLEDGEHAMMERGRINDERSLEDGEHAMMERGRINDER


Ok, mit diesem Wissen schauen wir uns jetzt mal die Routine von Clipmate an:
****************************************************
* Codegenerierungsroutine Clipmate 5.1.04 Build 119
* Disassembled by Sledge Hammer of Grinder
* Die Kommentare sollten eigentlich ausreichen.

:00471B24 8D4DE2	lea ecx, dword ptr [ebp-1E] 	;Name in ECX laden
:00471B27 8D75D7	lea esi, dword ptr [ebp-29] 	;Ausgabeadresse in ESI laden

:00471B2A 33C0		xor eax, eax			; EAX loeschen
:00471B2C 8A01		mov al, byte ptr [ecx]		; Buchstabe #[EXC] in AL
:00471B2E F7EB		imul ebx			; mit EBX multiplizieren
:00471B30 BF0A000000	mov edi, 0000000A		; Wert 10 in EDI
:00471B35 99		cdq				; Modulo 10 (Berechneter
:00471B36 F7FF		idiv edi			; Wert wird in DL gespeichert)
:00471B38 8816		mov byte ptr [esi], dl		; DL nach Adresse ESI
:00471B3A 43		inc ebx				; EBX + 1 (Einfacher Zaehler)
:00471B3B 46		inc esi				; ESI + 1 (Adresse Code #)
:00471B3C 41		inc ecx				; ECX + 1 (Adresse Buchstaben #)
:00471B3D 83FB0A	cmp ebx, 0000000A		; 10 Werte berechnet???
:00471B40 75E8		jne 00471B2A			; nein -> Sprung nach oben

							; ja -> Dann gehts hier weiter
:00471B42 33C0		xor eax, eax			; EAX mal wieder loeschen
:00471B44 8A45E2	mov al, byte ptr [ebp-1E]	; 1. Buchstaben in AL holen
:00471B47 B90A000000	mov ecx, 0000000A		; Wert 10 in ECX
:00471B4C 33D2		xor edx, edx			; EDX loeschen
:00471B4E F7F1		div ecx				; und ein Modulo 10
:00471B50 8855D7	mov byte ptr [ebp-29], dl	; DL nach Ausgabeadresse[0]

00471B53-00471B6C hab ich geloescht.
Hat keine direkte Auswirkung aus die Code Generierung, koennen wir also getrost vergessen. 

Hier gehts jetzt weiter:

:00471B73 33C0		xor eax, eax			; EAX mal wieder loeschen
:00471B75 8A45E5	mov al, byte ptr [ebp-1B]	; 4. Buchstaben in AL holen
:00471B78 03C0		add eax, eax			; und mit sich selber addieren (*2)
:00471B7A 33D2		xor edx, edx			; EDX mal wieder loeschen
:00471B7C 8A55EF	mov dl, byte ptr [ebp-11]	; 14. Buchstaben in DL holen
:00471B7F 2BC2		sub eax, edx			; und von EAX abziehen
:00471B81 B90A000000	mov ecx, 0000000A		; Wert 10 in ECX
:00471B86 99		cdq				; und das altbekannte
:00471B87 F7F9		idiv ecx			; Modulo 10
:00471B89 8855DE	mov byte ptr [ebp-22], dl	; DL nach Ausgabeadresse[7]

:00471B8C 33C0		xor eax, eax			; EAX mal wieder loeschen
:00471B8E 8A45EB	mov al, byte ptr [ebp-15]	; 10. Buchstaben in AL holen
:00471B91 03C0		add eax, eax			; und mit sich selber addieren (*2)
:00471B93 B90A000000	mov ecx, 0000000A		; Wert 10 in ECX
:00471B98 33D2		xor edx, edx			; EDX mal wieder loeschen
:00471B9A F7F1		div ecx				; Na, ratet mal... Modulo 10!
:00471B9C 8855E0	mov byte ptr [ebp-20], dl	; DL nach Ausgabeadresse[9]
****************************************************

Der Rest ist laut SevenofNine: "Irrelevant!" :)

Wir wissen jetzt auf jeden Fall schonmal folgendes:

1. Die dynamischen (vom Programm berechneten Werte) sind exakt 10 Zahlen zwischen 0 und 9.
2. Dazu benoetigt Clipmate maximal 14 Buchstaben aus unserem Namen.

Machen wir also mal eine Beispielberechnung um zu sehen ob wir alles verstanden haben:

Dazu denken wir uns erstmal einen Beispielnamen aus: The Rage

Das sieht im Speicher so aus:

Adresse 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Name T H E R A G E T H E R A G E
Ascii-Wert 84 72 69 82 65 71 69 84 72 69 82 65 71 69
Code * * * * * * * * * * * * * *


Koennt ihr euch noch an den ersten Codeabschnitt erinnern? Nein? Ok, Hier isser nochmal.
:00471B2A 33C0		xor eax, eax			; EAX loeschen
:00471B2C 8A01		mov al, byte ptr [ecx]		; Buchstabe #[EXC] in AL
:00471B2E F7EB		imul ebx			; mit EBX multiplizieren
:00471B30 BF0A000000	mov edi, 0000000A		; Wert 10 in EDI
:00471B35 99		cdq				; Modulo 10 (Berechneter
:00471B36 F7FF		idiv edi			; Wert wird in DL gespeichert)
:00471B38 8816		mov byte ptr [esi], dl		; DL nach Adresse ESI
:00471B3A 43		inc ebx				; EBX + 1 (Einfacher Zaehler)
:00471B3B 46		inc esi				; ESI + 1 (Adresse Code #)
:00471B3C 41		inc ecx				; ECX + 1 (Adresse Buchstaben #)
:00471B3D 83FB0A	cmp ebx, 0000000A		; 10 Werte berechnet???
:00471B40 75E8		jne 00471B2A			; nein -> Sprung nach oben

Nun, was passiert hier genau? Keine Sorge, gleich wisst ihr es... Fangen wir an:
Generell:
Code an [Adresse] = (Ascii-Wert des Buchstabens an [Adresse] * Adresse) modulo 10

Jetzt die einzelnen Buchstaben:
Code 0 = (84 * 0) mod 10 = 0
Code 1 = (72 * 1) mod 10 = 2
Code 2 = (69 * 2) mod 10 = 8
Code 3 = (82 * 3) mod 10 = 6
Code 4 = (65 * 4) mod 10 = 0
Code 5 = (71 * 5) mod 10 = 5
Code 6 = (69 * 6) mod 10 = 4
Code 7 = (84 * 7) mod 10 = 8
Code 8 = (72 * 8) mod 10 = 6
Code 9 = (69 * 9) mod 10 = 1


Daraus ergibt sich folgende Tabelle:

Adresse 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Name T H E R A G E T H E R A G E
Ascii-Wert 84 72 69 82 65 71 69 84 72 69 82 65 71 69
Code 0 2 8 6 0 5 4 8 6 1 * * * *


Nun aber weiter im Code:

:00471B42 33C0		xor eax, eax			; EAX mal wieder loeschen
:00471B44 8A45E2	mov al, byte ptr [ebp-1E]	; 1. Buchstaben in AL holen
:00471B47 B90A000000	mov ecx, 0000000A		; Wert 10 in ECX
:00471B4C 33D2		xor edx, edx			; EDX loeschen
:00471B4E F7F1		div ecx				; und ein Modulo 10
:00471B50 8855D7	mov byte ptr [ebp-29], dl	; DL nach Ausgabeadresse[0]

Neuberechnung von Code 0
Code 0 = 84 mod 10 = 4


Daraus ergibt sich die nun folgende Tabelle:

Adresse 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Name T H E R A G E T H E R A G E
Ascii-Wert 84 72 69 82 65 71 69 84 72 69 82 65 71 69
Code 4 2 8 6 0 5 4 8 6 1 * * * *


weiter gehts...

:00471B73 33C0		xor eax, eax			; EAX mal wieder loeschen
:00471B75 8A45E5	mov al, byte ptr [ebp-1B]	; 4. Buchstaben in AL holen
:00471B78 03C0		add eax, eax			; und mit sich selber addieren (*2)
:00471B7A 33D2		xor edx, edx			; EDX mal wieder loeschen
:00471B7C 8A55EF	mov dl, byte ptr [ebp-11]	; 14. Buchstaben in DL holen
:00471B7F 2BC2		sub eax, edx			; und von EAX abziehen
:00471B81 B90A000000	mov ecx, 0000000A		; Wert 10 in ECX
:00471B86 99		cdq				; und das altbekannte
:00471B87 F7F9		idiv ecx			; Modulo 10
:00471B89 8855DE	mov byte ptr [ebp-22], dl	; DL nach Ausgabeadresse[7]

Generell:
Code an Adresse 7 = ((Ascii-Wert des Buchstabens an Adresse [3] * 2) - Ascii-Wert des Buchstabens an Adresse [13]) modulo 10

Neuberechnung von Code 7
Code 7 = ((82 * 2)- 69) mod 10 = 5


Daraus ergibt sich folgende Tabelle:

Adresse 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Name T H E R A G E T H E R A G E
Ascii-Wert 84 72 69 82 65 71 69 84 72 69 82 65 71 69
Code 4 2 8 6 0 5 4 5 6 1 * * * *


Gleich haben wirs geschafft. Ein Wert muss noch berechnet werden!

:00471B8C 33C0		xor eax, eax			; EAX mal wieder loeschen
:00471B8E 8A45EB	mov al, byte ptr [ebp-15]	; 10. Buchstaben in AL holen
:00471B91 03C0		add eax, eax			; und mit sich selber addieren (*2)
:00471B93 B90A000000	mov ecx, 0000000A		; Wert 10 in ECX
:00471B98 33D2		xor edx, edx			; EDX mal wieder loeschen
:00471B9A F7F1		div ecx				; Na, ratet mal... Modulo 10!
:00471B9C 8855E0	mov byte ptr [ebp-20], dl	; DL nach Ausgabeadresse[9]

Generell:
Code an Adresse 9 = (Ascii-Wert des Buchstabens an Adresse [9] * 2) modulo 10

Neuberechnung von Code 9
Code 9 = ((69 * 2) mod 10 = 8


Daraus ergibt sich folgende Tabelle:

Adresse 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Name T H E R A G E T H E R A G E
Ascii-Wert 84 72 69 82 65 71 69 84 72 69 82 65 71 69
Code 4 2 8 6 0 5 4 5 6 8 * * * *


Hey, wir habens... Der Code fuer The Rage ist 4286054568. Doch halt... Moment. Irgendwie laesst Clipmate das nicht zu...

Mhh, da faellt mir noch was ein: Irgendwo hab ich gesehen das die Seriennummer mit einem Q01 anfaengt. Moment... [Debug...] Ahh... Also:

Der Code Q identifiziert die Version 5.1
und das 01 steht fuer die Anzahl der Lizenzen (01-FF)

Also lautet die richtige Seriennummer fuer The Rage: Q014286054568

Testen... Bang... Ja, das passt! Jetzt muessen wir uns nur noch einen Key-Generator dazu schreiben!

C++, Pascal oder Assembler. I'll let you decide

Jetzt kommt die eigentliche Arbeit, naemlich ein Programm zu schreiben welches nach Eingabe eines beliebigen Namens die passende Seriennummer ausspuckt. Ich hab den Keygenerator zuerst in Pascal programmiert, doch das Stringhandling ist ein wenig komplizierter als in C++. Deshalb hab ich das Programm kurzerhand nach C++ portiert. Ihr koenntet ihn natuerlich auch in BASIC, PERL, FORTRAN, ASSEMBLER, oder was weiss ich fuer 'ner Sprache schreiben. Am schnellsten geht's auf jeden Fall in C++ :)
/*
Programm:    Keygenerator fuer Clipmate 5.1.04 Build 119 (2 July 1999)
Copyright:   coded by Sledge Hammer of Grinder
Datum:       07.08.1999 - 4 Days till Judgement Day :)
Compiler:    Borland Turbo C++ 3.1
Bemerkungen: Hoffentlich blickt hier irgendjemand meinen Chaos-Code :)
Greets to:   Compiler-Torsten, Micha Fix
*/

#include<iostream.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>

void main(void)
{
  // Variablendeklaration
  char name[300];
  char temp[100];
  int code[10];
  int zaehler, laenge, index;
  
  // Bildschirm loeschen und Copyright ausspucken!
  clrscr();
  cout << "\nClipmate 5.1.04 Build 119 Keygenerator - "
  << "(c) by Sledge Hammer of Grinder\n\n";
  
  // Name eingeben
  cout << "Bitte Name eingeben: ";
  gets(name);
  
  // In Grossbuchstaben umwandeln
  strupr(name);
  
  // Laenge merken
  laenge=strlen(name);
  
  // Nur Zeichen A-Z zulassen!
  index=0;
  for (zaehler=0;zaehler<=laenge;zaehler++)
  {
    if (name[zaehler]>=65&&name[zaehler]<=90)
    {
      temp[index]=name[zaehler];
      index++;
    }
    temp[index]='\0'; // Hehe... Die magische 0 anhaengen!
  }
  
  // 10 Mal in name kopieren (Damit wir genug zum berechnen haben :)
  name[0]=0; // String loeschen!
  for (zaehler=0;zaehler<=10;zaehler++) strcat(name,temp);
  
  // So und ab hier geht die Berechnung los! (Gut aufpassen)
  // (Asciiwert des Buchstabens * Buchstabennummer) modulo 10
  for (zaehler=0;zaehler<=10;zaehler++)
  {
    code[zaehler]=(name[zaehler]*zaehler) % 10;
  }
  
  // 1. Buchstaben neu berechnen
  // Asciiwert des 1. Buchstabens modulo 10
  code[0]=(name[0] % 10);
  
  // 8. Buchstaben neu berechnen
  // (Asciiwert des 4. Buchstabens * 2 - Asciiwert des 14. Buchstabens) modulo 10
  code[7]=((name[3]*2-name[13]) % 10);
  
  // 10. Buchstaben neu berechnen
  // (Asciiwert des 10. Buchstabens * 2) modulo 10
  code[9]=((name[9]*2) % 10);
  
  // Die eigentliche Codeausgabe
  // Erstmal BlaBla
  cout << "Die Seriennummer lautet: ";
  // Dann das bekannte Q01
  cout << "Q01";
  // und schliesslich unseren berechneten Code
  for (zaehler=0;zaehler<=9;zaehler++) cout << code[zaehler];
  // schon sind wir fertig :)
}

Back to Real Life... Das Schlusswort!

So, ich hoffe euch hat es Spass gemacht dieses Tutorial zu lesen und vor allem habt ihr moeglicherweise etwas Interessantes dazugelernt...

Ich hab mir die ganze Arbeit NICHT gemacht, damit ihr einen funktionierenden Key fuer Clipmate habt sondern wirklich nur um zu zeigen wie so eine Key-Routine funktioniert. Das es dabei Clipmate erwischt hat, war eher Zufall.

Wenn ihr das Programm regelmaessig benutzt, lasst euch bitte registrieren denn jeder (ok, auch da gibts Ausnahmen) Programmierer hat sich sein Geld wirklich verdient! Und je mehr Shareware Programme ihr kauft, desto besser werden sie, ist doch logisch, oder?

Also bitte verwendet dieses Tutorial nicht illegal! Danke!

Greetings fly out to:
The Sandman, Compiler-Torsten, Micha Fix, alle Leutz aus der ehemaligen Atari-Szene (Animal Mine, Synergy, Aura, The Lost Boys, Germs und wie sie alle hiessen), alle Leutz die jemals mit mir im Grinder Projekt gearbeitet haben (Cyberpunk, Scraper, Kermit, Masterboy, Sir Bit usw. Hoffentlich hab ich da jetzt niemanden vergessen...) natuerlich auch alle Amiga-Freax da es wohl die treuesten Computerfreax sind, die es gibt, Twister-Klaus, Alex, Andi, Peter, Roland, Moritz, Puffi, ID-Software fuer Doom/Quake, Pantera, Black Sabbath, Judas Priest, Sick of it all und alle anderen die sich angesprochen fuehlen....

Und bitte Leute vergesst neben der ganzen Computerei das Real Life nicht, denn es ist mindestens genauso spannend wie so eine Keyroutine :) In diesem Sinne: Party on dudez!

Euer Sledge Hammer / Grinder


(c) by Sledge Hammer of Grinder 1999 - Use only for legal purposes!