Tuesday, October 26, 2004

Hookers and services

No, this post is not related to prostitution. It is, in fact, related to Windows hooks - just as bad. Well, no, not nearly.. Anyway!

First, I'd like to mention that rattle's article on Systemwide Windows Hooks without external DLL is what first sparked my interest in this. Thanks!

I've mainly been experimenting with WH_KEYBOARD and WH_KEYBOARD_LL. As mentionned by MSDN, the NT-specific WH_KEYBOARD_LL delivers notifications in the process that set the hook. This is especially interesing because it means no external DLL need be created. On the the other hand, it makes you wonder about the numerous context switches that will happen upon keyboard input.

The second point I want to explore is exactly that - the delivery of notifications. As far as I can see, hooks use some kind of Windows messages. If, after hooking, the thread is Sleeping or SleepExing (to put the thread in an alertable wait state), hooks are not called. If, however, it is in a GetMessage or PeekMessage-based message pump, it processes messages successfully. What's more, MsgWaitForMultipleObjects returns WAIT_OBJECT_0+nCount (indicative of a message queued in the thread's message queue) when a hook is about to be called.

The strange behavior in this entire system is that, given an application which does not have any windows or other message sources than the hooks, GetMessage never returns! In fact, PeekMessage returns FALSE and never returns a valid message in *lpMsg. The hook procedure gets called, it appears, from inside them (in GetMessage and MsgWaitForMultipleObjects). I always suspected there was much more to GetMessage than meets the eye!

So, take all this, and throw most of it away. This only happens for WH_KEYBOARD_LL and WH_MOUSE_LL (and possibly WH_JOURNALRECORD and WH_JOURNALPLAYBACK). All other hooks seem to still require an external DLL. But wait... My original goal was to hook when the process was registered as a service. Things start to get even weirder in this case.

The service (it may be worth mentionning that it is set as an "interactive service" - interaction with the desktop is permitted) seems to be able to use WH_KEYBOARD, but still to a very restricted extent. (Normal processes simply didn't have their hook procedure called at all.) I observed that the hook procedure is called when the events are being delivered to a console window. As soon as events are received by other windows, the hook stops functionning, and switching back to a console window does not "re-enable" it. (Note that the message processing is still necessary for services.)

Soon to come... Hooking in other desktops and window stations. Probably yet another ugly beast, but I love it. I love it all.

No comments: