Opfer : Glcksrad95 - Version 1.06
Woher : www.shareware.de
Author: Terminal Cilla


			Hiya Freunde,
heute wollen wir mal schaun, ob wir ein Keygen zu Glcksrad95
basteln knnen. Das besondere dabei wird sein, das wir den
Keygen bauen werden ohne zu wissen, was die Registrierungsroutine
macht - ich rede von 'built-in-keygen'.
Wir werden das Programm dahingehend vergewaltigen, da es uns
freiwillig:) die gewnschte Seriennummer ausspuckt.
Das Schne an built-in-keygens ist, da man gar nicht zu wissen
braucht, was die Registrierungsroutine eigentlich anstellt. Wir
spielen nur ein wenig mit Registern 'rum.
Theoretisch kann man aus allen Reg.Routinen, die nach dem Schema:

		'cmp falsche_serial, richtige_serial'
				
				oder

			'push richtige_serial
			 push falsche_serial
			 call vergleiche_beide'

...verlaufen einen built-in-keygen machen. Wir brauchen blo einen
Register, der die richtige Serial hlt.
Das war die erste Bedingung, die meist schon ausreicht um 'stumme'
b-i-kg zu bauen. 
Wir wollen jedoch einen b-i-kg, der uns in Form einer MessageBox
ber die richtige Serial informiert.
Idealerweise benutzt man dafr die jeweilige Fehlermeldung der
Reg.Routine. Optimal wre hierbei, wenn die Fehlermeldung
in Form von:

		'push bla  (Titel der Box) 
		 push bla2 (Text der Box)
		 call messagebox'

...erscheint.
Nun, bei unserem heutigen Opfer wird das der Fall sein.
Eins noch vorweg, am Ende dieses Tutorial haben wir
einen MemoryPatcher gebastelt - nur so zur Einstimmung;).

Zu unserem Opfer:
Seit ich West-Fernsehen schauen konnte (huch jetzt habe ich mich geoutet;),
ging mir damals, wie heute das GLCKSRAD erheblich auf den Wecker.
Um so mehr freue ich mich darauf, es diesem beknackten Rad heimzuzahlen:)
Nee nee, Spa beseite - lasst uns in den Kampf gehen.


Ich setze das Finden unserer Reg.Routine einfach mal voraus.
Wie auch immer - wir sollten folgendes vor Augen haben:

---
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00488EFC(C)
|
:00488F16 8D55FC                  lea edx, dword ptr [ebp-04]
...
...
...
:00488F7C 8B55F0                  mov edx, dword ptr [ebp-10] ->Falsche SN!
:00488F7F 58                      pop eax                     ->Richtige SN!
:00488F80 E803B0F7FF              call 00403F88               ->Vergleich
:00488F85 741D                    je 00488FA4 ->Springe wenn SN richtig
:00488F87 6A10                    push 00000010
---

So, nachdem wir mit SoftIce ein wenig herumgeschaut haben, wissen
wir das EDX unsere Falscheingabe enthlt und EAX die richtige
Seriennummer aus dem Stack bekommt.
Der darauffolgende call dient lediglich zum Vergleichen der beiden,
ist fr uns aber relativ unwichtig.
Was wichtig ist, ist die Tatsache, da nach dem call EAX nicht mehr
unsere richtige Serial enthlt. Das merken wir uns erstmal.

Nun schauen wir, ob wir eine passende Ausgabemglichkeit finden.
Die zugehrige Fehlermeldung erfllt unsere Ansprche.

---
* Possible StringData Ref from Code Obj ->"Fehler"
                                  |
:00488F89 B970904800              mov ecx, 00489070

* Possible StringData Ref from Code Obj ->"Der eingegebene Code ist falsch, "
                                        ->"bzw. pa"
                                  |
:00488F8E BAE4904800              mov edx, 004890E4 ->HIER!!!
:00488F93 A15C3A4900              mov eax, dword ptr [00493A5C]
:00488F98 8B00                    mov eax, dword ptr [eax]
:00488F9A E82D00FCFF              call 00448FCC
:00488F9F E98E000000              jmp 00489032
---
 
SoftIce hilft uns wieder herauszufinden, was sich in den Registern
befindet. Idealerweise bietet sich 'mov edx, 004890E4' an. Normalerweise
wrde EDX den Fehlermeldungstext enthalten, 
nachdem wir dran waren nicht mehr;)
Unser Ziel: Statt des Textes die richtige Seriennummer!

