Maschinencode zur Laufzeit generieren und ausführen

thekiller

Viceinator
Nabend,

im Titel ist ja eigentlich schon die hälfte beschrieben. Ich möchte eine Anwendung entwickeln die Maschinencode zur Laufzeit generieren kann. Programmiersprache ist natürlich C/C++ und das ganze unter Windows. Vorerst Visual Studio falls das wichtig sein sollte.
Kann in einfach allokiertem Speicher (mit malloc() oder new) Code ausgeführt werden? Wie kodiere ich die Maschinenbefehle im Speicher? Und wie setze ich den Ausführungspunkt der Anwendung in meinen Speicher? Einfacher jump mit Assembler?
Google sagt mir irgendwie nicht viel zu dem Thema oder ich suche mit den falschen Begriffen.

MfG
Manuel
 
Hi

Teilproblem 1:
Woraus besteht das Ausgangsmaterial?
Völlig beliebiger Code?
Oder gibts Gemeinsamkeiten?

(Was soll das am Ende eigentlich werden?)
 
Ausgangsmaterial für was? Für den Anfang würde es mir reichen wenn ich in dem generierten Code eine einfache Funktion aufrufen könnte die nach der Ausführung wieder zurückspringt und die Ausführung fortsetzt. Wie es halt üblich ist.
 
Mit Ausgangsmaterial mein ich:
Soll wirklich aus Quellcode, wie er auch in VS steht, ausführbares Zeug gemacht werden,
oder aus was?
 
Ich versteh deine Frage so, dass aus C/C++ Quellcode Maschinencode erzeugt werden soll!?
Ich möchte keinen Compiler mit Parser entwickeln! Ich möchte lediglich einen Ausführbaren Speicherbereich haben.

Inzwischen habe ich etwas herumprobiert und es zum Teil hinbekommen.

Hier mal der Code
C++:
void	test() {
	1 + 1;
}

