Windows Services (Part I)

Windows Services fill the gap between mortal user applications and the privileged, high-profile kernel-mode drivers. They are neither user applications nor do they make the cut to be fully fledged kernel modules. Services are still user-mode applications. They don’t get any higher privileges than their other user-mode applications (this is not entirely correct, as kernel-mode drivers may be run as services, but that’s outside the scope of this post). However, they do serve some very useful needs for which they are designed.

When are Services useful?

Perhaps the most obvious application of Services is the need to run some application without the requirement that a specific use be logged-in. That is, either we need to run an application before any user logs in or regardless of who (read: which account) has logged-in.

But that’s not all. Services have other very powerful features, including dependencies (Services may be automatically started or stopped based on the state of their dependencies) and auto-run modes. Automatic activity logging (in Event Logs). System-wide visibility. Administrator-only configuration. Running under system or arbitrary accounts. And many more.

How do they work?

We are really interested in understanding how Windows manages Services, how they are run and what responsibilities we have, as developers and administrators, when we deal with Services. The details and inner workings of Windows Services are of course extremely interesting, however without a good grasp of how things work on the outside, the internal details don’t mean much.

As far as developers are concerned, Services run as normal applications. The only and main difference is that unlike a normal stand-alone, user-mode application, Services have different and multiple entry-points. Each binary image may host one or more Service. Each Service needs to register a ServiceMain entry-point as well as an SCM (Service Control Manager) Control Handler entry-point.

Services are run based on a preset through which an administrator may decides when and if a Service should run. A common setting is to auto-run the service on boot (called Automatic). Another option is to run it only when some application (could be the SCM via user interaction) requests a Service to be run (by sending the Service the Start Control Code.) This mode is called Manual.

It should be clear that unlike other applications, Services by definition need a different method for running and controlling them. And in fact that is the case. An interesting consequence of this would be the difficulty in debugging Services while developing them. The reason is, of course, that one cannot debug past the StartService function which is the function used to run and start a Service.

Debugging Services

The reason that StartService function is the last point where debugging works is that we assume we are using a user-mode debugger. StartService by definition needs to transition to kernel-mode and upon return the service would be on its way to start (assuming creating the ServiceMain thread succeeded). However, StartService doesn’t wait, nor does it guarantee that the Service in question succeeded in starting. The state of Service could be queries via the QueryServiceStatus function.

But all is not lost. User-mode Service can still be debugged, yes, with a user-mode debugger. After all, user-mode Services run in user-mode. The trick is to get a debugger hooked after a Service has started running.

Debugging can be started basically in 3 different manners. The first is the most invasive, Kernel-Mode Debugging. In KM debugging, the debugger is typically either run during booting and stays resident at all times, or it’s attached from a debugger machine to a debuggee via some –typically serial– port. Most all KM debuggers can debug UM applications. However, KM debugging has many drawbacks. Besides the fact that they are complicated to setup and complicated to run (at least relative to UM debugging) there are other issues. For one, some software implement sophisticated protection mechanisms that primarily check for the existence of a debugger and if so they either work differently (typically in reduced functionality mode) or stop working altogether. This is a completely undesirable side-effect, especially if the application we are interested in debugging depends on other components/services/applications that may be sensitive to the presence of a debugger. Notice that a KM debugger will be visible to all applications and doesn’t require hooking to any particular one. It’s invasive.

The next two are UM debugging. The second manner is to run an application from within a debugger. That is, start the application in debug-mode. This method is very useful if we need to debug application start-up code and other entry-point related issues. Unfortunately for us, we can’t use this method with Services (the reason should be obvious by now).

We are stuck with the last method: Attaching the debugger to a running process. With Services this means running the service and then attach a UM debugger to it after it’s run successfully. This method works great and we can even set breakpoints within the Control Handler function used by the SCM to send Control Codes and we will break in our debugger when/if a control code is sent to our service. However there is one very significant disadvantage to this method that might not be obvious at first. The fact that we have to attach a debugger at some arbitrary point after the service is run means that we can’t debug start-up code. Put in another way, we must race with time to attach a debugger to our service to catch it at an as early point in its execution as possible. Clearly, this is not a fun thing to do, nor it’s very reproducible, let alone that you can’t set a breakpoint at a very early point in the start-up sequence (in the entry-point function). Or can we?

In the next part we will see what tricks we can utilize to have a user-friendly and humane way of debugging Services.

  • Share/Bookmark
This entry was posted in Windows Services and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Bad Behavior has blocked 32 access attempts in the last 7 days.