AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Detours : Routinen hooken

Ein Thema von sk0r · begonnen am 30. Sep 2007 · letzter Beitrag vom 5. Okt 2007
Antwort Antwort
sk0r

Registriert seit: 1. Mai 2007
181 Beiträge
 
Delphi 7 Enterprise
 
#1

Detours : Routinen hooken

  Alt 30. Sep 2007, 18:12
Hi,

ich möchte gerne eine Routine durch einen Detour hooken.
Nur leider klappt es bei mir nicht. Ich möchte die ersten
fünf Bytes der zu hookenden Routine mit einem jmp + address
überschreieben, welche zu einem allozierten Speicher zeigt.
In diesem allozierten Speicherbereich habe ich mir zehn
Bytes reserviert: Die ersten fünf sind noch von der Routine,
denn sie müssen ja auch ausgeführt werden. Danach kommt ein
jmp zu einer neuen Adresse und zwar zu der neuen Routine.
Um dann in der gehookten Routine auch die alte Routine ausführen
zu können, rufe ich die originale einfach auf, aber überspringe
die ersten fünf Bytes, damit ich nicht in einer Endlosschleife lande.

So sieht die Theorie aus, aber in der Praxis funktioniert es nicht.

Im folgenden Beispiel möchte ich die API-Prozedur Sleep() hooken.

Delphi-Quellcode:
type T_Sleep = procedure(dwMilliseconds: Cardinal);stdcall;

var pSleep: T_Sleep;

//Neue Sleep Prozedur
procedure NewSleep(dwMilliseconds: Cardinal);stdcall;
begin
  MessageBox(0, 'Test', 'Q', 0);
  pSleep(dwMilliseconds);
end;

function DetourHook(lpModule, lpRoutine: PChar; pTargetAddr, pNewAddr: Pointer):Pointer;
var
  pBackupAddr: Pointer;
  dwFiveBytes: DWord;
  pResultAddr: Pointer;
  dwJmpCode: DWord;
  dwJmpGateway: DWord;
  hAlloc: Pointer;
  bVProtect: Boolean;
  dwvProtect: DWord;
const
  DETOUR_JMP = $E9;
  DETOUR_SIZE = $05;
begin
  result := nil;
  pBackupAddr := GetProcAddress(GetModuleHandle(lpModule), lpRoutine); //Adresse der Routine einholen, zur weiteren Verwendung
  pResultAddr := Pointer(Cardinal(pBackupAddr) + (DETOUR_SIZE)); //Originale Adresse + fünf Bytes speichern, damit er nicht mehr den Jump Code ausführt (wird dann der result Wert)
  CopyMemory(@dwFiveBytes, pTargetAddr, DETOUR_SIZE); //Die Bytes, welche gleich überschrieben werden, kopieren.
  dwJmpCode := dwFiveBytes + DWord(DETOUR_JMP) + DWord(pNewAddr^); //Die zu überschreibenden 5 Bytes + Jump opcode + die Adresse, auf die gesprungen werden soll
  hAlloc := VirtualAlloc(0, DETOUR_SIZE*2, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); //Irgendwo im Bereich des Prozesses Speicher allozieren
  if hAlloc <> nil then
  begin
    bVProtect := VirtualProtect(hAlloc, DETOUR_SIZE*2, PAGE_READWRITE, dwvProtect); //Zugriffsrechte für Lesen und Schreiben einholen
    if bVProtect then
    begin
      CopyMemory(hAlloc, @dwJmpCode, DETOUR_SIZE*2); //Den Jump Code in den Bereich schreiben
      dwJmpGateway := DWord(DETOUR_JMP) + DWord(hAlloc); //Jump + Adresse des neuen allozierten Speicherbereichs
       if VirtualProtect(pTargetAddr, DETOUR_SIZE, PAGE_READWRITE, dwvProtect) then //Schreib - und Leserechte an der originalen Adresse einholen
      begin
        CopyMemory(pTargetAddr, @dwJmpGateway, DETOUR_SIZE); //Den Jump Code zum Gateway an die originale Adresse kopieren
        result := pResultAddr;
      end;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  lol, retaddr: Pointer;
begin
  lol := GetProcAddress(GetModuleHandle('kernel32.dll'), 'Sleep');
  if lol <> nil then
  begin
    retaddr := DetourHook('kernel32.dll', 'Sleep', lol, @NewSleep);
    if retaddr <> nil then
    begin
      ShowMessage('Detoured');
      pSleep := retaddr; //Backup Adresse zum Backup zuweisen
      //Sleep(2007);
    end
    else begin
      ShowMessage('Error');
    end;
  end;
end;
So weit bin ich nun gekommen. Ich bekomme aber immer eine Zugriffsverletzung,
wenn ich dann Sleep() aufrufen will. Deshalb nun meine Frage: Weiß jemand,
wo denn mein Fehler liegt? Ich weiß einfach nicht, was ich falsch mache...

Ich bedanke mich im Voraus für Hilfe.

MfG: sk0r
  Mit Zitat antworten Zitat
brechi

Registriert seit: 30. Jan 2004
823 Beiträge
 
#2

Re: Detours : Routinen hooken

  Alt 30. Sep 2007, 18:38
