Search code examples
delphidllhookdelphi-6

Hooking a DLL function in Delphi


I have a coclass which checks the registry to determine if an application is installed, but it does this poorly and doesn't find newer versions of the application. In cases where a competing application has been installed, it will try to open that one. If the competing application has been uninstalled, the program will crash. This coclass is defined in a DLL file I do not have the source code for the library, so I can't just change that. I have been looking into using hooking to replace the function with one that works, but it seems complicated when I look at the MSDN documentation on using SetWindowsHookEx. Can someone please provide an example of how to use SetWindowsHookEx or another method of hooking into Windows?

Thank You

EDIT: I would like to note that I accepted the answer I did because it worked for me. I could not use the other answer at the time the question was asked, but it looks like its just as good.


Solution

  • Here is a short example from my own codebase which shows the most basic hooking technique:

    unit MethodHooker;
    
    interface
    
    implementation
    
    uses
      SysUtils, Windows, Classes;
    
    procedure Patch(Address: Pointer; const NewCode; Size: Integer);
    var
      NumberOfBytes: DWORD;
    begin
      WriteProcessMemory(GetCurrentProcess, Address, @NewCode, Size, NumberOfBytes);
    end;
    
    type
      PInstruction = ^TInstruction;
      TInstruction = packed record
        Opcode: Byte;
        Offset: Integer;
      end;
    
    procedure Redirect(OldAddress, NewAddress: Pointer);
    var
      NewCode: TInstruction;
    begin
      NewCode.Opcode := $E9;//jump relative
      NewCode.Offset := Integer(NewAddress)-Integer(OldAddress)-SizeOf(NewCode);
      Patch(OldAddress, NewCode, SizeOf(NewCode));
    end;
    
    function GetCursorPos(var lpPoint: TPoint): BOOL; stdcall;
    (* The GetCursorPos API in user32 fails if it is passed a memory address >2GB which
       breaks LARGEADDRESSAWARE apps.  We counter this by calling GetCursorInfo instead
       which does not suffer from the same problem. *)
    var
      CursorInfo: TCursorInfo;
    begin
      CursorInfo.cbSize := SizeOf(CursorInfo);
      Result := GetCursorInfo(CursorInfo);
      if Result then begin
        lpPoint := CursorInfo.ptScreenPos;
      end else begin
        lpPoint := Point(0, 0);
      end;
    end;
    
    initialization
      if not ModuleIsPackage then begin
        if not CheckWin32Version(6, 1) then begin
          //this bug was fixed in Windows 7
          Redirect(@Windows.GetCursorPos, @MethodHooker.GetCursorPos);
        end;
    
    end.