Skip to content

user32.__ClientLoadLibrary(x)

May 11, 2007

Anti SetWindowsHookEx DLL injection made possible 😀 Read on.

After spending some time reversing the user32 internals, I discovered this undocumented function. This function is responsible to load the SetWindowsHookEx() registered DLL into your process. This blog will only focus on usermode, where the actual DLL loading takes place.

user32.__ClientLoadLibrary(lpHook)

This function takes only 1 argument, a pointer to an undocumented structure allocated in process stack. It holds the path of the DLL, pointer to notification function and some yet to be known data.

_USERHOOK struct
    unknown_00	DWORD ?	           ; 0x00
    unknown_04	DWORD ?	           ; 0x04
    nCount	DWORD ?	           ; 0x08 numbers of pointer to fix up
    unknown_0C	DWORD ?	           ; 0x0C
    offCbkPtrs	DWORD ?	           ; 0x10 offset to callback pointers
    bFixed	DWORD ?	           ; 0x14 indicates if the pointer is fixed
    lpDLLPath	UNICODE_STRING {}  ; 0x18 DLL path
    lpfnNotify	DWORD ?	           ; 0x20 offset to notification procedure
                                     (called when DLL is injected)
_USERHOOK ends

At the beginning of function, it checks for _USERHOOK.nCount and _USERHOOK.bFixed value. Then it calls to FixupCallbackPointers.

user32.FixupCallbackPointers(lpHook)

It takes only 1 argument, the same argument passed to __ClientLoadLibrary. This function “fix up” the pointers in a pretty interesting way. First it locate the address of callback pointers.

lpCbkPtrs = lpHook + offCbkPtrs

Then it loops through the a list of pointers and fix it up by resolving the offset to actual address.

newaddress = lpHook + offset

After fixing up all the pointers, we return to __ClientLoadLibrary and then it calls to InitUserApiHook.

user32.InitUserApiHook(hModule, lpfnNotify)

It calls to ResetUserApiHook, which fills up an array with function address given by argument 1. After that it calls to the notification function __Unknown_DllInjected pointed by (hModule + lpfnNotify), passing the array of address as argument 2.

__Unknown_DllInjected(lpvReserved, lpFuncList)

user32.ResetUserApiHook(lpFuncList)

Fills up the array given by the pointer lpFuncList.

__UserFuncList struct
    lSize DWORD ?    ; size of the list
    ...              ; array of function address
__UserFuncList  ends

Most of the part is still missing. You are welcomed to post here about anything I missed. Attached below is an example that hooks __ClientLoadLibrary, prints out the DLL that tried to load into it, and refuse to load it. Anti-SetWindowsHookEx DLL injection eh? 😀 DebugView is needed to see the dumps.

——————————————————————————————-

Trypanophobia 2

http://w14.easy-share.com/3759581.html

15 Comments
  1. There’s an easier way. Just hook ntdll.dll!LdrLoadDll, this is a more or less documented one. It provides you with the name of DLL. If you doesn’t want it, just return STATUS_DLL_NOT_FOUND and that’s it. Anyway, thanks for some insight, it might be useful later

  2. But you cant tell if that DLL is legimate or unwanted, can you? 😉 You might block your process from loading its own DLL.

  3. Yes, that’s true. But if the library was injected through
    CreateRemoteThread() / any flavour of LoadLibrary()
    you won’t catch it (for at least i’m pretty sure you won’t). On the other hand, you can usually tell good DLLs from bad, say by checking if it is located under SYSTEM32 or (a better way) checking if it belongs to Microsoft.

  4. By the way, unknown_18 and lstrLib are actually parts of UNICODE_STRING. That is, unknown_18 contains two words: current len (in bytes) and max len of contained string

  5. If you are talking about DLLs injected through CreateRemoteThread(), check out my last blog on “Shield from thread injection”. 😉

    Good to know that is actually a _UNICODE_STRING structure, never thought of it. :O Updated.

  6. Your update is definetely wrong, now lpDLLPath takes only 2 bytes in your struct 🙂

  7. Oops, typo. Fixed.

  8. That’s better, but offsets are still wrong 😉

  9. I didnt find anything wrong with the offset. :/ UNICODE_STRING is 8 bytes long, and 0x18 + 0x8 = 0x20.

  10. Oops, my fault 😦

  11. It looks like “USER32!ResetUserApiHook”
    not “user32.ResetUsetApiHook(lpFuncList)”
    very informative. thanks 😉

  12. Heh, typo gone unnoticed for years, thanks. Fixed :3

  13. Bevan permalink

    I don’t suppose you have an alternate download for the example code? easy-share.com no longer has it.

  14. Gurmit permalink

    Great post. You said- “Attached below is an example that hooks __ClientLoadLibrary, prints out the DLL that tried to load into it, and refuse to load it”…

    Where is the code? I could not find it here.

Trackbacks & Pingbacks

  1. Windows Process Injection: KernelCallbackTable used by FinFisher / FinSpy | modexp

Leave a comment