Evil WM_TIMER... and workarounds

Yup, WM_TIMER can be used in callback mode. Yup, you can use this to run (more or less) arbitrary code... on NT anyway. No, this is not a problem - or rather, it's not a windows design problem.

You might want to grab the sample code now, so you don't miss the link later on ;).

WM_TIMER messages *are* posted to the window message queue, so you have a chance of handling them in your message loop - a bit more on this later. While SendMessage calls the wndproc directly (in the context of the thread running the messageloop, not the caller), it does not process the WM_TIMER callback. Thus, you will get a WM_TIMER message in the wndproc, with wparam==0 and lparam==address. Not an issue.

PostMessage inserts in the message queue; but since the callback dispatch isn't done until DispatchMessage, you have all the time you need to do message filtering.

Ah yes, filtering... there's quite a few ways of going about this, but by far the easiest is to not use message callbacks, and rather do all WM_TIMER processing in your wndproc. And no, it isn't really much trouble setting this up in a way that's about as easy to use as timer callbacks.

For most apps, I'd say that this whole thing is totally a nonissue, as long as sysadmins have configured the boxes correctly (ie, don't leave stuff running with admin-or-higher privileges - might be a bit hard to avoid with services though). But of course it would be nice if people started implementing this WM_TIMER 'fence', to be on the safe side - you never know how stupid sysadmins can be, nor what tricks evil haxx0rz can come up with.

There's a couple ways I can think of to fix these issues without rewriting all existing apps. Have DispatchMessage ignore WM_TIMER callbacks which havent been registered with SetTimer, or have Get/PeekMessage drop these messages. There surely must be an internal list of timers somewhere, and if this isn't easy to access, it could be achieved by hooking SetTimer. I doubt this would break any existing apps - and if it does, I'd say those apps are broken already.

Or, PostMessage (SendMessage is not an issue, remember?) could be made to disallow posting WM_TIMER messages to other processes. This should be rather easy to accomplish, using GetWindowThreadProcessId and GetCurrentProcessId. This might break existing apps, perhaps with a bit higher probability than the other fix, but I reckon WM_TIMER 'cross-posting' applications are bad. I've included a sample using Microsoft Detours. It could probably be extended to hook all running processes and set a process creation notification callback, but that's a bit more work than I care for right now ;). The proper way to go about this is probably coding a NT KMD (as 9x system doesn't seem to be affected by this), but I haven't messed enough with KMD coding to do that. Or, one could patch USER32.DLL on disk - I think it would be nice to do the disk patching (ignoring issues like Windows File Protection), as one could then see which effect this patch has globally.

While I don't really think that the callback stuff is a windows design flaw (there's just no proper way to validate the address with the current Win32 API, and 'proper checks' would probably add too much overhead), I *am* alarmed if it's true that normal systems have hidden windows, run in the context of high-privilege users... and I find it rather amusing that main focus of foon's article is the "Win32 API flaws", and not the presence of these windows, and the lack of separation between Sevices and GUIs.

As for other messages, what can I say except "check your buffers". It's been said over and over again, yet a lot of people still forget to do it. Even in the "oh-so-secure" opensource stuff. No, just because you have done a EM_LIMITTEXT (or whatever) doesn't mean you shouldn't check for overruns.

WM_PASTE ought not to be a problem, as long as the windows controls internally check for buffer overflows. I haven't checked if they do, but I should think so... I wouldn't be surprised if they don't, though. EM_GETLINE is a somewhat tougher beast to handle gracefully... it could allow you to trash arbitrary addresses in arbitrary programs. However, as long as you don't have a way to execute code in the target process (I assume VirtualAllocEx and CreateRemoteThread can be disallowed by proper privilege settings, and WM_TIMER wont work when the fix outline above has been applied), this isn't much of an issue imo - if people have access to run code on your box, there should be even easier ways of crashing apps or bringing down the system.

There's probably other interesting messages, too... and sure it would be nice if win32 had some better means of verification. But in my opinion, all this is not as much of an issue as it's made out to be.

One can argue that choosing the desktop as a security boundary; but I feel that it does make sense that "if you can see it, it's yours". For "critical" stuff, the interface and the critical components should be kept separate --- too bad that this isn't being followed all the time.

Anyway, it's not like this is a new thing. Matt Pietrek had a little sidenote about it in an old 'Under The Hood' article - google for pietrek+hood+WM_TIMER, and do a text search for "surprising".

Essay by f0dder(a)flork.dk (f0dder.has.it), last edit at 2002-08-08.