Opfer : Quintessential CD v1.27
Woher : www.quinnware.com/qcd
Author: Terminal Cilla


			Hiya Leute,
letztes mal haben wir einen built-in-keygen gebaut - 
heute wollen wir einen 'richtigen' Keygen programmieren.
Ich muss dazu sagen, da ich eigentlich so gut wie nie
Keygens mache, da ich immer viel zu schnell die Lust am Code
verliere (vorallem wenn's nicht gleich beim ersten Versuch klappt:).
Was Ihr heute bruchtet sind cracker-asm-Kenntnisse. 

Zum Opfer:
Was das Programm auer CDs abspielen so alles kann, wei ich ehrlich
gesagt nicht - ist ja auch nicht so wichtig fr unsere Zwecke.
Das Schne am Programm ist seine Reg.Routine, die absolut
'newbie-compatible' ist.
Fr diejenigen, die nur 'ne Serial wollen, werden sich ber ein
simples: "cmp falsch, richtig" freuen. Ansonsten werden wir
ein bichen den Code nach Delphi/Pascal bersetzen - ich hoffe, da
Ihr Delphi einigermaen versteht.
Ich werde Euch versuchen zu zeigen, da es manchmal sehr einfach
sein kann einen Keygen zu programmieren, indem man einfach die
asm-Befehle bersetzt und dann einfach umschreibt. 
Natrlich mssen wir auch wissen was wir machen;)
Los geht's...

Mit 'GetDlgItemTextA' als Breakpoint sollten wir schnell hierher kommen:

---
:00412D09 684D040000              push 0000044D
:00412D0E 56                      push esi
:00412D0F FFD7                    call edi
:00412D11 8D542418                lea edx, dword ptr [esp+18]
:00412D15 52                      push edx ->unser Name
:00412D16 E815C1FFFF              call 0040EE30 ->HIER!!!
:00412D1B 83C404                  add esp, 00000004
:00412D1E 8BF8                    mov edi, eax
:00412D20 8D44240C                lea eax, dword ptr [esp+0C]
:00412D24 50                      push eax
:00412D25 E846BDFFFF              call 0040EA70 ->fr uns unwichtig
:00412D2A 83C404                  add esp, 00000004
:00412D2D 3BF8                    cmp edi, eax ->Hmm, ist das billig;)
:00412D2F 750D                    jne 00412D3E ->Wenn SN richtig dann spring
:00412D31 6A01                    push 00000001
---

Wir sehen uns erstmal die Register bei :00412D2D an.
EDI enthlt die richtige Serial, EAX unsere Falscheingabe.
Jetzt schauen wir mal, wo die richtige Serial das erste mal
auftaucht...
...aha, nach dem call bei :00412D16 hat EAX unser Baby.
Das bedeutet fr uns, da wir in den call tracen werden,um zu
schauen, was der call anstellt.
Die Tatsache, da unser Name als Parameter dem call bergeben
wird, lt uns vermuten, da hier die zugehrige Seriennummer
errechnet wird. Mal sehen, ob das stimmt:)

---
(*) EAX ist 1 beim ersten Durchlauf

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040EE7D(C)
|
:0040EE5B 85D2                    test edx, edx	------------------------<----------------		
:0040EE5D 7420                    je 0040EE7F				    		|
:0040EE5F 8A0A                    mov cl, byte ptr [edx]->ein Zeichen weiter   		|
:0040EE61 80F920                  cmp cl, 20  ->Leerzeichen im Name?	    		|
:0040EE64 7411                    je 0040EE77 ->gehe zum nchsten Zeichen   		|
:0040EE66 0FBEC9                  movsx ecx, cl ->Zeichen nach ecx	   		|
:0040EE69 8BD8                    mov ebx, eax	->EAX nach EBX (*)	   		|
:0040EE6B 8D0440                  lea eax, dword ptr [eax+2*eax] EAX:=EAX+(2*EAX)	^
:0040EE6E 0FAFD9                  imul ebx, ecx ->EBX:=EBX*ECX		    		|
:0040EE71 03DE                    add ebx, esi	->EBX:=EBX+ESI		    		|
:0040EE73 03FB                    add edi, ebx	->EDI:=EDI+EBX		    		|
:0040EE75 03F1                    add esi, ecx	->ESI:=ESI+ECX		    		|
:0040EE77 8A4A01                  mov cl, byte ptr [edx+01]->nchstes Zeichen einlesen	|
:0040EE7A 42                      inc edx	->EDX:=EDX+1		    		|	
:0040EE7B 84C9                    test cl, cl ->letzter Buchstabe erreicht? 		|
:0040EE7D 75DC                    jne 0040EE5B -------------------------->--------------
:0040EE7F 33D2                    xor edx, edx ->EDX=0
:0040EE81 B9FFFF0000              mov ecx, 0000FFFF ->ECX:=FFFFh
:0040EE86 F7F1                    div ecx ->EDX:= EAX mod ECX
:0040EE88 8BC7                    mov eax, edi ->EDI nach EAX
:0040EE8A BFFFFF0000              mov edi, 0000FFFF ->EDI:=FFFFh
:0040EE8F 8BCA                    mov ecx, edx ->EDX nach ECX
:0040EE91 99                      cdq ->EDX=0
:0040EE92 F7FF                    idiv edi ->EDX:=EAX mod EDI
:0040EE94 8BC6                    mov eax, esi ->ESI nach EAX
:0040EE96 BEFF000000              mov esi, 000000FF ->ESI:=FFFFh
:0040EE9B C1E210                  shl edx, 10 ->EDX:=EDX shl 10h
:0040EE9E 0BCA                    or ecx, edx ->ECX:=ECX or EDX
:0040EEA0 99                      cdq  ->EDX:=0
:0040EEA1 F7FE                    idiv esi ->EDX:= EAX mod ESI
:0040EEA3 0BCA                    or ecx, edx ->ECX:=ECX or EDX
:0040EEA5 8BC1                    mov eax, ecx ->ECX nach EAX ->SN!!!
:0040EEA7 5F                      pop edi
:0040EEA8 5E                      pop esi
:0040EEA9 5B                      pop ebx
:0040EEAA C3                      ret
---

