Debugging a Service on Windows Vista


I recently picked up John Robbins’ excellent Debugging Microsoft .NET 2.0 Applications and was flipping through it to discover just what new things I would learn and/or remind myself of. His brilliant description of setting up a local symbol server could not have been more well-timed – I spoke with a customer literally the next day who a symbol server was the perfect solution for, and rather than having them wade through the documentation to understand exactly how to do this, I could just lift up the book (as I said, it was litterally the next day, so it was still in my bag) and say “get this and go to this chapter.” Saved me a lot of time, and solved a serious customer isue.

However, I did notice one thing that may cause some grief on Windows Vista due to Session 0 isolation. In Windows Vista, you see, services alone run in Session 0. This provides defense in depth against elevation of privlege attacks (supported also by MIC, UIPI, etc.). You can no longer send a windows message to a service. The boundary of a windows message, you see, is the desktop. Each desktop lives in a Windows Station, each Windows Station lives in a Session, and if you aren’t even in the same session, you certainly can’t send a windows message.

How is this relevant? Well, here John talks about using gflags.exe to configure startup options for the service. He sets everything up correctly, and launches windbg when the service is launched. Except he is launching windbg directly. In the same desktop. The desktop you are no longer looking at, because you are in Session 1 or higher, and not Session 0. An easy assumption to make, and one that service debuggers have been using successfully for quite a long time. Not a huge deal, but you can set up an even better solution using the implementation of remote debugging in our debugging tools.

Here is how you can set up and debug a service on Vista and have everything appear in your default desktop:

  1. Configure the service control manager to be a bit more patient. It likes to detect hung services and restart them, and if you are debugging you are intentionally hanging the service in the debugger and you don’t want it restarted. So you can add a new DWORD value called ServicesPipeTimeout to HKEY_LOCAL_MACHINE SYSTEM CurrentControlSet Control, and set the value as the number of milliseconds you want to configure the timeout for. Set this guy to 28,800,000 and you’ll get 8 hours of interruption-free debugging. (Obviously, you probably want to set this back or remove it when you are done, because it’s nice not to have hung services just stay hung for 8 hours.)
  2. Tell the SCM to start the debugger. But, instead of launching WinDBG, launch NTSD and set up a remote. In the registry again, configure HKEY_LOCAL_MACHINE SOFTWARE Microsoft Windows NT CurrentVersion Image File Execution Options <name of the service exe> Debugger, and instead of directly feeding it WinDBG, tell it to launch NTSD and set up a remote. On my machine, I have my debugging tools installed to c:debuggers, so I provide the value of C:Debuggersntsd.exe -server tcp:port=1234 -noio. (Any unused TCP port will do – pick your favorite.)
  3. Reboot the machine, so the SCM will pick up the new information.
  4. Attach WinDBG to the remote you now have running using windbg.exe -remote tcp:server=localhost,port=1234
  5. Start debugging!

Of course, you can also use the gflags approach John recommends. The only difference here is setting up a remote rather than launching WinDBG directly. Now, don’t let this dissuade you from picking up John’s book (or attending one of his classes in person). Obviously none of you write applications with bugs, but I bet your co-workers do, and you wouldn’t want to miss out on all of the great tips in here!

Updated 2007-Feb-02

I have heard some feedback from folks who are trying to use this technique to debug services experiencing some problems. If the service you are attempting to debug is an auto-start service (I recommend you change this configuration for the service you are trying to debug), you will block any demand start services. They will queue up behind the auto-start services that the service control manager is attempting to start.

As an example, this will block UAC from working correctly, as the AppInfo service (which is the back end for elevation) is a demand start service.

Other demand start services will see similar behavior. Just wanted to make sure you know what to expect.

(I also updated the timeout to actually be 8 hours instead of 0.8 hours – I neglected a 0.)


Comments (10)

  1. Nikhil says:

    Chris,

    Great post! Many thanks and keep up the good work!

    Nick

  2. SteveH says:

    I used this today to work out a problem where a service gave the timeout message after a few milliseconds.  Turns out it was a dll dependancy problem that only affected a service running from the SCM, from anyones desktop it started fine as a command line app and dependency walker showed no problems.  Very strange, had been racking my brains for a week now, after reading this I found the prob in 10 mins.

    Thanks v. much, will watch this blog very closely from now on!

  3. The Evolution of Malicious IRC BotsSubVirt: Implementing malware with virtual machinesAre there perils in penetration testing?DNS Security BasicsNothing To See HereTheory of Self-Reproducing AutomataThe Myth of the Superuser: Fear, Risk, and Harm OnlineD

  4. I have conneted the debugger to a client machine.And want to see the debug output.I have installed vista on it. But naot able to see the output.

    for this I have set thr registry key as follows-

    "REGISTRYHKLMSYSTEMControlSet001ServicesBridgeMP

    to 0xffff.

    But still not able to see the output.

  5. I have conneted the debugger to a client machine.And want to see the debug output.I have installed vista on it. But naot able to see the output.

    for this I have set thr registry key as follows-

    "REGISTRYHKLMSYSTEMControlSet001ServicesBridgeMP

    to 0xffff.

    But still not able to see the output

    Please tell me is there any other setting , i need to do

    thanks.

  6. Hector says:

    No need to use remote debugging currently. There is a simple way to start windbg interactively. Just start Interactive Services Detection Service which is available in the interim. Step:

    Run services.msc in a command line.

    Start Interactive Services Detection Service.

    When windbg (set in gflags as the default debugger) is launched, an dialog is prompt to ask the user to switch to the service destop.

    You can debug there and switch back to your original destop anytime.

  7. Hi Hector,

    Yes, it does still pop up, and interactive services detection is automatically running (no need to go and turn it on). However, most people like being able to navigate to other functionality of the machine without having to switch back and forth between the session 0 default desktop and the user’s default desktop. Since it’s not any more difficult to configure it this way, I’ve always opted for that route.

    Thanks,

    Chris

  8. Divya says:

    Useful post! Thanks and keep up the good work!

  9. Lurker says:

    Great notes Chris.  Being new to Vista this was another hurdle for me, and I wasted a few hours before I saw your blog.

    As long as a remote debugger is used, it can be done from another machine, and then one will have problems from the firewall.  You could add step 2.5 to the list above:

    2.5 Run "C:Debuggersntsd.exe -server tcp:port=1234 -noio" (or similar) from the command line, to bring up the firewall dialog and allow the port to always go through.