Services.exe and the Windows CE 6.0 kernel

Note: This is more of a geeky article for people who want to know how stuff works under the hood in Windows CE.  If you're just trying to write a service DLL there's much better guides available.

In CE 6.0, services.exe was completely rewritten and renamed to be servicesd.exe.  In CE 4.0, I copied and pasted some of the code from device.exe for really gross things like the super low level IPC magic on WinCE, managing some kernel handle stuff, etc...  Cloning code like that really bugged me, but there wasn't really a clean way to extend the device.exe code and I needed to make some tweaks to it.  Fortunately in CE 6.0 we solved this cloning problem.

In CE 4.0-5, when you called say DeviceIoControl() on a service handle your process called directly into Services.exe via what's called a PSL (it's the low level IPC magic on CE).  Basically services.exe "stole" your application's thread, did whatever work you asked it to do on that thread, and returned (rather than spinning up its own worker thread and using events to signal when it was done).  In CE 6.0, user mode processes cannot call directly into a PSL table exported by another user-mode process.  They have to go through the kernel.  So that means that we have a reflector in the kernel that takes user-mode process calls and then forwards them onto another process associated with the call, like servicesd.exe.

I was lucky that our kernel team decided anyway that they wanted to move a bunch of device drivers out of the kernel and into a user-mode driver framework.  They wrote this kernel reflector and they wrote udevice.exe, to host stuff that may not need kernel privilege like console.dll and certain drivers.  I really liked the way that udevice was implemented.  The best part was that udevice was done totally with C++ classes that could be over-ridden.  And it was done with a clean C++, and not random "let's use weirdo templates for the sake of using weirdo templates" type of style :).

servicesd.exe in WinCE 6.0 is a super-set of udevice.exe but core IPC code is the same.  The biggest changes are needed to support <https://blogs.msdn.com/cenet/archive/2006/08/15/701668.aspx> this stuff.  I also have hard-coded knowledge about certain IOCTLs (like IOCTL_SERVICE_START) that udevice.exe really doesn't care about but services have to do special things for.  All I had to do to make this work was override udevice.exe IOCTL pipe channel and put my logic in and I was done.  Servicesd.exe took about 2 weeks to get up on the new kernel, as opposed to the 4-5 or so had I had to do the IPC plumbing myself.

When I started this blog I wanted to show how smart I was, though it's seeming to show how smart the udevice.exe writer was instead :).  So the credit goes David Liao on the CE device driver team.

If you're super curious to see how the code to this works, the driver/service manager stuff is in \private\winceos\COREOS\device\ and servicesd.exe itself lives at .\services.  It's part of the shared source program in Windows CE 6.0.

I'll talk about why we renamed services.exe to servicesd.exe in the first place in a future post.  It had nothing to do with the rewrite, and if you search services.exe related entries on this blog you may be able to guess why (hint: it's a security thing).

[Author: John Spaith]