[Hilfe]Hooking überschreibt register

03/03/2012 14:19 Lazeboy#1
Hey leute,
ich bin gerade dabei einen kleinen PacketLogger zu schreiben und stoße da auf ein Problem. Ich möchte nicht groß drum reden und fange am besten gleich mit meinem Problem an:

Also ich möchte gerne diese Funktion hooken:
Aufruf:
Code:
005DBD68     53                PUSH EBX
005DBD69     56                PUSH ESI
005DBD6A     8BF2              MOV ESI,EDX
005DBD6C     8BD8              MOV EBX,EAX
005DBD6E     EB 04             JMP SHORT NostaleX.005DBD74
005DBD70     EB 05             JMP SHORT NostaleX.005DBD77
005DBD72     3919              CMP DWORD PTR DS:[ECX],EBX
005DBD74     8BD6              MOV EDX,ESI
005DBD76     8BC3              MOV EAX,EBX
005DBD78     E8 E7FDFFFF       CALL NostaleX.005DBB64
Anfang der Funktion:
Code:
005DBB64     55                PUSH EBP                                             ; ENCRYPT PACKET
005DBB65     8BEC              MOV EBP,ESP
005DBB67     6A 00             PUSH 0
005DBB69     6A 00             PUSH 0
005DBB6B     6A 00             PUSH 0
005DBB6D     53                PUSH EBX
005DBB6E     56                PUSH ESI
005DBB6F     57                PUSH EDI
005DBB70     8955 FC           MOV DWORD PTR SS:[EBP-4],EDX
005DBB73     8BD8              MOV EBX,EAX
005DBB75     8B45 FC           MOV EAX,DWORD PTR SS:[EBP-4]
005DBB78     E8 C395E2FF       CALL NostaleX.00405140
005DBB7D     33C0              XOR EAX,EAX
005DBB7F     55                PUSH EBP
005DBB80     68 40BD5D00       PUSH NostaleX.005DBD40
005DBB85     64:FF30           PUSH DWORD PTR FS:[EAX]
005DBB88     64:8920           MOV DWORD PTR FS:[EAX],ESP
005DBB8B     807B 31 00        CMP BYTE PTR DS:[EBX+31],0
so hooke ich:
Code:
typedef void (__fastcall *tSend)(DWORD, char *, DWORD);
tSend oSend;

oSend = (tSend)DetourFunc((PBYTE)SendHookAdr, (PBYTE)SendHook, 
5);

void __fastcall SendHook (DWORD ecx, char *edx, DWORD esp4)
{
	MessageBox(0,edx,0,0);
	oSend(ecx, edx, esp4);
}
Da es aus meiner Sicht eine __fastcall funktion ist und das Paramter in edx übergeben wird lese ich mit meinem 2. Parameter das Packet aus. Die MessageBox gibt mir auch das komplette Packet aus. Das Problem entsteht wenn ich die orginale funktion aufrufen möchte :
005DBB73 8BD8 MOV EBX,EAX -> hier wird das Register EBX verändert und dadurch ensteht her:
CMP BYTE PTR DS:[EBX+31],0
der Crash.

das Problem ist halt das mein hook irgendwie das eax register verändert und nicht sichert.
Kann mir vlt jemand sagen wie ich das verhindern kann.
mfg Lazeboy
03/03/2012 14:55 SmackJew#2
1. Register sind physisch auf der CPU. Außer an den Werten der Register wirst du da nichts verändern.

2. Microsoft fastcall nutzt ECX und EDX, nicht EAX.

3. Poste bitte den kompletten Code und ein Disassemble der Funktion während sie gehookt ist, sowie ein Disassemble der SendHook Funktion.
03/03/2012 15:36 Lazeboy#3
Danke für die schnelle Rückmeldung

also mein kompletter Code:
[Only registered and activated users can see links. Click Here To Register...]

die Funktion im Client mit Jmp Hook:
[Only registered and activated users can see links. Click Here To Register...]

die SendHook Funktion:
[Only registered and activated users can see links. Click Here To Register...]

