How to locate the service in svchost.exe that crashed it?

I'm seeing that the following thread crashed the svchost.exe, which in turn resulted in MANUALLY_INITIATED_CRASH due to user-mode-exceptions being enabled in the kernel.

        THREAD ffff898d32317080  Cid 14bc.14c0  Teb: 000000679d633000 Win32Thread: ffff898d32446230 RUNNING on processor 3
        Not impersonating
        DeviceMap                 ffffde0fcd224480
        Owning Process            ffff898d32314080       Image:         svchost.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      2031           Ticks: 0
        Context Switch Count      67             IdealProcessor: 1             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.031
        Win32 Start Address svchost!wmainCRTStartup (0x00007ff7219f69d0)
        Stack Init ffffc806722aadb0 Current ffffc806722a9d30
        Base ffffc806722ab000 Limit ffffc806722a3000 Call 0000000000000000
        Priority 9  BasePriority 8  Decay Boost 1  IoPriority 2  PagePriority 5
        Child-SP          RetAddr               Call Site
        ffffc806`722a9950 fffff801`1ca5d104     nt!KeBugCheck2+0x1fc
        ffffc806`722a9f70 fffff801`1d278368     nt!KeBugCheckEx+0x14  
        (Inline Function) --------`--------     nt!KdpCauseBugCheck+0x20 (Inline Function @ fffff801`1d278368)
        ffffc806`722a9f80 fffff801`1d2775b4     nt!KdpSendWaitContinue+0x680 
        ffffc806`722aa190 fffff801`1ccc5184     nt!KdpReportExceptionStateChange+0xac 
        ffffc806`722aa2e0 fffff801`1d27a640     nt!KdpReport+0xa4
        ffffc806`722aa320 fffff801`1ca5765c     nt!KdpTrap+0x168 
        ffffc806`722aa350 fffff801`1ca6b8d4     nt!KdTrap+0x5c
        ffffc806`722aa3a0 fffff801`1cab29a8     nt!KiDispatchException+0x374  
        (Inline Function) --------`--------     nt!KiDispatchExceptionOnExceptionStack+0x1c (Inline Function @ fffff801`1cab29a8) 
        ffffc806`722aa900 fffff801`1ce05c5c     nt!KiSynchronousException+0xd8 
        ffffc806`722aa9f0 fffff801`1ce05d38     nt!KzSynchronousException+0x24 
        ffffc806`722aaa50 00007ffc`28b3c104     nt!KiUserExceptionHandlerRaise+0x54 (TrapFrame @ ffffc806`722aaa50)  
        00000067`9d5de8d0 00007ffc`24922c28     ntdll!RtlUnhandledExceptionFilter2+0x374
        00000067`9d5de920 00000000`00000000     KERNELBASE+0x142c28

I have three questions:

  1. Why does the callstack seem to be cut off in user mode?

  2. Can user-mode exceptions be handled on a different thread than where they were raised? (this may explain the call stack that I showed above.)

  3. How to tell which service (or which DLL) caused this exception? (that was loaded into svchost.exe)

1 Like

This won't help after the fact, but here's something that I wrote up long ago which I frequently do to track down the Windows service sub-processes (is there a term for those?).

This will discuss splitting SVCHost.exe services into their own processes in Windows, in my case, Windows Server 2016. The reason for doing this is for debugging and performance analysis.

The list of SVCHOST.EXE services is obtained via the command:

tasklist /SVC /FI "IMAGENAME eq svchost.exe"

My Windows image shares the processes as follows.

Image Name PID Services
========================= ======== ============================================
svchost.exe 704 BrokerInfrastructure, DcomLaunch, LSM,
PlugPlay, Power, SystemEventsBroker
svchost.exe 760 RpcEptMapper, RpcSs
svchost.exe 908 Appinfo, CertPropSvc, DsmSvc, gpsvc, IAS,
IKEEXT, iphlpsvc, ProfSvc, Schedule, SENS,
SessionEnv, ShellHWDetection, Themes,
UserManager, Winmgmt, wlidsvc, WpnService,
wuauserv
svchost.exe 916 TermService
svchost.exe 1012 NcbService, PcaSvc, ScDeviceEnum, TrkWks,
UALSVC, UmRdpService, WdiSystemHost,
WPDBusEnum, wudfsvc
svchost.exe 364 Dhcp, EventLog, lmhosts, TimeBrokerSvc
svchost.exe 492 BFE, CoreMessagingRegistrar, DPS, MpsSvc
svchost.exe 1088 EventSystem, FontCache, LicenseManager,
netprofm, nsi, RemoteRegistry,
WdiServiceHost, WinHttpAutoProxySvc
svchost.exe 1336 CryptSvc, Dnscache, LanmanWorkstation,
NlaSvc, WinRM
svchost.exe 1936 AppXSvc, ClipSVC
svchost.exe 980 Wcmsvc
svchost.exe 1532 StateRepository, tiledatamodelsvc
svchost.exe 2064 PolicyAgent
svchost.exe 2236 AppHostSvc
svchost.exe 2268 DiagTrack
svchost.exe 2404 LanmanServer
svchost.exe 2484 W3SVC, WAS
svchost.exe 1948 TapiSrv
svchost.exe 5360 ftpsvc
svchost.exe 6152 CDPUserSvc_fcec0, OneSyncSvc_fcec0

When I set all of the above processes to their own processes, the system doesn't reboot correctly, getting stuck at a black screen with a slow mouse pointer. After trial-and-error, there are a bunch of processes that can't be their own procedss, so I I come up with the following list of commands.

sc config ftpsvc type= own
sc config iphlpsvc type= own
sc config lmhosts type= own
sc config netprofm type= own
sc config nsi type= own
sc config wisvc type= own
sc config wlidsvc type= own
sc config wuauserv type= own
sc config wudfsvc type= own
sc config AppHostSvc type= own
sc config Appinfo type= own
sc config CDPUserSvc type= own
sc config CertPropSvc type= own
sc config CryptSvc type= own
sc config Dhcp type= own
sc config DiagTrack type= own
sc config Dnscache type= own
sc config DsmSvc type= own
sc config EventLog type= own
sc config EventSystem type= own
sc config FontCache type= own
sc config IAS type= own
sc config IKEEXT type= own
sc config LanmanServer type= own
sc config LanmanWorkstation type= own
sc config LicenseManager type= own
sc config NcbService type= own
sc config NlaSvc type= own
sc config OneSyncSvc type= own
sc config PcaSvc type= own
sc config PlugPlay type= own
sc config PolicyAgent type= own
sc config Power type= own
sc config ProfSvc type= own
sc config RemoteRegistry type= own
sc config SENS type= own
sc config ScDeviceEnum type= own
sc config Schedule type= own
sc config SessionEnv type= own
sc config ShellHWDetection type= own
sc config TapiSrv type= own
sc config TermService type= own
sc config Themes type= own
sc config TrkWks type= own
sc config UALSVC type= own
sc config UmRdpService type= own
sc config UserManager type= own
sc config UsoSvc type= own
sc config WPDBusEnum type= own
sc config Wcmsvc type= own
sc config WdiServiceHost type= own
sc config WdiSystemHost type= own
sc config WinHttpAutoProxySvc type= own
sc config WinRM type= own
sc config Winmgmt type= own
sc config WpnService type= own

REM These must be shared or the service won't start.
sc config W3SVC type= share
sc config WAS type= share

REM These must be shared or the system will not boot.
sc config RpcEptMapper type= share
sc config RpcSs type= share

REM These must be shared or the system will not boot.
sc config AppXSvc type= share
sc config ClipSVC type= share

REM These generate errors.
sc config gpsvc type= own
sc config tiledatamodelsvc type= own
sc config BFEs type= own
sc config BrokerInfrastructure type= own
sc config CoreMessagingRegistrars type= own
sc config DcomLaunch type= own
sc config DPSs type= own
sc config LSM type= own
sc config MpsSvcs type= own
sc config StateRepository type= own
sc config SystemEventsBroker type= own
sc config TimeBrokerSvc type= own

@Taed_Wynnell I wonder how does tasklist get the names of services from the svchost.exe?

I wonder how does tasklist get the names of services from the svchost.exe?
well this is one possible method

#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "advapi32.lib")
int main(void)
{
    printf("Enumerating Services\n");
    SC_HANDLE Scmgr = NULL;
    DWORD BytesNeeded = 0;
    DWORD Retserv = 0;
    BYTE *servinf = NULL;
    BOOL Servstat;
    Scmgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == Scmgr)
    {
        printf("OpenSCManager failed (%x)\n", GetLastError());
        return 0;
    }
    printf("Service manager Handle is %p\n", Scmgr);
    Servstat = EnumServicesStatusExA(
        Scmgr, SC_ENUM_PROCESS_INFO, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL,
        servinf, 0, &BytesNeeded, &Retserv, NULL, NULL);

    if (!Servstat && GetLastError() == ERROR_MORE_DATA)
    {
        SIZE_T asize = BytesNeeded + 0x1000;
        BytesNeeded = 0;
        printf("BytesNeed = %I64x\n Allocating\n", asize);
        servinf = (BYTE *)VirtualAlloc(
            NULL, asize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if (servinf == NULL)
        {
            printf("VIrtual Alloc Failed\n");
            return 0;
        }
        Servstat = EnumServicesStatusExA(
            Scmgr, SC_ENUM_PROCESS_INFO, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL,
            servinf, asize, &BytesNeeded, &Retserv, NULL, NULL);
        if (Servstat)
        {
            printf("Services Returned = %x\n", Retserv);
            ENUM_SERVICE_STATUS_PROCESSA *ServStatProc = (ENUM_SERVICE_STATUS_PROCESSA *)servinf;
            DWORD ServCount = 0;
            while (ServCount < Retserv)
            {

                printf("%u\t%-50s\t",
                       ServStatProc->ServiceStatusProcess.dwProcessId,
                       ServStatProc->lpDisplayName);
                HANDLE hproc = NULL;
                char exepath[MAX_PATH] = {0};
                DWORD plen = MAX_PATH;
                hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
                                    FALSE, ServStatProc->ServiceStatusProcess.dwProcessId);
                if (hproc)
                {
                    if (QueryFullProcessImageNameA(hproc, 0, exepath, &plen))
                    {
                        printf("%s\n", exepath);
                    }
                    else
                    {
                        printf("noname\n");
                    }
                }
                else
                {
                    printf("no proc\n");
                }

                ServStatProc++;
                ServCount++;
            }
        }
    }
    return 0;
}

should yield

:\>tasklist /svc /fi "imagename eq ls*"

Image Name                     PID Services
========================= ======== ============================================
lsass.exe                     1000 KeyIso, SamSs, VaultSvc

:\>ensrv.exe | sort | grep lsass
1000    CNG Key Isolation                                       C:\Windows\System32\lsass.exe
1000    Credential Manager                                      C:\Windows\System32\lsass.exe
1000    Security Accounts Manager                               C:\Windows\System32\lsass.exe

You are just enumerating all services in the system.

Well that is what TaksList does just dump it in windbg and check for yourself just uses some fastproxy ->next stuff in tasklist::show() to print the result

see below

running the command under debugger

`C:\>cdb tasklist /svc /fi "imagename eq ls"`
Microsoft (R) Windows Debugger Version 10.0.19041.685 AMD64
CommandLine: tasklist /svc /fi "imagename eq ls"
ntdll!LdrpDoDebuggerBreak+0x30:
00007ffc`a4d60750 cc              int     3

checking the commandline thats being debugged

0:000> dt ntdll!_PEB ProcessParameters->CommandLine @$peb

   +0x020 ProcessParameters              :
      +0x070 CommandLine                    : _UNICODE_STRING "tasklist /svc /fi "imagename eq ls""

setting a relevent breakpoint and continue

0:000> bp tasklist!CTaskList::LoadServicesInfo
0:000> g

Breakpoint 0 hit
tasklist!CTaskList::LoadServicesInfo:
00007ff6`162768d4 488bc4          mov     rax,rsp

enumerating the calls being made in the relevent function

0:000> uf /c .
tasklist!CTaskList::LoadServicesInfo (00007ff6`162768d4)
  tasklist!CTaskList::LoadServicesInfo+0x6a (00007ff6`1627693e):
    call to ADVAPI32!OpenSCManagerWStub (00007ffc`a31678c0)
  tasklist!CTaskList::LoadServicesInfo+0x83 (00007ff6`16276957):
    call to tasklist!SaveLastError (00007ff6`1627ae3c)
  tasklist!CTaskList::LoadServicesInfo+0xcc (00007ff6`162769a0):
    call to tasklist!AllocateMemory (00007ff6`1627cf08)
  tasklist!CTaskList::LoadServicesInfo+0xe6 (00007ff6`162769ba):
    call to KERNEL32!SetLastErrorStub (00007ffc`a3fe5fc0)
  tasklist!CTaskList::LoadServicesInfo+0xf2 (00007ff6`162769c6):
    call to tasklist!SaveLastError (00007ff6`1627ae3c)
  tasklist!CTaskList::LoadServicesInfo+0x142 (00007ff6`16276a16):
    call to ADVAPI32!EnumServicesStatusExWStub (00007ffc`a31538b0) <<<<<<<<<<<<<<<
  tasklist!CTaskList::LoadServicesInfo+0x15b (00007ff6`16276a2f):
    call to tasklist!FreeMemory (00007ff6`1627cdf8)
  tasklist!CTaskList::LoadServicesInfo+0x160 (00007ff6`16276a34):
    call to KERNEL32!GetLastErrorStub (00007ffc`a3fe5f00)
  tasklist!CTaskList::LoadServicesInfo+0x180 (00007ff6`16276a54):
    call to tasklist!SaveLastError (00007ff6`1627ae3c)
  tasklist!CTaskList::LoadServicesInfo+0x188 (00007ff6`16276a5c):
    call to ADVAPI32!CloseServiceHandleStub (00007ffc`a31678a0)
  tasklist!CTaskList::LoadServicesInfo+0x1a9 (00007ff6`16276a7d):
    call to tasklist!FreeMemory (00007ff6`1627cdf8)