Ok, wir haben alles was wir brauchen: das Register, welches
die richtige SN enthlt (EAX) und einen Platz, wo wir
sie unterbringen knnen.
Erinnern wir uns, nachdem call bei :00488F80, hat EAX nicht mehr die
Seriennummer. Was sagt uns das? 
Richtig, der call sollte nicht ausgefhrt werden. Warum auch,
die Serial haben wir ja lngst. Also nop-en wir das ganze und
den Jump bei :00488F85 gleichdazu.
Das ganze sieht jetzt ungefhr so aus:

---
:00488F7C 8B55F0                  mov edx, dword ptr [ebp-10] 
:00488F7F 58                      pop eax                     
:00488F80 90                      nop      
:00488F81 90			  nop
:00488F82 90     		  nop
:00488F83 90			  nop
:00488F84 90			  nop
:00488F85 90			  nop	
:00488F86 90                      nop
:00488F87 6A10                    push 00000010

* Possible StringData Ref from Code Obj ->"Fehler"
                                  |
:00488F89 B970904800              mov ecx, 00489070

* Possible StringData Ref from Code Obj ->"Der eingegebene Code ist falsch, "
                                        ->"bzw. pa"
                                  |
:00488F8E BAE4904800              mov edx, 004890E4 ->HIER!!!
:00488F93 A15C3A4900              mov eax, dword ptr [00493A5C]
:00488F98 8B00                    mov eax, dword ptr [eax]
:00488F9A E82D00FCFF              call 00448FCC
:00488F9F E98E000000              jmp 00489032
---

So, jetzt behlt EAX erstmal seine wertvolle Fracht.
Nun ndern wir einfach den Inhalt von EDX.
Und in was? 
Was wre, wenn wir EAX nach EDX packen wrden?
Genau, der Inhalt von EAX wrde in der MessageBox als Text auftauchen.
Also ndern wir das ganze nochmal:

---
:00488F7C 8B55F0                  mov edx, dword ptr [ebp-10] 
:00488F7F 58                      pop eax                     
:00488F80 90                      nop      
:00488F81 90			  nop
:00488F82 90     		  nop
:00488F83 90			  nop
:00488F84 90			  nop
:00488F85 90			  nop	
:00488F86 90                      nop
:00488F87 6A10                    push 00000010

* Possible StringData Ref from Code Obj ->"Fehler"
                                  |
:00488F89 B970904800              mov ecx, 00489070

* Possible StringData Ref from Code Obj ->"Der eingegebene Code ist falsch, "
                                        ->"bzw. pa"
                                  |
:00488F8E 8BD0                    mov edx, eax -> HIER!!!
:00488F90 90			  nop
:00488F91 90			  nop
:00488F92 90              	  nop
:00488F93 A15C3A4900              mov eax, dword ptr [00493A5C]
:00488F98 8B00                    mov eax, dword ptr [eax]
:00488F9A E82D00FCFF              call 00448FCC
:00488F9F E98E000000              jmp 00489032
---

Ttert...
...was wir bis jetzt geschafft haben:

1. Wir haben dafr gesorgt, da ein Register die SN enthlt.
2. Wir haben dafr gesorgt, da der Inhalt des SN-Registers angezeigt wird.

Jetzt werden einige sagen: 	"Hey tC - du Depp! Wenn wir das so ndern,
				 haben wir zwar 'ne Serial, aber werden
				 uns nie registrieren knnen, da wir
				 ja den call & jump ge-nop-t haben."

Und Ihr habt recht damit, man knnte zwar die
Reg.Routine so gut wie neu-um-schreiben, aber wir sind ja viel
cleverer:)
Desweiteren finde ich es persnlich nicht so toll, wenn man 
ein Programm unntigerweise zu sehr entfremdet - man msste
sich ja dann gleich noch als Co-Author eintragen lassen;)
Wir werden es geschickter anstellen, indem wir einen MemoryPatcher
benutzen werden, das wirkt zudem professioneller:).
Das witzige an diesen Patchern ist, da sie nur im Speicher patchen
und die eigentliche Datei unberht lassen.
Bei uns sollte es dann so ablaufen, da man mit hilfe des MemoryPatchers 
die richige Serial aufschreiben kann, das Programm neu startet und
es 'ganz normal' registriert.

Ich habe jetzt zwei verschiedene MemoryPatcher sources fr Euch.
Einmal in C und dann nochmal in Delphi.
Ich gehe davon aus, das Ihr in einer dieser Sprachen coden knnt.

---C-source using LCC-Compiler---------:

#include <windows.h>

