AGB  ·  Datenschutz  ·  Impressum  







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

Generischer Code-Hook

Ein Thema von Flocke · begonnen am 2. Okt 2005
Antwort Antwort
Benutzerbild von Flocke
Flocke

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

Generischer Code-Hook

  Alt 2. Okt 2005, 13:05
Im Anhang (oder hier) befindet sich vier Units inkl. einer kleinen Demo-Anwendung, die durch Code-Analyse das generische Ersetzen von beliebigen Funktionen ermöglichen.

Dabei werden die ersten 5 Bytes der betreffenden Funktion mit einen Sprung an die neue Adresse überschrieben. Gleichzeitig wird aber auch ein neues Code-Fragment erstellt, dass die überschriebenen CPU-Instruktionen enthält (also >= 5 Bytes) und einen Sprung zur ersten gültigen Adresse hinter dem an der Originaladresse eingefügten Sprung.

Das bietet zwei Möglichkeiten:

1. Es wird damit möglich, Bibliotheksfunktionen und -prozeduren der RTL zu überschreiben (bzw. erweitern), ohne den Code komplett neu schreiben zu müssen.

2. Man kann damit API-Funktionen direkt an der Einsprungadresse patchen und somit die Aufrufe aller geladenen DLLs umleiten; und auch eine via GetProcAddress geholte Adresse wird somit erfasst.

Beispiel

Wenn man z.B. die Funktion ReadFile aus kernel32.dll hooken will, dann sieht das etwa so aus:
Delphi-Quellcode:
uses
  GenCodeHook;

type
  TFnReadFile = function(hFile: THandle; var Buffer;
    nNumberOfBytesToRead: DWORD; var lpNumberOfBytesRead: DWORD;
    lpOverlapped: POverlapped): BOOL; stdcall;

var
  OldReadFile: TfnReadFile;

function NewReadFile(hFile: THandle; var Buffer;
  nNumberOfBytesToRead: DWORD; var lpNumberOfBytesRead: DWORD;
  lpOverlapped: POverlapped): BOOL; stdcall;
begin
  // ... Aktion vorher

  Result := OldReadFile(hFile, Buffer, nNumberOfBytesToRead,
                        lpNumberOfBytesRead, lpOverlapped);

  // ... Aktion hinterher
end;

procedure InstallPatch;
var
  Module: HMODULE;
begin
  Module := GetModuleHandle('kernel32.dll');
  CreateGenericCodeHook(GetProcAddress(Module, 'ReadFile'),
    @NewReadFile, @OldReadFile);
end;
Die Beispielanwendung zeigt recht schön, was man damit so alles machen kann.

Funktionsweise

Die eigentliche Arbeit leistet dabei die Funktion GetCpuInstructionLength in der Unit CodeLen.pas, die die Länge der CPU-Instruktion bei einer bestimmten Speicheradresse zurückgibt.

Dadurch wird es möglich, nicht nur einfach eine feste Instruktion wie JMP oder CALL zu patchen, sondern beliebigen Code der mindestens 5 Bytes lang ist. Hier am Beispiel von ReadFile.

Der originale ReadFile-Code steht bei Adresse $7C80180E:
Code:
kernel32.ReadFile:
7C80180E 6A20             push $20
7C801810 68D89B807C      push $7c809bd8
7C801815 E8B10C0000       call $7c8024cb   ; <-- Schnittpunkt
7C80181A 33DB            xor ebx,ebx
7C80181C 8B4D14           mov ecx,[ebp+$14]
...
Wir benötigen 5 Bytes für die JMP-Instruktion, die wir an dieser Stelle einfügen möchten. Der nächste mögliche `Schnittpunkt´ ist also bei Adresse $7C801815, das liegt 7 Bytes hinter dem Eintrittspunkt der Funktion (7 ist also der Wert, den die Funktion GetCpuInstructionSequence(pointer($7C80180E), 64, 5) hier zurückliefern würde).

Unsere neue Funktion NewReadFile steht bei Adresse $456D28. Nach dem Einfügen der JMP-Instruktion sieht der gepatchte Code dann so aus:
Code:
kernel32.ReadFile:
7C80180E E91555C583       jmp NewReadFile
7C801813 80               db $80            ; Rest des urspr. Codes
7C801814 7C              db $7C           ; Rest des urspr. Codes
7C801815 E8B10C0000       call $7c8024cb   ; <-- Schnittpunkt
7C80181A 33DB            xor ebx,ebx
7C80181C 8B4D14           mov ecx,[ebp+$14]
...
Wie man sieht, steht bei $7C801815 die erste noch gültige Instruktion des originalen Codes, also exakt 7 Bytes hinter dem Eintrittspunkt. An genau diese Stelle springt jetzt das von CreateGenericCodeHook erstellte Codefragment, und das sieht dann so aus:
Code:
00A90FE0 6A20             push $20
00A90FE2 68D89B807C      push $7c809bd8
00A90FE7 E92908D77B      jmp $7c801815
Die ersten 7 Bytes wurden aus dem Originalcode von kernel32.ReadFile herüber kopiert und der anschließende Sprung zeigt 7 Bytes dahinter.

Beispielanwendung

Die Beispielanwendung erweitert die Funktionen ReadFile und WriteFile und zeigt auf dem Formular zwei Indikatoren in grün und rot, die die jeweilige E/A-Aktivität anzeigen.

Wenn man zwei Dateinamen auswählt und dann auf "Start" klickt, dann wird die erste Datei mit der API-Funktion CopyFile über die zweite kopiert. Die beiden Indikatoren zeigen dabei den Lese- und Schreibzugriff an. Am deutlichsten wird dies, wenn man ein langsames Medium wählt, wie z.B. eine
Diskette.

Interessant ist es auch schon, einfach nur das Flackern der Indikatoren zu beobachten, während man mit dem OpenDialog oder SaveDialog navigiert; besonders deutlich wird dies, wenn man über die rechte Maustaste das Kontextmenü von Dateien aufruft, insbesondere das "Senden an"-Menü.

ACHTUNG: NICHT UNTER 95/98/ME AUSPROBIEREN!

Bitte

Falls euch irgendetwas auffällt, insbesondere bei den CPU-Instruktionen in CodeLen.pas, dann teilt mir das bitte mit. Es sollten alle nativen, Fließkomma, MMX, SSE, SSE2, SSE3 und 3DNow CPU-Instruktionen enthalten sein, aber 100%-ig sicher bin ich mir da nicht.

[edit=Chakotay1308]Anhang geupdatet. Mfg, Chakotay1308[/edit]
Angehängte Dateien
Dateityp: zip codehook_1.4_108.zip (34,0 KB, 203x aufgerufen)
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  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 07:23 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