remove the bp and set a bp on FreeMemory and continue

0:000> bc *
0:000> bp tasklist!FreeMemory
0:000> g
Breakpoint 0 hit
tasklist!FreeMemory:
00007ff6`1627cdf8 48895c2408      mov     qword ptr [rsp+8],rbx ss:00000072`e30ef410=0000000000000000

checking the contents of memory and type casting the result

0:000> dq @rcx l3
00000072`e30ef4c0  00000175`8325bf00 00000000`00000001
00000072`e30ef4d0  00007ff6`162847c8
0:000> dq poi(@rcx) l3
00000175`8325bf00  00000175`8325cef0 00000175`8325cec0
00000175`8325bf10  00000004`00000030

0:000> dt -r ole32!ENUM_SERVICE_STATUS_PROCESS poi(@rcx)
   +0x000 lpServiceName    : 0x00000175`8325cef0  "Appinfo"
   +0x008 lpDisplayName    : 0x00000175`8325cec0  "Application Information"
   +0x010 ServiceStatusProcess : _SERVICE_STATUS_PROCESS
      +0x000 dwServiceType    : 0x30
      +0x004 dwCurrentState   : 4
      +0x008 dwControlsAccepted : 0x81
      +0x00c dwWin32ExitCode  : 0
      +0x010 dwServiceSpecificExitCode : 0
      +0x014 dwCheckPoint     : 0
      +0x018 dwWaitHint       : 0
      +0x01c dwProcessId      : 0x20a0
      +0x020 dwServiceFlags   : 0

finding who is the owner of the pid and if it indeed matches the service

0:000> ? 0x20a0
Evaluate expression: 8352 = 00000000`000020a0
0:000>
	  

0:000> .shell  -ci ".tlist /v" grep -A3 -B3 8352
 0n1400 svchost.exe
 0n1552 svchost.exe
       Session: 0  Services: PcaSvc  Command Line: C:\WINDOWS\system32\svchost.exe -k LocalSystemNetworkRestricted -p -s PcaSvc
 0n8352 svchost.exe
       Session: 0  User: NT AUTHORITY\SYSTEM  Services: Appinfo  Command Line: C:\WINDOWS\system32\svchost.exe -k netsvcs -p -s Appinfo <<<<<
 0n3724 SecurityHealthService.exe
 0n5588 svchost.exe
.shell: Process exited

you can see Appinfo is hosted by svchost having pid 8352 in a live session

hope that makes sense