Jo du darst keine halben Befehle ausführen. Wer sagt denn, dass bei 5 Bytes die genaue größe ist? Du musst dir einen Disassembler schreiben der den Code analysiert und dann die entsprechende richtige Anzahl kopiert.
  Mit Zitat antworten Zitat
sk0r

Registriert seit: 1. Mai 2007
181 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: Detours : Routinen hooken

  Alt 5. Okt 2007, 15:02
Naja, es ist schon die richtige Größe.

Wenn ich z.B. Sleep aus der kernel32.dll hooken möchte, dann bestehen
die Bytes, die ich überschreibe aus dem stdcall. Dies rekonstruiere ich
bei der neuen Sleep wieder.

Falls es jemand anderen noch interessiert, hier der Code mit Beispiel.

Delphi-Quellcode:

var origSleep: Pointer;

procedure NewSleep(dwMilliseconds: Cardinal);stdcall;
begin
  MessageBox(0, 'Hallo aus der neuen Prozedur.', 'NewSleep', MB_ICONINFORMATION);
  asm
    jmp origSleep
  end;
end;

function DetourHook(lpModule, lpRoutine: PChar; pNewAddr: Pointer):Pointer;
type
  TDetourRec = packed record
    bJmpOpcode: Byte;
    dwAddress: DWord;
end;
var
  lpDetourCode: TDetourRec;
  lpGatewayCode: TDetourRec;
  pTargetAddr: Pointer;
  pJmpGateway: Pointer;
  dwTargetProtect: DWord;
const
  DETOUR_JMP = $E9;
  DETOUR_SIZE = $05;
begin
  result := nil;

  pTargetAddr := GetProcAddress(GetModuleHandle(lpModule), lpRoutine);
  if pTargetAddr = nil then exit;

  pJmpGateway := VirtualAlloc(0, DETOUR_SIZE, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  if pJmpGateway <> nil then
  begin

    lpDetourCode.bJmpOpcode := DETOUR_JMP;
    lpDetourCode.dwAddress := DWord(pNewAddr) - DWord(pJmpGateway) - DETOUR_SIZE;

    CopyMemory(pJmpGateway, @lpDetourCode, DETOUR_SIZE);

    lpGatewayCode.bJmpOpcode := DETOUR_JMP;
    lpGatewayCode.dwAddress := DWord(pJmpGateway) - DWord(pTargetAddr) - DETOUR_SIZE;

    if VirtualProtect(pTargetAddr, DETOUR_SIZE, PAGE_EXECUTE_READWRITE, dwTargetProtect) then
    begin
      CopyMemory(pTargetAddr, @lpGatewayCode, DETOUR_SIZE);
      result := Pointer(DWord(pTargetAddr) + DETOUR_SIZE);
    end;
  end;
end;

begin
  origSleep := DetourHook('kernel32.dll', 'Sleep', @NewSleep);
  if origSleep = nil then ExitProcess(0);
  Sleep(2007);
  MessageBox(0, 'I slept 2007 milliseconds', 'EntryPoint', MB_ICONINFORMATION);
end.
Ja, ich weiß, ich brauch gar keinen Speicherbereich allozieren, es geht auch
mit weniger Code, bzw. einfacher, aber das kann ja jeder selbst ändern.
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

Re: Detours : Routinen hooken

  Alt 5. Okt 2007, 16:15
Also bei mir fängt kernel32.Sleep so an:
Code:
8BFF   mov edi, edi
55      push ebp
8BEC   mov ebp, esp
6A00    push 0
Dein Detour überschreibt die ersten 5 Bytes - diese sind aber wichtig, da sie den Stackframe erzeugen.

Wie Brechi schon schrieb: du kannst nicht einfach Maschinencode überschreiben, ohne ihn analysiert zu haben. Dazu brauchst du einen Disassembler oder zumindest ein vereinfachte Abwandlung davon (z.B. hier).

Du musst also mehr oder minder wissen, was der Code macht, den du überschreibst - dann kannst du den überschriebenen Bereich sichern (und ggf. relozieren) und ab einer gewissen Stelle im Originalcode weitermachen.
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
sk0r

Registriert seit: 1. Mai 2007
181 Beiträge
 
Delphi 7 Enterprise
 
#5

Re: Detours : Routinen hooken

  Alt 5. Okt 2007, 16:54
Das denke ich ja auch, mir wurde aber gesagt, dass in diesem Fall, also obigen Beispiel, man
das nicht beachten muss, da die Bytes für stdcall benutzt werden. Man überschreibt also quasi
das stdcall, welches aber in der neuen Prozedur rekonstruiert wird, somit also kein Verlust entsteht.
So habe ich das verstanden, was mit von jemanden aus einem anderen Forum erklärt wurde.

Ich zitiere ihn mal:

Zitat:
In diesem Fall braucht man keinen Backup der Original-bytes, da diese nur aus dem stdcall Function-Prolog bestehen, welches wir dadurch rekonstruieren, dass wir unsere Callback-Funktion NewSleep als solche Kennzeichnen.
Ihr könnt ja mal den Code testen, er sollte funktionieren. Bei mir funktioniert er.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:15 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz