Cracking Tutorial Nr.3
Der Stack: Was es damit auf sich hat, und wie er uns hilft. 
Hubertus Loobert
eMail: ger.tuts@redseven.de

Voraussetzungen: Das Lesen meiner beiden ersten Tuts. Assemblerkentnisse sind von Vorteil.



			***************************Vorwort********************************

Fr jemand, der ernsthaft in Assembler programmiert, ist der Stack ein wichtiger Bestandteil seiner Arbeit. Fr die Arbeit eines Crackers sollte dies genauso gelten. Doch leider ist es meines Anscheins nicht so. In Tutorials wird der Stack zu 95% nicht erwhnt. Und wenn er erwhnt wird, dann ist er nur als Kommentar hinter einem PUSH oder POP Befehl zu finden("Rauf auf den Stack!" "Runter!"). Doch diese wohl in keinster Weise ausreichenden Erklrungen helfen dem Leser nicht weiter. Deswegen werde ich in diesem Tutorial versuchen den Stack in seiner Funktionsweise und seiner Funktion an sich zu erklren.

Den Stack ganz zu erklren geht etwas weiter in die Assemblerprogrammierung hinein als die normalen Themen eines Tutorials. 
Troztdem werde ich versuchen meine Ausfhrungen und Erklrungen so klar wie mglich zu halten. Ich werde mich auerdem auf die relevanten Themen beschrnken, und z.B. nicht erklren, warum der Stack so strukturiert ist und nicht anders. Wer sich fr solche Details interessiert, mge sich doch bitte ein Buch zu diesem Thema besorgen.




1.			*************************Der Aufbau des Stacks**********************

In meinem letzten Tutorial habe ich erwhnt, da die Adresse des Stacks durch die Registerkombination "SS:ESP" definiert ist. Diese Aussage ist an sich nicht ganz korrekt, denn diese Adresse ist das Ende! des Stack. In SoftIce kann man sich diese Adresse mittels dem Befehl "d esp" anzeigen lassen("D SS:ESP" ist nicht ntig, denn SoftIce bezieht automatisch auch das Register SS mit ein). Eine weiteres Register spielt im Zusammenhang mit dem Stack eine wichtige Rolle: EBP('base pointer register'). Dieses Register gibt den Anfang des aktuellen Bereiches des Stack an.
Bevor wir weiter uns mit dem Anfang und Ende des Stack beschftigen, mu als erstes geklrt werden, wie der Stack 'wchst'. Man knnte meinen, da ESP auf eine Speicherstelle zeigt, die immer erhht wird, wenn man durch den Befehl PUSH einen Wert auf den Stack kopiert wird. Doch genau das Gegenteil ist der Fall: Der Stack wchst nach unten. Somit wird ESP immer verringert, wenn man einen Wert kopiert, bzw. erhht, wenn man einen Wert vom Stack herunterholt. An dieser Stelle mchte ich auch gleich klren, um wieviel das Register ESP erhht, bzw. verringert wird: Nmlich um 4. Dies kommt daher, da immer ein DWORD auf den Stack kopiert wird, welches maximal 4 Byte gro ist. Um es klar zu stellen: ESP wird !immer! um 4 erhht bzw. verringert. Auch wenn zum Beispiel der Befehl "push ah" nur ein 1 Byte kopiert.
Wenn ein Programm zum Beispiel die Register EAX, EBX eund ESI auf den Stack kopiert durch die folgenden Befehle, so verringert sich der Wert von ESP jeweils und 4 pro Befehl und zeigt dadurch auf das unterste und damit auf den letzten verfgbaren Wert.


Die Befehle
			PUSH EAX
			PUSH EBX
			PUSH ESI

erzeugen folgendes Bild auf dem Stack:

			
			EAX
			EBX
		ESP=>	ESI