Wie Ihr seht, habe ich schonmal die Erluterungen rangeschrieben.
Wir bernehmen einfach die Struktur fr unseren Keygen.
In Delphi sieht das dann so aus:

---
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var 	eax,ebx,edi,edx,ecx,esi : Longint;
    	Name, Serial            : String;
	index		        : Integer;
	
Begin
eax:=1;
ebx:=0;
ecx:=0;
esi:=0;
Name:=edit1.text; {Einlesen des Namens}
If length(name)<6 then begin
                       showmessage('Name muss mind. 6 Zeichen lang sein!');
                       EXIT;
                       end;
 
 For index:=1 to Length(Name) do {------------------<--- 
  Begin							|
	If Ord(Name[index])<>32 then {Leerzeichen?}	|
	Begin						|
	 ebx:=eax;					|
	 eax:=eax+2*eax;				|
	 ebx:=ebx*Ord(Name[index]);			^
	 ebx:=ebx+esi;					|
	 edi:=edi+ebx;					|
	 esi:=esi+Ord(Name[index])			|
	end else					|
   end;                      {---------------------->----

  {Letzter Buchstabe erledigt...}

	ecx:= $FFFF;
	edx:= eax mod ecx;

	eax:= edi;
	edi:= $FFFF;
	ecx:= edx;
	edx:= eax mod edi;
	eax:= esi;
	esi:= $FF;
	edx:= edx shl 16;

	ecx:= ecx or edx;
	edx:= eax mod esi;
	ecx:= ecx or edx;

{Ausgabe, ECX hlt die Serienummer}
Edit2.text:=inttohex(ecx,8);
end;
end.
---

Wenn Ihr den Originalcode mit unserem Kg-code vergleicht, werdet Ihr
feststellen, das es fast eine exakte Kopie der eigentliche Routine ist.
Ich habe extra die Registernamen bernommen, um dies zu veranschaulichen.
Sicherlich kann man den ganzen Kg-code noch optimieren, aber so ist es
doch glaub' ich bersichtlicher.
Eins muss allerdings noch erwhnt werden:
	Der Name muss mindestens 6 Zeichen beinhalten.
	Wieso das so ist, kann man bei :0040EE47 nachlesen, wo
	ein 'cmp ecx, 00000006' steht. Wobei ECX die Lnge
	unseres Namens beinhaltet.

Eigentlich war es das nun schon. Es geht jedoch nicht immer
so einfach, wie bei 'Quintessential CD':( - davon abgesehen
das keygen-ing eh meine Schwche ist. 

Ich hoffe ich konnte Euch etwas vermitteln - in diesem Sinne...
		...bye.


----------------------------------------------------------------------------
Falls ich etwas Falsches erzhlt haben sollte, dann informiert
mich bitte - ich bin halt auch nur ein newbie...
...danke.
----------------------------------------------------------------------------
			Peace&Respect to: 
	  Bjanes, DnNuke, TRDonJuan, Loki und Adrenalin.

Spezielle Gre an: 	Kati  		- ...bitte,bitte
			rubor 		- mein Keygen - Idol;)
			Mr.X & Mr.Y	- fr musikalische Untersttzung
			
(c) Terminal Cilla (Juni 1999) [BeAm.To/CUG]
    bombasticx@gmx.net

