1

When I use EasyHook to hook API calls, the first bytes of the hooked API function are replaced with a so called "trampoline" which is a jump into EasyHook code.

For example this is TextOutW in Gdi32.dll disassembled:

Original code in Gdi32.dll for exported function TextOutW()   
---------------------------------------------------------------
7daceeb1 8b ff           MOV   EDI,EDI
7daceeb3 55              PUSH  EBP
7daceeb4 8b ec           MOV   EBP,ESP
7daceeb6 53              PUSH  EBX
7daceeb7 56              PUSH  ESI
7daceeb8 57              PUSH  EDI
7daceeb9 8b 7d 18        MOV   EDI,dword ptr [EBP + c]
....

Code modified by Easyhook:
---------------------------------------------------------------
7daceeb1 e9 82 2b 64 8d  JMP   LAB_0b111a38 
7daceeb6 53              PUSH  EBX
7daceeb7 56              PUSH  ESI
7daceeb8 57              PUSH  EDI
7daceeb9 8b 7d 18        MOV   EDI,dword ptr [EBP + c]
....

Here you see that the first 5 bytes of the code in Gdi32.dll have been replaced with a JMP instruction. Each time TextOutW is called, EasyHook will forward the call to my hook function.


But when I use ApiMonitor nothing in the code in Gdi32.dll is modified.

I found that ApiMonitor loads a DLL into the hooked process (Windows Calculator):

ApiMontor hooking Windows Calculator

The file apimonitor-drv-x86.sys has the wrong file extension. It is not a driver. I used the API EnumDeviceDrivers() to enumerate all drivers in the system, but apimonitor-drv-x86.sys is not listed as driver.

It is an ordinary DLL as I can prove by loading it into DependencyWalker:

apimonitor-drv-x86.sys in DepedencyWalker

It has 4 exported functions with funny ordinals.

So my question is: How does ApiMonitor hook API calls without modifying the code in the hooked DLL? There must be any magic going on in apimonitor-drv-x86.sys

2 Answers 2

1

It is likely that ApiMonitor does a EAT/IAT hook which wouldn't require to write to the function's code. If I were you, I would put a breakpoint in the WinApi function's code and I would inspect the callstack for an address in the ApiMonitor module. That way, it would be easy to understand how the flow is redirected.

1
  • Your answer is correct. But it is only an assumption. What was missing is the proof. I added my own answer with the details that I would have expected from you.
    – Elmue
    Commented May 29 at 15:26
1

I could confirm that the assumption of Ariel is correct. I wrote a small C++ Console application to prove that ApiMonitor manipulates the Import Address Table.

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    wprintf(L"\nPress a key...\n");
    getch();

    HMODULE h_Kernel    = GetModuleHandleA("Kernel32.dll");
    void* f_CreateFile  = GetProcAddress(h_Kernel, "CreateFileW");
    void* f_GetProcAddr = GetProcAddress;
    
    wprintf(L"Kernel32:    0x%X\n", h_Kernel);
    wprintf(L"GetProcAddr: 0x%X\n", f_GetProcAddr);
    wprintf(L"CreateFile:  0x%X\n", f_CreateFile);

    wprintf(L"Press a key...\n");
    getch();
    return 0;
}

When I execute this without ApiMonitor I get:

Without ApiMonitor

You see that GetProcAddress is not inside Kernel32.dll. The address 7400FFF6 is inside C:\Windows\SysWow64\AppHelp.dll.

When I attach ApiMonitor with hooking for CreateFileW enabled after the first "Press a key..." I get this:

With ApiMonitor

So he does not only patch the IAT for CreateFileW, but also for GetProcAddress, so he can manipulate the return value and even monitor API calls that are not stored in the IAT.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.