ESP zeigt auf den zu letzt kopierten Wert ESI. ESP+4 zeigt auf EBX und ESP+8 zeigt auf EAX. ESP wird vom Prozessor verwaltet, so da man sich als Programmierer nicht um dieses Register kmmern mu. Im Gegensatz zu EBP. Das bas pointer register wird vom Programmierer verwaltet, bzw. der Compiler verwaltet es bei Hochsprachen wie C oder Pascal. Wie oben erwhnt zeigt EBP auf den Anfang des aktuellen Bereiches des Stack. In diesem zusammenhang sind folgende berlegungen wichtig:
Ein sehr wichtiger Bestandteil jedes Programmes, egal in welcher Sprache, sind Funktionen. Ein Funktion ist ein Unterprogramm, welches mitunter sehr komplex ist und seine eigenen Variablen. Ein Funktion, die z.B. einen Registrierungscode aus einem als Parameter bergebenen Namen. Ein Programm mit solch einer Funktion ist z.B. Winamp(siehe vorhergehendes Tutorial). Ein solches Unterprogramm hat seinen eigenen Bereich auf dem Stack, welche durch die Register ESP (zeigt auf das Ende) sowie EBP (zeigt auf den Anfang) angegeben sind. Ein Parameter wird dadurch bergeben, da er vor dem Aufruf auf den Stack kopiert wird.

Das sieht wie folgt aus:

			PUSH EAX	// Der Parameter wird auf den Stack kopiert. ESP zeigt danach auf diesen.
			CALL ????????	// Die Funktion wird aufgerufen.

Der Befehl CALL kopiert das Register EIP (Dieses Register enthlt die aktuelle Adresse des Programmes. Es wird auf den Stack kopiert damit der Prozessor wei, wo er mit der Arbeit fortfahren mu, wenn das Unterprogramm beendet ist.) auf den Stack. 
Nachdem diese beiden Befehel ausgefhrt sind, sieht der Stack so aus (Wichtig: Um es in SoftIce nachzuvollziehen mu man in den Call gehen mit der Taste F8):


			EAX	// Der Parameter
		ESP=>	EIP	// Die Adresse, von der der CALL Befehl erfolgt ist 

Nachdem der CALL erfolgt ist und das Programm befindet sich am Anfang der Funktion. Als aller erstes wird jetzt der Bereich auf dem Stack definiert, welcher die Funktion benutzt. Dies erfolgt folgendermaen:
Das Register EBP wird gesichert, dadurch, da es auf den Stack kopiert wird. Danach wird EBP mit dem Wert von ESP geladen. 
Diese Befehle:
		PUSH EBP	// Speichert EBP
		MOV EBP,ESP	// EBP wird mit dem Wert ESP geladen

erzeugen folgendes Bild:

			EAX						// Der Parameter
			EIP						// Die Adresse, von der der CALL Befehl efolgt ist
		ESP=>	EBP	<=EBP					// Das gesicherte 'base point register'

ESP zeigt auf das gerette EBP Register. EBP zeigt ebenfalls auf diese Adresse. Doch dies ist noch nicht ausreichend. Danach wird eine Zahl von ESP abgezogen, die die private Gre des Stacks definiert. (In Winamp ist dies z.B. die Zahl 100h). Nachdem nun auch der Befehl "sub esp,xx" ('xx' ist eine bestimmte Zahl, die von Unterprogramm zu Unterprogramm verschieden ist.) 

Danach hat sich das Bild vom Stack so verndert:

			EAX						// Der Parameter
			EIP						// Die Adresse, von der der CALL erfolgt ist
			EBP	<=EBP					// Das gesicherte 'base point register'
			.						// Freier Platz
			.
			.
			.
		ESP=>	.						// ESP zeigt auf das Ende des privaten Stack

Der Platz zwichen EBP und ESP ist somit frei. Dieser Platz wird durch das Register EBP angsprochen. EBP-4 zeigt auf den ersten freien Platz. EBP-100 auf den letzten. Doch warum spricht man diese Speicherstellen nicht durch ESP an? Weil jedesmal wenn im weiteren Verlauf des Programmes ein PUSH Befehl erfolgt verndert sich ESP. Somit ist ESP nicht mehr gleich ESP am Ende des Unterprogrammes. Am Ende des Unterprogrammes wird ESP mit dem Wert von EBP berschrieben. Danch zeigt ESP wieder auf den gesicherten EBP Wert. Danach wird mittels des POP Befehls dieser Wert wieder vom Stack in das Register EBP kopiert. Das sieht so aus:

		MOV ESP,EBP	// ESP wird mit dem Wert von EBP berschrieben
		POP EBP		// Der gesicherte EBP Wert wird wieder in das Register EBP geschrieben
		RET		// RET beendet das Unterprogramm