das ecx und edx genutzt wird weiß ich ja nur wird halt vor dem funktion aufruf eax gesetzt und auf eax habe ich ja keinen zugriff drauf wenn ich keine naked funktion schreibe.
03/03/2012 15:47 SmackJew#4
Dein SendHook überschreibt hier

Code:
100116F8    B8 CCCCCCCC     MOV EAX,CCCCCCCC
eax, speichert es aber vorher nicht.

Versuch's mal hiermit:

Code:
void __fastcall SendHook (DWORD ecx, char *edx, DWORD esp4)
{
        __asm pushad
        __asm pushfd
	MessageBox(0,edx,0,0);
        __asm popfd
        __asm popad
	return oSend(ecx, edx, esp4);
}
Generell immer eine gute Idee alle Register und Flags zu speichern und sie bevor du zurück in die originale Funktion gehst wieder vom Stack zu holen.
03/03/2012 15:56 Lazeboy#5
also da überschreibe ich zwar nur irgendwie gehört das zur Calling Convention denn die beiden push kommen erst danach. Das ist zwar ein problem aber das richtige problem ist eig. das oSend mit einem veränderten paramter eax aufgerufen wird. Habe ich gerade dank dir bemerkt :D


Code:
100116E0    55              PUSH EBP
100116E1    8BEC            MOV EBP,ESP
100116E3    81EC D8000000   SUB ESP,0D8
100116E9    53              PUSH EBX
100116EA    56              PUSH ESI
100116EB    57              PUSH EDI
100116EC    51              PUSH ECX
100116ED    8DBD 28FFFFFF   LEA EDI,DWORD PTR SS:[EBP-D8]
100116F3    B9 36000000     MOV ECX,36
100116F8    B8 CCCCCCCC     MOV EAX,CCCCCCCC
100116FD    F3:AB           REP STOS DWORD PTR ES:[EDI]
100116FF    59              POP ECX
10011700    8955 EC         MOV DWORD PTR SS:[EBP-14],EDX
10011703    894D F8         MOV DWORD PTR SS:[EBP-8],ECX
10011706    60              PUSHAD
10011707    9C              PUSHFD
10011708    8BF4            MOV ESI,ESP
1001170A    6A 00           PUSH 0
1001170C    6A 00           PUSH 0
1001170E    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
10011711    50              PUSH EAX
10011712    6A 00           PUSH 0
10011714    FF15 B4930110   CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; user32.MessageBoxA
1001171A    3BF4            CMP ESI,ESP
1001171C    E8 6FFAFFFF     CALL NostaleP.10011190
10011721    9D              POPFD
10011722    61              POPAD
10011723    8BF4            MOV ESI,ESP
10011725    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
10011728    50              PUSH EAX
10011729    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
1001172C    8B4D F8         MOV ECX,DWORD PTR SS:[EBP-8]
1001172F    FF15 3C810110   CALL DWORD PTR DS:[1001813C]
10011735    3BF4            CMP ESI,ESP
10011737    E8 54FAFFFF     CALL NostaleP.10011190
1001173C    5F              POP EDI
1001173D    5E              POP ESI
1001173E    5B              POP EBX
1001173F    81C4 D8000000   ADD ESP,0D8
10011745    3BEC            CMP EBP,ESP
10011747    E8 44FAFFFF     CALL NostaleP.10011190
1001174C    8BE5            MOV ESP,EBP
1001174E    5D              POP EBP
1001174F    C2 0400         RETN 4
Code:
10011725    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
10011728    50              PUSH EAX
10011729    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
1001172C    8B4D F8         MOV ECX,DWORD PTR SS:[EBP-8]
1001172F    FF15 3C810110   CALL DWORD PTR DS:[1001813C]
03/03/2012 16:33 SmackJew#6
Quote:
Originally Posted by Lazeboy View Post
also da überschreibe ich zwar nur irgendwie gehört das zur Calling Convention denn die beiden push kommen erst danach. Das ist zwar ein problem aber das richtige problem ist eig. das oSend mit einem veränderten paramter eax aufgerufen wird. Habe ich gerade dank dir bemerkt :D
Hm, verstehe auch nicht ganz wo der ganze Code in SendHook herkommt. Ich würde das Ding ausziehen und dann sollte da auch nicht viel mehr drin sein als 'ne Calling Convention, dein MB Call und ein jump zurück.
03/03/2012 16:50 Lazeboy#7
jo wollte ich zwar vermeiden aber führt wohl kein weg dran vorbei ;) danke für die Hilfe läuft jetzt wunderbar
03/04/2012 03:28 MrSm!th#8
Ansonsten wäre ein Weg in die Compiler Optionen gegangen.
Etwaige Einstellungen wie Optimierung, standardmäßige Calling Conventions und andere Spielereien verfälschen gerne mal den Code.
03/04/2012 12:43 Tyrar#9
wie wärs beim msvc mit __declspec(naked)?
kannst dann komplett kontrollieren wie die funktion aussieht
03/04/2012 18:16 MrSm!th#10
Er sagte doch bereits, dass es als naked funktioniert.
03/05/2012 22:27 Lazeboy#11
könntest du mir sagen welchen genauen einstellungen ich verändern muss um jegliche optimierung zu entfernen. Denn ich habe das problem das wenn ich eine Funktion per dll Calle und die dll in embacadero c++ builder erstelle funktioniert das ganze jedoch in Vc++ nicht :D gehört jetzt nicht ganz zu dieser topic aber wegen jeden problem ne neue topic aufmachen ist auch nicht das wahre

