c++windowshookeasyhook

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.


Solution

  • 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);
    }