user32.__ClientLoadLibrary(x)
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
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
But you cant tell if that DLL is legimate or unwanted, can you? 😉 You might block your process from loading its own DLL.
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.
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
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.
Your update is definetely wrong, now lpDLLPath takes only 2 bytes in your struct 🙂
Oops, typo. Fixed.
That’s better, but offsets are still wrong 😉
I didnt find anything wrong with the offset. UNICODE_STRING is 8 bytes long, and 0x18 + 0x8 = 0x20.
Oops, my fault 😦
It looks like “USER32!ResetUserApiHook”
not “user32.ResetUsetApiHook(lpFuncList)”
very informative. thanks 😉
Heh, typo gone unnoticed for years, thanks. Fixed :3
I don’t suppose you have an alternate download for the example code? easy-share.com no longer has it.
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.