Entwickler-Ecke

Windows API - HookCode FileGetAttributesA


dummzeuch - So 16.03.08 18:18
Titel: HookCode FileGetAttributesA
Hi,

ich versuche mit der uallcollection einen Hook auf die API Funktion GetFileAttributesA zu setzen. Leider funktioniert das nicht. Es wird zwar meine Funktion aufgerufen und ausgefuehrt, jedoch bekomme ich beim Aufruf der Original-Funktion eine Access-Violation:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
  // Installieren des Hooks:
  p4 := GetProcAddress(GetModuleHandle(kernel32), 'GetFileAttributesA');
  if p4 <> nil then begin
    @GetFileAttributesARec.old := p4;
    if uallHook.HookCode(@GetFileAttributesARec.old, @MyGetFileAttributesA, @GetFileAttributesARec.next) then begin
      LogLine('Hook for GetFileAttributesA installed');
    end else
      LogLine('Failed to hook GetFileAttributesA');
  end;

  // meine Hook-Funktion:
function MyGetFileAttributesA(lpFileName: PAnsiChar): DWORD; stdcall;
begin
  Result := GetFileAttributesARec.next(lpFileName);
end;


Natuerlich soll die Hook-Funktion mal etwas mehr machen, als nur die Original-Funktion aufrufen, aber schon dieser einfache Code fuehrt zu dem Fehler. Andere
Funktionen lassen sich ohne Probleme hooken.

Im Debugger sieht der Aufruf ganz OK aus:


Quelltext
1:
2:
3:
4:
5:
6:
7:
01F8FD30 55               push ebp
01F8FD31 8BEC             mov ebp,esp
01F8FD33 8B4508           mov eax,[ebp+$08]
01F8FD36 50               push eax
01F8FD37 FF1528A7F901     call dword ptr [$01f9a728]
01F8FD3D 5D               pop ebp
01F8FD3E C20400           ret $0004


Allerdings finde ich den aufgerufenen Code irgendwie seltsam:


Quelltext
1:
2:
3:
4:
021E0000 FF742404         push dword ptr [esp+$04]
021E0004 E885200100       call $021f208e
021E0009 685474587C       push $7c587454
021E000E C3               ret


Meine Assembler-Kenntnisse reichen nicht wirklich aus, um zu verstehen, was hier passiert. Die beiden letzen Befehle legen wohl eine neue Ruecksprungadresse auf den Stack und rufen sie auf, vermutlich ist das der Aufruf fuer die Originalfunktion. Aber so weit kommt es gar nicht erst, schon der zweite Befehl landet in der Pampa: $021f208e ist ein nicht initialisierter Speicherbereich.

Mache ich was falsch? Wieso funktioniert es mit anderen API-Funktionen (z.B. FindFirstFileA) aber nicht mit FileGetAttributesA?

twm


dummzeuch - So 16.03.08 18:58
Titel: Re: HookCode FileGetAttributesA
user profile icondummzeuch hat folgendes geschrieben:


Quelltext
1:
2:
3:
4:
021E0000 FF742404         push dword ptr [esp+$04]
021E0004 E885200100       call $021f208e
021E0009 685474587C       push $7c587454
021E000E C3               ret



Ok, ich mache nichts falsch, es liegt wohl daran, dass der Befehl

Quelltext
1:
021E0004 E885200100       call $021f208e                    

aus dem Original-Code von FileGetAttributesA kopiert wird, aber leider ein relativer Aufruf ist, sprich, wenn man ihn woandershin kopiert, springt er an die falsche Stelle. Im Original sieht er naemlich so aus:

Quelltext
1:
7C58744F E885200100       call $7c5994d9                    

uallHook.HookCode erkennt das Problem anscheinend nicht.

So weit, so schlecht.

Was kann ich nun dagegen tun?

twm


dummzeuch - So 16.03.08 20:05
Titel: Re: HookCode FileGetAttributesA
OK, fuer alle, die evtl. mal dasselbe Problem haben:

uall collection kann auch auf andere Weise APIs hooken, naemlich via der Import Address Table (IAT). Das ist, wenn es funktioniert, auch einfacher, da kein Code kopiert werden muss sondern nur ein Pointer umgesetzt wird:


Delphi-Quelltext
1:
2:
3:
4:
  if uallHook.HookApiIAT(kernel32, 'GetFileAttributesA', @MyGetFileAttributesA, p4) then begin
    @GetFileAttributesARec.old := p4;
    @GetFileAttributesARec.next := p4;
  end;


In meinem Fall hat's geklappt.

twm


uall@ogc - Di 25.03.08 12:01

Hi Thomas,
mit dem IAT Hook werden jedoch nicht alle Aufrufe der API abgefangen, sondern nur alle statischen (logisch: da nur diese in der IAT stehen). Der Codehook, wenn er denn funktioniert, fängt jedoch alle ab.

Über Vor- und Nachteile kann man sich hier informieren: http://help.madshi.net/ApiHookingMethods.htm
Madshi bietet selbst (leider nur kommerziell, früher gabs auch eine freie Version) ebenfalls eine weitaus ausgereiftere Version zum API hooken an.

Eine von mir erweiterte Version des IAT Hooks wäre der Relcoation hook, der die Relocation Section der PE Datei nach JMP [ADDR] durchsucht und diese auch noch mithookt. Dann können einige dynamisch geladenen Funktionen zusätzlich zum IAT gehookt werden.

PUSH ADDR, RET ist auch eine von mir eingeführte Art des JUMPs. Dieser Jump ist genau wie ein relativer Jump nur 6Bytes groß, hat aber den Vorteil, dass man diesen widerum einfach durch Codekopieren hooken kann. So kann man die selbe API mehrmals hooken ohne den relativen Code anzupassen.

Das relative Adressen angepasst werden müsste noch implementiert werden. Da hast du richtig gesehen, dass es noch nicht in der derzeitigen Version implementiert wird. Alternativ kannst du die WideChar API hooken, da sowieso jeder Call der A in den Aufruf der W Version endet. Und dort sollte (hoffentlich) kein relativer Call am Anfang der Funktion sein.


BenBE - Di 25.03.08 23:51

Ich hab mal im Bugtracker nen Report eingetragen, um das Problem im Auge zu behalten. Die Bugmeldung gibt's unter http://bugs.omorphia.de/view.php?id=220.