void main(void)
{
STARTUPINFO si;
char* cl;
PROCESS_INFORMATION pi;

ZeroMemory(&si,sizeof(si));
si.cb = sizeof(si);
cl = GetCommandLine();

if (CreateProcess("glksrd95.exe", cl, NULL, NULL,FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi))
{

// PATCH IT IN MEMORY
WriteProcessMemory (pi. hProcess, (LPVOID) 0x488F80, "\x90\x90\x90\x90\x90\x90\x90", 7, NULL);
//patche ab Adresse 00488F80 - 7*Nops
WriteProcessMemory (pi. hProcess, (LPVOID) 0x488F8E, "\x8B\xD0\x90\x90\x90", 5, NULL);
//patche ab Adresse 00488F8E - 1*mov edx, eax, 3*Nops

CloseHandle (pi.hProcess);
CloseHandle (pi.hThread);
}

else

MessageBox(NULL,
"glksrd95.exe nicht gefunden!",
"Glcksrad Keygen", MB_OK);

}

---Ende---

Den Original-Quellcode entnahm ich Torn@do's Tutorial ber
'MM Fireworks'. Vielen Dank an dieser Stelle an Torn@do!

---Delphi-source---

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Datei_: String;
  Datei : Pchar;
implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var cl: pchar;
    si:STARTUPINFO ;
    pi:PROCESS_INFORMATION;
    byte_one,byte_two:Byte;
    ad,ad2:cardinal;
    ofs_one, ofs_two: cardinal;
    const patchsize=7;
          patchsize2=5;
          BytesToPatch:array[0..PatchSize-1] of Byte=($90,$90,$90,$90,$90,$90,$90);
          BytesToPatch2:array[0..PatchSize2-1] of Byte=($8B,$D0,$90,$90,$90);
    begin
    ofs_one:=$488F80;
    ofs_two:=$488F8E;

ZeroMemory(@si,sizeof(si));
si.cb := sizeof(si);
cl := GetCommandLine();

If (CreateProcess(Datei, cl, 0, 0 ,FALSE, NORMAL_PRIORITY_CLASS,
0, 0, si, pi)) then begin

WriteProcessMemory (pi. hProcess, pointer(ofs_one) ,@BytesToPatch, patchsize, ad);
WriteProcessMemory (pi. hProcess, pointer(ofs_two) ,@BytesToPatch2, patchsize2, ad2);

CloseHandle (pi.hProcess);
CloseHandle (pi.hThread);

end
else Begin ShowMessage('Error...');Exit;
 end;end;

procedure TForm1.Button2Click(Sender: TObject);{Button, um Datei auszuwhlen}
begin
If OpenDialog1.Execute then Begin
Datei_:=OpenDialog1.FileName;
end;
Datei:=Pchar(Datei_);
end;

end.
---Ende---

Vielen Dank hierbei an The AntiXryst, der mir half den Code an einigen
Stellen zu optimieren.

Was passiert hier nun eigentlich?
Also, wenn Ihr einen der Patcher started, ldt er unser
Opfer - alles ist ganz normal, blo das diesmal die notwendigen
Stellen im Speicher gepacht sind und wir somit bei einer Falschangabe
beim Registrieren die richtige Serial in einer MessageBox prsentiert
bekommen werden.
Diese schreiben wir uns auf. Beenden das Programm - der Patcher beendet
sich dadurch automatisch - und starten das Programm nun ohne den Patcher -
also nur die 'glksrd95.exe' anklicken:)
Wir geben unsere notierte Serial ein und freuen uns, da wir nun
Glcksrad bis zum Umkippen spielen drfen.
Und wenn wir 'ne andere Serial wollen, starten wir halt Glcksrad
wieder mit dem Patcher und holen uns eine neue Seriennummer.
Und nicht vergessen, wir verndern nie das eigentliche Programm!

Puhh, mir reicht's jetzt erstmal - ich hoffe Ihr konntet 
aus diesem Schrieb etwas Brauchbares mitnehmen...

...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: 
	duelist, Torn@do, TheAntiXryst, rubor und Sanhedrin.

Spezielle Gre an: 	Kati  		- nur eine Nacht, bitte,bitte
			Otto  		- Ich bin nicht schwul, blo weil
			        	  ich mit solchen Leuten rumhnge!
			rubor 		- for beeing a friend
			TheAntiXryst 	- for killing me all the time:)
			DarkDorc 	- weil Du mir immer 'n Platz 
					  in der Cafeteria freihlst:) 
			Torn@do 	- fr Deine Tutorials 
					  (Pflichtlektre!)
			
(c) Terminal Cilla (Juni 1999) [bEam.To/CUG]
    bombasticx@gmx.net


