Windows shared services allow us to run system services together in a single service by having multiple DLLs run in a single process called Svchost. This allows Windows to have many services to run with the overhead of a single process.You can find more information about shared services here and here.

I like to do a lot of my user mode debugging from a kernel mode debugger. I can just attach to a Hyper-V VM though a virtual serial port and all my tools are available to me without having to set up a user mode debugger on the target, plus if my application calls into kernel mode I’m all set.

The Svchost process won’t load the DLL until it’s time to start the service, so it can be tricky to set the correct breakpoint to catch the service starting up. This is complicated by the fact that the dll entry point will usually be <module>!ServiceMain, however this is not necessarily the case.

We can leverage the fact that svchost.exe exists in the same shared memory across all the Svchost processes, and a change to this shared memory will affect all of the svchost process. When you set a user mode breakpoint from a kernel mode debugger the debugger changes the user mode code by inserting an int 3 (the debugger changes the code back when it is executed). We can take advantage of this functionality to set one breakpoint that will fire from any svchost process.

If we can get past the Svchost process loading the service dll, we can find the host process main function or any other function we want to set a breakpoint on.

First, find the process address of any Svchost. I’m just showing the first of a long list of processes:

kd> !process0 0 svchost.exe

PROCESS fffffa80098c5970

SessionId: 0Cid: 0270Peb: 7fffffd8000ParentCid: 0204

DirBase: 35986000ObjectTable: fffff8a001115b20HandleCount: 343.

Image: svchost.exe

Now let’s get into the context of this Svchost (it doesn’t matter which one) and set a breakpoint. .process –i sets an invasive breakpoint so we can get into the active context of the process.

kd> .process -i fffffa80098c5970

You need to continue execution (press 'g' <enter>) for the context

to be switched. When the debugger breaks in again, you will be in

the new process context.

Then go the debugger to enter the active process.

kd> g

Break instruction exception - code 80000003 (first chance)

nt!DbgBreakPointWithStatus:

GetServiceMainFunctions()is where Svchost both loads the service DLL and gets the service main function so let’s set a breakpoint for it:

kd> .reload /user

Loading User Symbols

.......................................................

kd> bp svchost!GetServiceMainFunctions

Now I just go the debugger and start my service.I’ll use the workstation service as an example (I had previously stopped the workstation service for this test).

kd> g

At a command prompt on the target I enter:

C:\>net start workstation

In the debugger I get:

Breakpoint 0 hit

svchost!GetServiceMainFunctions:

0033:00000000`ffc813cc fff3pushrbx

kd> k

Child-SPRetAddrCall Site

00000000`0339f7f8 00000000`ffc8128d svchost!GetServiceMainFunctions

00000000`0339f800 000007fe`fe38a82d svchost!ServiceStarter+0xba

00000000`0339f890 00000000`77a5f56d sechost!ScSvcctrlThreadW+0x25

00000000`0339f8c0 00000000`77b93281 kernel32!BaseThreadInitThunk+0xd

00000000`0339f8f0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

svchost!GetServiceMainFunctions is called from Svchost!ServiceStarter.I just leave GetServiceMainFunctions with gu (Go Up). Now the service dll will have been loaded and I can load symbols for wkssvc.dll and get the service main() function.