also ich habs mir nochmal angeguckt das problem ist das man in c++ builder AnsiString benutzen kann und das ist nötig ich wüsste aber nichts was man dem AnsiString in visual c++ gleichstellen kann.
03/06/2012 09:26 xNopex#12
Quote:
Also ich habs mir nochmal angeguckt das problem ist das man in c++ builder AnsiString benutzen kann und das ist nötig ich wüsste aber nichts was man dem AnsiString in visual c++ gleichstellen kann.
Da gibts wohl nix, was dem zu 100% entspricht. Musst du entweder selbst nachbaun oder du versuchst es mit std::string
03/06/2012 13:33 Lazeboy#13
Quote:
Originally Posted by xNopex View Post
Da gibts wohl nix, was dem zu 100% entspricht. Musst du entweder selbst nachbaun oder du versuchst es mit std::string
C++ BUILDER -> Funktioniert
Code:
AnsiString tmp = "say test";
			const char *Packet = tmp.c_str();
			DWORD Func = 0x005DBD68;

			__asm
			{
				MOV EDX,Packet
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}

C++ BUILDER -> Funktioniert nicht
Code:
const char *Packet = "say test";
			DWORD Func = 0x005DBD68;

			__asm
			{
				MOV EDX,Packet
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}
Visual C++-> Funktioniert nicht
Code:
string Pack =   "/blabla test";
			char *Packet = (char*)Pack.c_str();

			DWORD Func = 0x005DBD68;

			__asm 
			{
				MOV EDX,Packet
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}
Visual C++ -> Funktioniert nicht
Code:
char *Packet = "/blabla test";

			DWORD Func = 0x005DBD68;

			__asm 
			{
				MOV EDX,Packet
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}
Visual c++ -> verzweiflungs versuch :D -> funktioniert auch nicht
Code:
char cAsciiStr[1024];
			string Pack =   "/blabla test";
			char *Packet = (char*)Pack.c_str();
			WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)Packet, -1, cAsciiStr, 1024, NULL, NULL);
			DWORD adr = (DWORD)&cAsciiStr;
			

			DWORD Func = 0x005DBD68;

			__asm 
			{
				MOV EDX,adr
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}

Ich hab auch schon versucht in den Projektoptionen: Charset oder c/c++ language umzustellen aber das führt alles nicht zum gewünschten ergebnis.
03/06/2012 15:21 link#14
Soweit ich weiß, besteht ein AnsiString aus jeweils einem Dword für den Referencecounter und die Länge und aus einem null-terminiertem Char-Array.
Eine AnsiString-Variable zeigt allerdings nicht auf solch eine Struktur, sondern direkt auf das Array, wobei die beiden anderen Members über ein negatives Offset angesprochen werden. Heißt es lässt sich wie ein normales Char-Array bzw. wie einen Pointer auf einen null-terminierten String benutzen.

