![]() |
Rückkehradresse bei Hook
Hallo,
ich bin gerade dabei einen Packet-Sniffer für ein Spiel zu schreiben und möchte das durch Hooks in ws2_32.dll machen. Normalerweise läuft das so ab: Spiel -> ws2_32.send -> Spiel Ich möchte folgendes: Spiel -> ws2_32.send (gepatchter Code) -> Sniffer-DLL -> ws2_32.send -> Sniffer-DLL -> Spiel Der erste Teil (Hook) funktioniert schon mit diesem Code:
Delphi-Quellcode:
Ich sehe, dass das Spiel die Pakete an den Server sendet, allerdings wird der nachfolgende Code (hier testweise eine Exception) nicht mehr ausgeführt. Meine Vermutung ist, dass er irgendwie direkt ins Spiel zurückspringt.
type
TRecvSend = function(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall; var hWS, SendRet: Cardinal; function NewSend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall; begin Result := TRecvSend(SendRet)(s, Buf, len, flags); raise Exception.Create('Test'); end; function JMP(iFrom, iTo: Cardinal): Cardinal; begin Result := (iTo - iFrom) - 5; end; var F, o, o2: Cardinal; begin hWS := LoadLibraryA('ws2_32.dll'); [...] F := Cardinal(GetProcAddress(hWS, 'send')); SendRet := F + 5; VirtualProtect(Pointer(F), 5, PAGE_EXECUTE_READWRITE, o); PByte(F)^ := $E9; PCardinal(F + 1)^ := JMP(F, DWORD(@NewSend)); VirtualProtect(Pointer(F), 5, o, o2); end. Das heißt, ich müsste die Rückkehradresse speichern, sie dann auf mein NewSend setzen und dann am Ende mit der Adresse ins Spiel zurückkehren. :? Weiß jemand wie das geht? |
AW: Rückkehradresse bei Hook
Entferne die Exception und schreibe dir anstatt eine Log-Routine und speichere den erfolgten Zugriff in einer Text-Datei.
|
AW: Rückkehradresse bei Hook
Delphi-Quellcode:
So passiert gar nichts mehr. Nur wenn ich das CloseFile vor SendRet ausführe sendet er das Paket.
var
T: TextFile; begin AssignFile(T, 'C:\test.txt'); Append(T); WriteLn(T, 'Lese...'); Result := TRecvSend(SendRet)(s, Buf, len, flags); WriteLn(T, 'Gelesen: ' + IntToStr(Result)); CloseFile(T); end; |
AW: Rückkehradresse bei Hook
Delphi-Quellcode:
var
T: TextFile; begin AssignFile(T, 'C:\test.txt'); Append(T); WriteLn(T, 'Lese...'); CloseFile( T ); Result := TRecvSend(SendRet)(s, Buf, len, flags); Append( T ); WriteLn(T, 'Gelesen: ' + IntToStr(Result)); CloseFile(T); end; |
AW: Rückkehradresse bei Hook
Gelesen kommt nie, immer nur Lese. Ist also genau so wie ich im 1. Post gesagt habe.
|
AW: Rückkehradresse bei Hook
Zitat:
|
AW: Rückkehradresse bei Hook
Du kannst den originalen code nicht einfach so aufrufen. Immerhin hast du 5 Bytes überschrieben. Genau die müssen wieder vorher ausgeführt werden. Und meistens zerschneidest du halt eine Assembler Anweisung, d.h. du musst vorher den Code noch analysieren und ggf. 6 und mehr Bytes kopieren.
Für dich gibt es jetzt mehrere Möglichkeiten: a) bevor du die originale Funktion aufrufst machst du den patch wieder rückgängig und am Ende deiner Funktion patched du wieder. (dann aber nicht jedes mal VirtualProtect aufrufen), das is sehr langsam -> nicht so einfach mit ThreadSafe, und wenn dann wieder langsamer (z.b. Mutex) b) du kopierst die dll und lädst sie ein 2. mal und rufst dann da die Funktion von auf (ggf. funktioneirt das nicht wenn die dll mit globalen variablen arbeitet) c) du nimmst eine andere Hook-Möglichkeit z.B. Import/Export/Relocation/PageGuard/ hook (ggf. verlierst du dadurch aber ein paar Aufrufe) d) du immst eine Dll (Name enfallen) die macht das alles für dich direkt auf Treiberebene (capi oder so?) e) seit Windows XP haben viele Funktionen 5 NOPs vor dem EntryPoint. Ist das der Fall kannst du dort deinen Jump reinschreiben und dann die ersten bytes mit einem short JMP dahhin überschreiben (das wird bei Windows Updates teilweise so gemacht) f) du nimmst fertige HookingUnits ( z.b. meine ![]() |
AW: Rückkehradresse bei Hook
Der originale Code sieht so aus:
![]() Das sind genau 5 Bytes, da wird also nichts zerstückelt. Möglichkeit f) entfällt, weil das Spiel mit HackShield geschützt ist, was die Veränderungen die diese Methoden anwenden aus welchem Grund auch immer erkennt. NewSend sieht in asm so aus: ![]() Die push Befehle unten sind Parameter für einen MessageBoxA Aufruf, der dann nicht ausgeführt wird. Großartig debuggen (z.B. break points setzen) kann ich leider auch nicht, denn dann hab ich Themida im Nacken :evil: Edit: Ich hatte folgenden Einfall:
Delphi-Quellcode:
NSRet ist die Adresse vom ersten push 0, wird vor dem Hooken gesetzt. In GameRet soll die alte Rückkehradresse.
function NewSend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
const a: PAnsiChar = 'testa'; asm push eax push edi mov eax, [ebp] mov edi, [eax+$04] mov [GameRet], edi mov edi, [NSRet] mov [eax+$04], edi pop edi pop eax call dword ptr [SendRet] push 0 push 0 push a push 0 call MessageBoxA end; Leider funktioniert es nur, wenn ich mov [GameRet], edi rausnehme - dann wird die MessageBox angezeigt, ansonsten passiert mal wieder gar nichts. Warum klappt die eine Zeile nicht? :( |
AW: Rückkehradresse bei Hook
Also wenn du das hardcoden willst:
schreib dir ne funktion:
Delphi-Quellcode:
die kannst du dann innerhalb deines Callbacks aufrufen.
function NewSend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
asm // delphi erzeugt den gleichen Stackframe (d.h. push ebp; mov ebp, esp) // adresse nach deinen ueberschriebenen bytes // einfacher absoluter jump push $7742c4cd ret end; btw. das mov edi, edi zeigt genau auf das verhalten e) hin |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz