?
Solved

Intercept API calls

Posted on 2009-12-23
21
Medium Priority
?
1,141 Views
Last Modified: 2013-12-03
I'm looking for a way to intercept all calls made from my application and any dll loaded by it, to certain Windows API functions. Like for example, CreateFileMapping. I'd also like to do this, preferably without adding any extra dll files to my project. I've been told I can do this with Microsoft Detours, but it's written in C++ and I can't find a Delphi wrapper for it, I've also tried compiling it into an object file with C++ Builder, but several of the external declarations needed look like gibberish. So I was hoping there might be another and possibly simpler way. I'm assuming since I only need to intercept calls made internally in my application, that that might make it easier. (My application has a scriptable environment and I need to intercept certain calls for security purposes to clarify as why I need to do this.)
0
Comment
Question by:Freddy1990
  • 10
  • 6
  • 3
  • +2
21 Comments
 
LVL 9

Expert Comment

by:JohnGaby
ID: 26115621
There is an open source hooking library that you can look at. Although it is written in C++, it should show you how it is done.  (Note that it is not as robust as Detours)

http://www.codeproject.com/KB/DLL/apihijack.aspx
0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26116937
This is what I've been able to make up so far, but it doesn't work, if anyone could help me fix it...
program MessageBoxHook;

uses Windows;

function Hook(ModuleName, ApiName: PChar; NewFunction: Pointer): DWORD;
var
  Lib: DWORD;
  Proc: Pointer;
  ModuleApp: DWORD;
  DosHeader: PImageDosHeader;
  NewExeHeader: DWORD;
  NTHeader: PImageNtHeaders;
  ImportDescription: PIMAGE_IMPORT_DESCRIPTOR;
  Thunk: PIMAGE_THUNK_DATA;
  mbi: MEMORY_BASIC_INFORMATION;
  OldProtect: DWORD;
  OldFunc: DWORD;
begin
  if IsBadCodePtr(NewFunction) then Exit(0);   
  Lib := LoadLibrary(ModuleName);
  Proc := GetProcAddress(Lib, ApiName);
  ModuleApp := GetModuleHandle(nil);
  DosHeader := PImageDosHeader(ModuleApp);
  if IsBadReadPtr(DosHeader, SizeOf(TImageDosHeader)) then Exit(0);
  if DosHeader.e_magic <> IMAGE_DOS_SIGNATURE then Exit(0);
  NewExeHeader := DosHeader^._lfanew;
  NTHeader := Pointer(DWORD(DosHeader) + NewExeHeader);
  if NTHeader.Signature <> IMAGE_NT_SIGNATURE then Exit(0);
  ImportDescription := Pointer(DWORD(DosHeader) + NTHeader.OptionalHeader.
    DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  if ImportDescription = PIMAGE_IMPORT_DESCRIPTOR(NTHeader) then Exit(0);
  while ImportDescription^.Name <> 0 do
  begin
    Thunk := Pointer(DWord(DosHeader) + ImportDescription^.FirstThunk);
    while Thunk._Function <> 0 do
    begin
      if (Pointer(Thunk._Function) = Proc) then
      begin
        VirtualQuery(Pointer(Thunk._Function), &mbi,
          SizeOf(MEMORY_BASIC_INFORMATION));
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, @OldProtect);
        OldFunc := Thunk._Function;
        Thunk._Function := DWORD(NewFunction);
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, OldProtect, @OldProtect);
        Exit(OldFunc);
      end else
        Inc(Thunk);
    end;
    Inc(ImportDescription);
  end;
  Result := 0;
end;

function MessageBoxCallback(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
begin
  MessageBoxW(hWnd, 'Hooked', '', MB_OK);
end;

var
  OldFunc: DWord;

begin
  MessageBox(0, 'No hook', '', MB_OK);

  OldFunc := Hook('user32.dll', 'MessageBoxA', @MessageBoxCallback);

  if (OldFunc <> 0) then
    MessageBox(0, 'No hook', '', MB_OK);
end.

Open in new window

0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26117039
Btw, just noticed that the "MessageBox" in the test should be MessageBoxA, as MessageBox references MessageBoxW, but even so it still doesn't work...
0
Transaction-level recovery for Oracle database

Veeam Explore for Oracle delivers low RTOs and RPOs with agentless transaction log backup and transaction-level recovery of Oracle databases. You can restore the database to a precise point in time, even to a specific transaction.

 
LVL 13

Expert Comment

by:ThievingSix
ID: 26117315
When you find your own answer it's a good idea to post it and select your own answer as the correct one. This way when other people look at your question to find an answer there is one.
0
 
LVL 4

Expert Comment

by:urban_smurf
ID: 26118578
My favourite way to hook api's in my own apps is to create a .dll and include it as a resource, that way you can extract it at runtime, inject it into your own app and it works SWEEEEET!

I can provide an example if you like.
0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26118883
Actually, my own answer only works like half as it's supposed to, I can override an api call, but I can't call the original api anymore... So I'm still stuck...

@urban_smurf: Would be cool if you could give an example, that's not exactly how  I hoped to do it, but if I fail doing it without a dll, I won't have much choice anyway...
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 26119802
You first need afxcodehook(pre delphi 2009, I have unicode enabled if you need): http://filebeam.com/9c98b83588184ce2a38aa312209806fb

afxcodehook has functions for both hooking WinAPI and injecting DLL's.

Next you need an example: First make a new DLL project within Delphi then:
library MyInjectDLL;

uses
  Windows,      
  afxCodeHook in '..\afxCodeHook\afxCodeHook.pas';

type
  TMessageBoxA = function(Wnd: DWORD; lpText: PChar; lpCaption: PChar; uType: UINT): Integer;

var
  MessageBoxANextHook: TMessageBoxA = nil;
 
function MessageBoxACallBack(Wnd: DWORD; lpText: PChar; lpCaption: PChar; uType: UINT): Integer;
begin
  //This function is called when the program you inject into calls MessageBoxA()
  //To call the original function you would do the following
  MessageBoxANextHook(Wnd,lpText,lpCaption,uType);
end;
 
procedure EntryPoint(Reason: DWORD);
var
  I : Integer;
begin
  Case Reason Of
    DLL_PROCESS_ATTACH:
      HookCode('Kernel32.dll','MessageBoxA',@MessageBoxACallBack,@MessageBoxANextHook);
    end;
    DLL_PROCESS_DETACH:
      begin
      UnhookCode(@MessageBoxACallBack,@MessageBoxANextHook);
    end;
  end;
end;

begin
  DLLProc := @EntryPoint;
  EntryPoint(DLL_PROCESS_ATTACH);
end.

Open in new window

0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26119883
Yea, I'm using Delphi 2010, so unicode enabled would be useful
0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26119955
I've tried this version of the code, and it results in the same problem as when I tried to hotpatch the MessageBoxA api, both when I try to do it with or without the dll... Instead of showing the messagebox like it should, it shows a messagebox with some gibberish in the caption and some random buttons, while I specified no caption, a text and MB_OK... Maybe the unicode version would fix that...
0
 
LVL 13

Accepted Solution

by:
ThievingSix earned 400 total points
ID: 26120243
Unicode afxcodehook: http://filebeam.com/4f9a0a0657481d98beccd703f470cc2b



Unicode Example:
library MyInjectDLL;

uses
  Windows,
  afxCodeHook in 'C:\Users\ThievingSix\Desktop\Delphi Projects\EFSoW\afxCodeHook\afxcodehook.pas';

type
  TMessageBoxA = function(Wnd: DWORD; lpText: PAnsiChar; lpCaption: PAnsiChar; uType: DWORD): Integer;

var
  MessageBoxANextHook: TMessageBoxA = nil;

function MessageBoxACallBack(Wnd: DWORD; lpText: PAnsiChar; lpCaption: PAnsiChar; uType: DWORD): Integer;
begin
  //This function is called when the program you inject into calls MessageBoxA()
  //To call the original function you would do the following
  MessageBoxANextHook(Wnd,PAnsiChar(AnsiString('This function has been hooked!')),PAnsiChar(AnsiString('Hooked Function')),uType);
end;

procedure EntryPoint(Reason: DWORD);
var
  I : Integer;
begin
  Case Reason Of
    DLL_PROCESS_ATTACH:
      begin
      HookCode('Kernel32.dll','MessageBoxA',@MessageBoxACallBack,@MessageBoxANextHook);
    end;
    DLL_PROCESS_DETACH:
      begin
      UnhookCode(@MessageBoxACallBack,@MessageBoxANextHook);
    end;
  end;
end;

begin
  DLLProc := @EntryPoint;
  EntryPoint(DLL_PROCESS_ATTACH);
end.

Open in new window

0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26121186
Hmm, I've tried the dll, by loading it trough LoadLibrary, the api got hooked, but it wouldn't work... I also tried the attached and again I got the same problem as with my hotpatch, I don't know why though... I've attached an image with the messagebox that'll show up with the attached code, also when you press ok, it just opens another one with some different gibberish. The dll caused a messagebox to appear with 3 buttons in reversed order and the text in the caption reversed to the right, well, more gibberish anyway...
program MessageBoxHook;

uses
  Windows,
  afxCodeHook in 'afxCodeHook.pas';

type
  TMessageBoxA = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer;

var
  MessageBoxANextHook: TMessageBoxA = nil;

function MessageBoxACallBack(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer;
begin
  Result := MessageBoxANextHook(hWnd, 'Win!', lpCaption, uType);
end;

begin
  HookCode('user32.dll','MessageBoxA',@MessageBoxACallBack,@MessageBoxANextHook);
  MessageBoxA(0, 'Hey', '', MB_OK);
end.

Open in new window

msgbox.png
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 26121219
Try:

Result := MessageBoxANextHook(hWnd, PAnsiChar(AnsiString('Win!')), lpCaption, uType);
0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26121241
Already tried that, same result, and delphi automatically converts the string to a PAnsiString anyway...
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 26121402
A maybe just Delphi 2009 doesn't, or maybe I'm just paranoid.

On the subject: I'm at a loss. This works fine on my computer although I don't use Delphi 2010 I doubt that is the issue.

Could you possibly post your compiled dll and exe that you're injecting it into so I can debug it to see why it's doing such issues?
0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26122333
I've attached the binaries and sources of both files... I am running Windows 7 x64 RC2 though, but normally it should be able to run on every Windows platform...
program MessageBoxHook;

uses
  Windows,
  afxCodeHook in 'afxCodeHook.pas';

begin
  LoadLibrary('MyInjectDLL.dll');
  MessageBoxA(0, 'Hey', '', MB_OK);
end.

-------

library MyInjectDLL;

uses
  Windows,
  afxCodeHook in 'afxcodehook.pas';

type
  TMessageBoxA = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer;

var
  MessageBoxANextHook: TMessageBoxA = nil;

function MessageBoxACallBack(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer;
begin
  Result := MessageBoxANextHook(hWnd,PAnsiChar(AnsiString('lol')),lpCaption,uType);
end;

procedure EntryPoint(Reason: DWORD);
var
  I : Integer;
begin
  Case Reason Of
    DLL_PROCESS_ATTACH:
      begin
      HookCode('user32.dll','MessageBoxA',@MessageBoxACallBack,@MessageBoxANextHook);
    end;
    DLL_PROCESS_DETACH:
      begin
      UnhookCode(@MessageBoxACallBack,@MessageBoxANextHook);
    end;
  end;
end;

begin
  DLLProc := @EntryPoint;
  EntryPoint(DLL_PROCESS_ATTACH);
end.

Open in new window

MessageBoxHook.zip
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 26122563
Lucky, I'm running the same. After the holiday celebrations I'll get this straightened out for you.
0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26292636
I'm still kind of waiting for a response here...
0
 
LVL 3

Expert Comment

by:fjocke
ID: 26338972
It's kind of funny, allthough this does not explain your problem. But when you change

HookCode('user32.dll','MessageBoxA',@MessageBoxACallBack,@MessageBoxANextHook);

to

HookCode('user32.dll','MessageBoxA',@MessageBoxACallBack,@MessageBoxANextHook);

Miracously your normal text will appear, i'll look into as to why this is.
0
 
LVL 3

Expert Comment

by:fjocke
ID: 26338995
Think i fould the problem, the afxCodeHook which ThievingSix updated for you, is indeed Unicode, and that's the problem. If i do not recall wrong, String is actually a deveration from Unicode and that's what's being used in afxCodeHook one soultion to this could be that you either make two functions, one HookCode for Ansi and one for Unicode.

If you want this in code, i can try write something up for you.
0
 
LVL 3

Assisted Solution

by:fjocke
fjocke earned 400 total points
ID: 26339025
Since i got it to work here is the HookCode that works:

I suggest you give

ThievingSix points for correct answer, and me for Assisting Answer.

Kind Regards

Jocke
function HookCode(TargetModule, TargetProc: String; NewProc: Pointer; var OldProc: Pointer): Integer;
var
  ModuleLoop : Integer;
  Modules : TModuleList;
  Module : hModule;
  Target : Pointer;
begin
  Result := 0;
  Module := GetModuleHandleA(PAnsiChar(TargetModule));
  Modules := GetModuleList;
  If Module = 0 Then
    begin
    Module := LoadLibraryA(PAnsiChar(TargetModule));
  end;
  Target := GetProcAddress(Module,PChar(TargetProc));
  If Target = nil Then Exit;
  For ModuleLoop := 0 To High(Modules) Do
    begin
    If (GetVersion And $80000000 = 0) Or (Modules[ModuleLoop] < $80000000) Then
      begin
      Result := HookModules(Pointer(Modules[ModuleLoop]),Target,NewProc,OldProc);
    end;
  end;
end;

Open in new window

0
 
LVL 3

Author Comment

by:Freddy1990
ID: 26358766
I'll try it out when I get my new Delphi license.
0

Featured Post

Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question