C/C++: Wer testet/verbessert mein kleines Experiment?

der_Kay

der_Kay

Aktives Mitglied
Thread Starter
Dabei seit
02.09.2004
Beiträge
1.765
Reaktionspunkte
25
Hallo,

ich versuche mich gerade an Anti-cracking/reverse-engineering-Tricks. Ein Schritt dazu ist gepackter (verschlüsselter und signierter) Code, oder Teile davon. Dazu muss man vorab assemblierten Code im Quelltext unterbringen, zur Laufzeit entpacken und dann die Anwendung auf den Speicherbereich springen lassen, wo der Code entpackt/hinkopiert wurde. Das bringt Disassembler/Debugger fürs erste aus dem Trab und hilft, die Routine für die Seriennummer zu verstecken.

Auf einem intel-Prozessor (unter Windows) weiss man genau, wie die CPU den Stack verwendet um Rücksprungadressen und Variablen zu verwalten aber von PowerPC-Assembler hab ich keinen blassen Schimmer. Ich dachte, vielleicht geht das auch ohne.

Und zu meiner Verblüffung scheint das der Fall zu sein: Untenstehend ein simples Programm mit einem Block "roh" assemblierten PowerPC-Codes, der (hoffentlich) eine triviale C-Funktion ("do_exp_sqrt") implementiert, die die Wurzel aus dem Logarithmus zur Basis 10 einer double zurückgibt.

Als weiteres Problem ergibt sich, das der kompilierte Code keine Importtabelle abbekommt; ich übergebe als Abhilfe eine "Mini-Importtabelle" als Pointer-Array in einem Argument, in dem Fall die Adressen von sqrt und log10 aus der math-library.

Wie schon erwähnt, funktioniert das auf meinem G4 (MPC7447A, OS X 10.4.7): Es schreibt brav sqrt(log10(10000.0))=2.0 in die Konsole. :D

Meine Fragen:
- Kann das mal wer auf einem G5 ausprobieren?
- Kann man sich darauf verlassen/ist garantiert, dass das immer funktioniert? Insbesondere: Funkt das Betriebssystem nie dazwischen, wenn man Code auf dem Heap laufen lässt?
- Verstosse ich u. U. gegen Aufrufkonventionen, wenn ich den Code einfach per Cast in den Heap springen lasse? Kann das Probleme mit den Rücksprungadressen auf dem Stack geben?
- Kann es sein, dass einem solche Sachen in "großen" Programmen "um die Ohren fliegen"?
- Ob das auch mit dynamischen Bibliotheken klappt?

Ich würde mich freuen, wenn sich nun jemand inspiriert fühlt und das z.B. weiterbastelt, austestet und ein paar Sachen mehr ausprobiert. Ideen gibt es genug; z.B. Packen, Verschlüsseln, Signaturen(<- interessant), Selbstmodifikation usw.

Zum Assemblieren habe ich pasm - a portable PowerPC assembler verwendet, den ich leicht patchen musste; binary im ZIP-File. Irgendwie ging das mit as nicht.

Alles Wissenswerte/Quellcode/Tools/binaries im ZIP untendran; Anleitungen in den Quellcode-Dateien.
PHP:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>

#define BYTE unsigned char

/*
double do_exp_sqrt ( double d, void** import_table  )
{
	DFD dfd1 = 	(double (*) (double)) import_table[0],
		dfd2 = 	(double (*) (double)) import_table[1];

	return (*dfd2)((*dfd1)(d)); 
} 
*/
/* kompilierter Code */
BYTE code [] = {
	0x7c, 0x08, 0x02, 0xa6, 0xbf, 0xc1, 0xff, 0xf8, 0x90, 0x01, 
	0x00, 0x08, 0x94, 0x21, 0xff, 0xa0, 0x7c, 0x3e, 0x0b, 0x78, 
	0xd8, 0x3e, 0x00, 0x48, 0x90, 0xbe, 0x00, 0x80, 0x80, 0x5e, 
	0x00, 0x80, 0x80, 0x02, 0x00, 0x00, 0x90, 0x1e, 0x00, 0x3c, 
	0x80, 0x5e, 0x00, 0x80, 0x38, 0x42, 0x00, 0x04, 0x80, 0x02, 
	0x00, 0x00, 0x90, 0x1e, 0x00, 0x38, 0x80, 0x1e, 0x00, 0x3c, 
	0xc8, 0x3e, 0x00, 0x48, 0x7c, 0x0c, 0x03, 0x78, 0x7d, 0x89, 
	0x03, 0xa6, 0x4e, 0x80, 0x04, 0x21, 0xfc, 0x00, 0x08, 0x90, 
	0x80, 0x1e, 0x00, 0x38, 0xfc, 0x20, 0x00, 0x90, 0x7c, 0x0c, 
	0x03, 0x78, 0x7d, 0x89, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x21, 
	0xfc, 0x00, 0x08, 0x90, 0xfc, 0x20, 0x00, 0x90, 0x80, 0x21, 
	0x00, 0x00, 0x80, 0x01, 0x00, 0x08, 0x7c, 0x08, 0x03, 0xa6, 
	0xbb, 0xc1, 0xff, 0xf8, 0x4e, 0x80, 0x00, 0x20
};

/*	Funktionszeigerdeklaration für sqrt() & log10() */
typedef double (*DoubleFuncDouble) (double);

/*	Funktionszeigerdeklaration für kompilierten Code	*/
typedef double (*DoubleFuncDoubleVoidPP) (double, void**);

/*	leserlicheres Typecasting auf obigen Funktionszeiger 	*/
#define CAST_DFDVPP(pointer) (double (*)(double, void**)) (pointer)

int main ( int argc, char** argv )
{
	/*	Mini-Importtabelle	*/
	DoubleFuncDouble my_import_table [] = { log10, sqrt };
	
	/*	Platz für den Code	*/
	void* code_relocated = malloc ( sizeof ( code ) );
	
	/*	Funktionszeiger für impliziten Aufruf */
	DoubleFuncDoubleVoidPP func = CAST_DFDVPP(code_relocated);
	
	/*	wird 2.0 ;)	*/
	double result;
	
	/*	Codeblock auf den Heap kopieren, später entpacken usw....	*/
	memcpy(code_relocated, code, sizeof( code )); 
	
	/*	Spannung...	*/
	result = (*func)( 10000.0, (void**) my_import_table);

	printf("%f\n", result);

	/* damit keiner hinterher hineinschaut ;) */
	memset (code_relocated, 0, sizeof(code));
	
	free ( code_relocated );
	
	return 0;	
}

Viel Spass,

Kay
 

Anhänge

  • funcode.zip
    45,5 KB · Aufrufe: 45
Zuletzt bearbeitet:
Zurück
Oben Unten