Nach den ersten beiden Befehlen zeigt ESP wieder auf den vom CALL Befehl abgelegten Wert aus EIP. Dieser Wert wird durch den RET Befehl vom Stack wieder in das EIP Register kopiert. Dadurch wird das Unterprogramm beendet und das Programm wird von dort fortgesetzt von wo der CALL Befehl erfolgt ist.
Ein Befehl der das gleiche bewirkt wie 
					MOV ESP,EBP
					POP EBP
ist der Befehl LEAVE.


Diese beschriebenen Befehle lassen sich sehr gut in Winamp nachvollziehen. Dazu siehe letztes Tutorial.


2.				*************Ein Beispiel fr Parameterbergabe************

Ein sehr gutes Beispiel fr Parameterbergabe sind die von allen Crackern benutzten API Funktionen. Die wohl wichtigsten dieser API Funktionen sind 'GetWindowText' und 'GetDlgItemText'. Diese Funktionen haben folgenden Syntax:

Fr die Funktion GetDlgItemText:

UINT GetDlgItemText(
  HWND hDlg,       // handle der Dialog Box
  int nIDDlgItem,  // Spezifiziert genauer was gemeint ist
  LPTSTR lpString, // Dies ist ein Zeiger auf die Stelle, wo der Inhalt hinkopiert wird
  int nMaxCount    // Gibt die Maximale Gre des Textes an
);


Fr die Funktion GetWindowText:

int GetWindowText(
  HWND hWnd,        // Gibt an von wo etwas kopiert werden soll
  LPTSTR lpString,  // Zeiger auf die Stelle, wo der Text hinkopiert wird
  int nMaxCount     // Gibt die Maximale Gre des Textes an
);



Einige fragen sich vielleicht was die Defintionen dieser Funktionen bringen. Dies kommt ganz darauf an: Wenn man an ein Programm herangeht mit dem Ziel dazu ein Patch zu schreiben setzt man einen Breakpoint auf diese Funktion, einzig und allein um in das Programm hineinzukomen. Man geht gewhnlich dann durch den Code und sucht nach der Stelle, die man patchen mu. 
Doch was ist, wenn man mit dem Ziel herangeht eine Serial zu bekommen oder gar einen Keygen zu schreiben, sind diese Funktionen sehr ntzlich. Durch diese API-Calls wei man genau, wwo das Programm zum ersten Mal wei, was der Benutzer eingegeben hat und wo sich diese Daten befinden.
Wie wir oben gelernt haben bergibt ein Programm ein Argument an ein Unterprogramm dadurch, da es vor dem Call diese Werte auf den Stack kopiert. Auch hier ist das der Fall; doch mu man eine Besonderheit beachten: In C/C++ Programmen werden die Argumente in umgekehrter Reihenfolge auf den Stack kopiert, als es der Programmierer angibt. Bei unserern API-Calls bedeutet es, da es so in Assembler aussieht:

	PUSH [Argument4]		// Gibt die Maximale Gre des Textes an
	PUSH [Argument3]		// Dies ist ein Zeiger auf die Stelle, wo der Inhalt hinkopiert wird
	PUSH [Argument2]		// Spezifiziert genauer was gemeint ist
	PUSH [Argument1]		// handle der Dialog Box
	CALL [USER32!GetDlgItemTextA]	// Aufruf der API Funktion

bzw.
	
	PUSH [Argument3]		// Gibt die Maximale Gre des Textes an
	PUSH [Argument2]		// Zeiger auf die Stelle, wo der Text hinkopiert wird
	PUSH [Argument1]		// Gibt an von wo etwas kopiert werden soll
	CALL [USER32GetWindowTextA]	// Aufruf der API Funktion

Wie gesagt: Wir interessieren uns fr den bergebenen Text. Dieser ist mit dem zweiten gepushten Wert zu finden. Die anderen Parameter sind fr uns uninteressant. 
Diese Ereignisse lassen sich mit jedem Programm nachvollziehen, welches diese Funktionen nutzt.

Nach dieser Einfhrung, sollte es keine Probleme mehr mit dem Stack geben.

Falls doch; oder wegen Kritik oder Anmerkungen, oder sonstigem:

ger.tuts@redseven.de










