![]() |
Generischer Code-Hook
Liste der Anhänge anzeigen (Anzahl: 1)
Im Anhang (oder
![]() 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:
Die Beispielanwendung zeigt recht schön, was man damit so alles machen kann.
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; 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:
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).
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] ... Unsere neue Funktion NewReadFile steht bei Adresse $456D28. Nach dem Einfügen der JMP-Instruktion sieht der gepatchte Code dann so aus:
Code:
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:
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] ...
Code:
Die ersten 7 Bytes wurden aus dem Originalcode von kernel32.ReadFile herüber kopiert und der anschließende Sprung zeigt 7 Bytes dahinter.
00A90FE0 6A20 push $20
00A90FE2 68D89B807C push $7c809bd8 00A90FE7 E92908D77B jmp $7c801815 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] |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:20 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