user12733526
user12733526

Reputation:

EasyHook stop catching some messages

As soon EasyHook EasyHook64.dll intercepts the first DefWindowProcW message, and from it starts a thread, it does not catch any DefWindowProcW anymore:

![image](https://user-images.githubusercontent.com/82878129/133332313-34255484-e795-4ac5-aa77-5017105e5aac.png)

|___ DefWindowProcW (caught)
     |--
     |--
     |--
     |-- DefWindowProcW (don't 'intercept' anymore)
     |-- ...

It stops 'catching' all DefWindowProcW messages until the thread end.

I was told:

This is by design, it is part of the thread deadlock barrier.

And:

You could install two hooks for the same function, leaving the second disabled until you enter your first hook, you would enable it by setting its ACL inclusive to the current thread, then disable it again as you leave the first hook.

Then I tried to call it like:


HOOK_TRACE_INFO hHook  = { NULL }; 
HOOK_TRACE_INFO hHook2 = { NULL }; 
HOOK_TRACE_INFO hHook3 = { NULL };


LRESULT __stdcall DefWindowProcW_Hook(  HWND   hWnd,    UINT   Msg, WPARAM wParam,  LPARAM lParam)
{

    switch (Msg) {
        //......
    }

    ULONG ACLEntries[1]  = { 0 };
    LhSetInclusiveACL(ACLEntries, 1, &hHook);
    ULONG ACLEntries2[1] = { 0 };
    LhSetInclusiveACL(ACLEntries2, 1, &hHook2);
    ULONG ACLEntries3[1] = { 0 };
    LhSetInclusiveACL(ACLEntries2, 1, &hHook3); 

   return DefWindowProcW(hWnd, Msg, wParam, lParam);
}


// =======================================

void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo)
{

        LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
            DefWindowProcW_Hook,    NULL,   &hHook);

        ULONG ACLEntries[1] = { 0 };
        LhSetExclusiveACL(ACLEntries4, 1, &hHook);
        

        LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
            DefWindowProcW_Hook,    NULL,   &hHook2);

        LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
            DefWindowProcW_Hook,    NULL,   &hHook3);
}

But now, looks like all hooks are doing the same thing:

Result:

enter image description here

Would like to ask someone who uses or already used EasyHook how to properly read the same function when there is a 2nd or more nested call.

Upvotes: 0

Views: 238

Answers (1)

Justin Stenning
Justin Stenning

Reputation: 1837

There is no elegant solution for this in EasyHook, however if you are happy to install as many intermediate hooks as you need for the nesting levels you can chain them together.

The outermost hook will be the only one enabled initially.

It will first ensure all innermost hooks are disabled, then enable the next hook.

To prevent calling the hook for the same DefWindowProcW call, we can retrieve the next hook's bypass address and call that instead of the original DefWindowProcW like you would normally do.

As you have already discovered, once within a hook handler for a hook it will not trigger that same hook again until after the return statement has completed and we have gone back up the call stack. This is due to the thread-deadlock barrier in EasyHook.

Example:

HOOK_TRACE_INFO hHook  = { NULL };
HOOK_TRACE_INFO hHook2 = { NULL };
HOOK_TRACE_INFO hHook3 = { NULL };
typedef LRESULT __stdcall DefWindowProcFunc(HWND, UINT, WPARAM, LPARAM);

// Innermost hook handler
LRESULT __stdcall DefWindowProcW_Hook( HWND   hWnd, UINT   Msg, WPARAM wParam, LPARAM lParam)
{

switch (Msg) {
//......
}

   // Innermost hook just call original

   return DefWindowProcW(hWnd, Msg, wParam, lParam);
}


// Middle hook handler
LRESULT __stdcall DefWindowProcW_Hook2( HWND   hWnd, UINT   Msg, WPARAM wParam, LPARAM lParam)
{

switch (Msg) {
//......
}

   // Activate next hook handler for next nesting level
   ULONG ACLEntries[1]  = { 0 };
   LhSetInclusiveACL(ACLEntries, 1, &hHook);

   PVOID* bypass_address;
   LhGetHookBypassAddress(&hHook, &bypass_address);
   
   //return DefWindowProcW(hWnd, Msg, wParam, lParam);
   
   // Bypass the handler for THIS call to DefWindowProcW - the next nested call will be captured in  DefWindowProcW_Hook
   return ((DefWindowProcFunc*)bypass_address)(hWnd, Msg, wParam, lParam);
}

// Outermost hook handler
LRESULT __stdcall DefWindowProcW_Hook3( HWND   hWnd, UINT   Msg, WPARAM wParam, LPARAM lParam)
{
    // Outermost hook handler - this will be called first for new calls to DefWindowProcW

switch (Msg) {
//......
}

   // Disable innermost hook(s) - do this for each inner hook that isn't the next hook
   ULONG disableACLEntries[1]  = { 0 };
   LhSetExclusiveACL(disableACLEntries, 1, &hHook);

   // Activate next hook handler for first nesting level
   ULONG ACLEntries[1]  = { 0 };
   LhSetInclusiveACL(ACLEntries, 1, &hHook2);

   PVOID* bypass_address;
   LhGetHookBypassAddress(&hHook2, &bypass_address);
   
   //return DefWindowProcW(hWnd, Msg, wParam, lParam);

   // Bypass the handler for THIS call to DefWindowProcW - the next nested call will be captured in DefWindowProcW_Hook2
   return ((DefWindowProcFunc*)bypass_address)(hWnd, Msg, wParam, lParam);
}

// =======================================

void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo)
{
    // NOTE: the last installed hook handler will be the first called i.e. hHook3, then hHook2 then hHook.
    LhInstallHook(
        GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
        DefWindowProcW_Hook, NULL, &hHook);

    LhInstallHook(
        GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
        DefWindowProcW_Hook2, NULL, &hHook2);
       
    LhInstallHook(
        GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
        DefWindowProcW_Hook3, NULL, &hHook3);
       
    // Activate outermost hook (ie last installed hook which will be the first called - hHook3)
    ULONG ACLEntries[1] = { 0 };
    LhSetExclusiveACL(ACLEntries, 1, &hHook3);
}

Upvotes: 0

Related Questions