Code:
const char *Packet = "say test";
MOV EDX,Packet
kann schlecht funktionieren, da EDX ' yas' als Wert erhält.

Wieso genau benötigst du denn einen AnsiString? Anscheinend übergibst du doch lediglich einen normalen null-terminierten String. Oder erwartet die Funktion tatsächlich einen AnsiString? Statt des .c_str() würde auch ein mov edx,offset Packet bzw. lea edx,[Packet] reichen.

Edit:
Btw. es gibt keine x86/x64 Calling Convention von MS, die EAX für Parameter verwendet. Von Borland gibt es register, die EAX, EDX und ECX verwendet und standardmäßig in Delphi benutzt wird. Das Pendant dazu in Borland C++ wird wohl fastcall sein.
03/06/2012 21:00 Lazeboy#15
so wen es interessiert habe jetzt mal nach den unterschieden zwischen AnsiString und char* geguckt.

Code:
int _tmain(int argc, _TCHAR* argv[])
{
	AnsiString a = "/blabla test";
	char *a2 = a.c_str();
	string b = "/blabla test";
	const char *b2 = b.c_str();

	char c[1024] = {0};
	strcpy(c,"/blabla test");

	for(int i = 0; i < a.Length()+10; i++)
	{
		printf("%02X,", (BYTE)a2[i]);
	}

	printf("\n\n");

	for(int i = 0; i < a.Length()+10; i++)
	{
		printf("%02X,", (BYTE)b[i]);
	}

	printf("\n\n");

	for(int i = 0; i < a.Length()+10; i++)
	{
		printf("%02X,", (BYTE)c[i]);
	}

	cin.get();
	return 0;
}

AUSGABE
Code:
2F,62,6C,61,62,6C,61,20,74,65,73,74,00,00,00,00,00,00,00,00,00,00

2F,62,6C,61,62,6C,61,20,74,65,73,74,00,8D,BC,32,0C,00,00,00,0F,00

2F,62,6C,61,62,6C,61,20,74,65,73,74,00,00,00,00,00,00,00,00,00,00
sowohl bei string als auch bei char* oder char[](ohne length) gibts nach der "NULL terminierung" noch irgendwelche sinnlosen werte. Bei AnsiString fällt dies weg und was dem enstpricht ist char[length].

so funktioniert derr code jetzt
Code:
char cAsciiStr[1024] = {0};
			strcpy(cAsciiStr,"/blabla test");
			

			DWORD Func = 0x005DBD68;

			__asm 
			{
				LEA EDX, [cAsciiStr]
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}

EDIT:
habe mich wohl geirrt und die falsche dll injeziert oder so... das problem besteht immer noch und ich weiß ehrlich gesagt nicht mehr weiter und auch nicht wie ich sowas nach programmieren sollte das würde den rahmen von meinem packet logger ein wenig sprengen XD

EDIT2:
ohh man....:facepalm:
schon fast als ob ich hier nen protokoll halte. Ich bin ein wenig verwirrt denn das wiederspricht ja allen Regeln.
das funktioniert:
Code:
char cAsciiStr[1024] = {0};
			string Pack =   "/blabla test";
			char *Packet = (char*)Pack.c_str();
			
			strcpy(cAsciiStr,"/blabla test");
			

			DWORD Func = 0x005DBD68;

			__asm 
			{
				LEA EDX, [cAsciiStr]
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}
das nicht:
Code:
char cAsciiStr[1024] = {0};

			
			strcpy(cAsciiStr,"/blabla test");
			

			DWORD Func = 0x005DBD68;

			__asm 
			{
				LEA EDX, [cAsciiStr]
				MOV EAX,DWORD PTR DS:[0x649AB8]
				MOV EAX,DWORD PTR DS:[EAX]
				CALL [Func]
			}
aber das
Code:
string Pack =   "/blabla test";
char *Packet = (char*)Pack.c_str();
hat doch gar nix mit dem senden zu tun lol :D