int main(int argc, char *argv[]) {
	short int		mem[1024]	= {0};
	unsigned long	i			= 0;
	LPVOID			execmem		= VirtualAlloc(&mem, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	printf("%p\n", test);

	((short int*)execmem)[i]	= 0xE8;	i++;	// 0xE8 ist der call befehl
	((short int*)execmem)[i]	= ****;	i++;
	((short int*)execmem)[i]	= ****;	i++;
	((short int*)execmem)[i]	= ****;	i++;
	((short int*)execmem)[i]	= ****;	i++;

	_asm {
		call	test;
		jmp 	execmem;
	}

	return 0;
}

Wie bekomme ich nun die Adresse von test() in execmem? Wenn ich die Adresse von test() ausgebe und die Adresse beim "normalen" Aufruf im Debugger über Dissambly anschaue weichen diese von einander ab.

Beispiel:

printf("%p\n", test) sagt mir die Adresse ist 00E2114A
Dissambly sagt mir aber dass die Adresse 80BAFFFF ist

Code:
_asm {
	call	test;
	00E256C5 E8 80 BA FF FF       call        test (0E2114Ah)  

	jmp execmem;
	00E256CA FF A5 60 EF FF FF    jmp         dword ptr [execmem]  
}

Wie komm ich an die richtige Adresse heran?
 
Zuletzt bearbeitet von einem Moderator:
Hallo,

eine Möglichkeit um dynamisch Code zur Laufzeit auszuführen wäre "shellcode". Shellcode's sind normalerweise als Strings bzw. in char[] -Buffern, oft in Form von Hex-Code, hinterlegte Machine-Code Anweisungen die durch verschiedene "Tricks" in-process zur Laufzeit ausgeführt werden können.

Zur Erzeugung von Shellcode geht man AFAIK normalerweise so vor, dass man zunächst die Logik in Assembler definiert und anschließend mit einem Assembler (wie z.Bsp.: nasm) ein entsprechendes Objekt-File (.o oder .obj) in einem plattform-spezifischen Format wie Beispielsweise elf unter linux- bzw. coff bei win32-Umgebungen erzeugt.
Danach wird dieses Object-File mit einem Linker (linux ld, windows link.exe) zu einer ausführbaren Datei gelinked.
Anschließend schaut man sich mit einem Object-Dumper wie objdump oder dumpbin die .text Sektion des binaries an. Den Inhalt der text-Sektion extrahiert man nun und konvertiert den Maschienencode in eine Hex-Repräsentation -> Das ist der Shellcode den wir mit untenstehender Methode ausführen können.

Hier hat man nun die Möglichkeit (unter Windows) mit LoadLibrary und GetProcAddress beliebige Funktionen aus beliebigen DLLs aufzurufen... aber Vosicht... die ProcAddressen der Funktionen bleiben nicht konstant, sondern ändern sich u.U. mit neuen DLL-Versionen.

Hier findest du dazu ein paar Anleitungen für Windows und Linux:
http://www.projectshellcode.com/node/17
http://www.vividmachines.com/shellcode/shellcode.html
Hier gibt es noch ein interessantes Buch zum Thema: Hacking die Kunst des Exploits: http://astore.amazon.de/tutorialsde-21/detail/3898645363

Ausführen kannst du deinen Shellcode dann Beispielhaft wie folgt:
(in dem Beispiel über das casten des char* in eine void-function pointer)
C++:
char* shellcode =   
		"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
		"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";

int main(int argc, char* argv[])
{
	void (*code)();
    code = (void(*)())shellcode; //shellcode als void Funktion-Pointer casten
    (void)(*code)(); //shellcode ausführen

	return 0;
}

Gruß Tom
 
Wie bekomme ich nun die Adresse von test() in execmem? Wenn ich die Adresse von test() ausgebe und die Adresse beim "normalen" Aufruf im Debugger über Dissambly anschaue weichen diese von einander ab.

Beispiel:

printf("%p\n", test) sagt mir die Adresse ist 00E2114A
Dissambly sagt mir aber dass die Adresse 80BAFFFF ist

Code:
_asm {
	call	test;
	00E256C5 E8 80 BA FF FF       call        test (0E2114Ah)  

	jmp execmem;
	00E256CA FF A5 60 EF FF FF    jmp         dword ptr [execmem]  
}
Du hast das Disassemblat falsch interpretiert. E8 steht für einen Prozeduraufruf mit relativer Adresse. 00E256CA (Instruktionszeiger nach dem CALL) + FFFFBA80 (Offset aus dem Disassemblat, Intel Byte Order beachten!) = 00E2114A. Somit gibt printf schon die richtige Adresse aus. Du musst also die Adresse von test relativ zu execmem eintragen. Außerdem solltest du für den allokierten Speicher auch Ausführungsrechte anfordern (PAGE_EXECUTE_READWRITE), sonst gibt es beim Sprung in deinen Code eine Schutzverletzung.

Am einfachsten wäre es allerdings, wenn du eine fertige Bibliothek wie asmjit verwendest, die dir das Assemblieren abnimmt.

Grüße,
Matthias
 
@Thomas Darimont: So wie ich es aus deinem Text lese muss der Shellcode VOR der Ausführung der eigentlichen Anwendung in Maschinencode übersetzt werden. Ich möchte aber, dass der Maschinencode während der Laufzeit generiert wird. Es soll also dynamisch werden.


@Matthias Reitinger: Ah ok. Ich hatte wirklich angenommen dass dem call-Befehl eine absolute Adresse übergeben wird. Die Adresse die printf liefert ist also die absolute und ich muss dass Offset der Adresse von execmem zu der Adresse von test() angeben. Oder das Offset zum call-Befehl? Könntest du mir das vielleicht an Quellcode veranschaulichen?

Gruß
Manuel

EDIT.: Ich habe anscheinend in deinem Text ein kleines Detail überlesen. Wie bekomme ich den Instruktionszeiger nach dem call-Befehl heraus?
 
Zuletzt bearbeitet:
EDIT.: Ich habe anscheinend in deinem Text ein kleines Detail überlesen. Wie bekomme ich den Instruktionszeiger nach dem call-Befehl heraus?
Der Call-Befehl beginnt bei execmem und hat eine Länge von 5 Bytes (1 Byte Opcode + 4 Bytes relative Adresse). Insofern steht der Instruktionszeiger bei der Auswertung des Call-Befehls auf execmem + 5.

Aber wie gesagt: tu dir den Gefallen und verwende asmjit o.ä., vor allem wenn du außer einem simplen Call auch noch andere Befehle verwenden willst, die nicht so einfach zu assemblieren sind (ModR/M Byte etc.).

Grüße,
Matthias
 
Zurück