一、调试Windows服务知识点汇总
若服务源码是自己开发的,可在被调试代码逻辑中主动调用DebugBreak(),以此呼叫”Just-In-Time Debugging”;也可通过命令行参数让被调试代码逻辑以普通控制台进程方式运行,这种没法调试SCM相关的代码。
一般调试Windows服务,并非服务源码可控的情形。通常分两种情况,一种是被调试代码逻辑可以在Attach之后触发,一种是被调试代码逻辑只在服务启动时触发。第一种情况和普通调试一样,第二种情况相对复杂些,要做些特别设置。以前没有过第二种需求,只知道大概思路,未实践过。最近碰上,实践一番,有不少琐碎的知识点,在此记录一二。
在Win10企业版2016 LTSB 1607(OS Build 14393.4704)上测试。
1) 官方文档
windbg帮助(debugger.chm)
Debugging Techniques
Specialized Debugging Techniques
Debugging a Service Application
Choosing the Best Method
Preparing to Debug the Service Application
Debugger Operation
Remote Debugging
Remote Debugging Through the Debugger
Activating a Debugging Server
Activating a Debugging Client
Controlling a Remote Debugging Session
官方文档是最好的,看过后就差不多了,不过我意识到这点有些晚。
2) Debugging Server模式
为了调试服务启动阶段,需要用到”Debugging Server”
2.1) Process Servers (User Mode)
在Guest中以管理员身份运行
dbgsrv.exe -t tcp:port=8765,password=8765
在Host中
cdb.exe -noinh -snul -hd -o -premote tcp:server=192.168.65.136,port=8765,password=8765 -pn lsass.exe
这种组合是”Process Servers (User Mode)”,不是”Debugging Server”,容易搞混的两种术语。
2.2) Debugging Server
在Guest中
cdb.exe -server tcp:port=8766,password=8766 -noinh -snul -hd -o -G notepad.exe
在Host中
cdb.exe -remote tcp:server=192.168.65.136,port=8766,password=8766 -noinh -snul -hd
这种组合是”Debugging Server”。
调试客户端用的是-remote,不是-premote。
调试服务端-server、调试客户端-remote必须是各自命令的第一个参数。调试客户端不能指定-p、-pn,完全由调试服务端决定调试目标。
调试客户端指定”-noinh -snul -hd”可能并无意义?反正调试客户端指定不了”-o”。
一个调试服务端可以对应多个调试客户端,比如在Host中开第二个cdb接入调试服务端。假设现在有一个调试服务端、两个调试客户端,这三端都可以输入调试命令,调试命令产生的输出会同时出现在三端。”Debugging Server”这种搞法允许多人同时协作调试同一个目标进程,有点意思,这与dbgsrv模式完全不同。
.servers
显示接入的调试服务端
.clients
显示接入的所有调试客户端
.endsrv 0
让调试服务端不再侦听8766/TCP。这个有延迟,在调试服务端用Process Explorer查看cdb,发现8766/TCP仍在LISTEN状态,实际上调试服务端不再接受新的入连接。新开调试客户端尝试接入,失败,再去看调试服务端,不再侦8766/TCP。
不影响已接入的所有调试客户端,已有TCP连接均保持。
.shell whoami
无论在哪端使用.shell,真正执行的都是调试服务端的shell,一般是cmd
.noshell
关闭调试服务端对.shell的支持。没有反命令,一旦生效,将保持到调试服务端终止。
!envvar _NT_SYMBOL_PATH
可用!envvar查看被调试进程环境变量。但该命令依赖ntdll!_PEB,要求ntdll.pdb就位。若.sympath有误,找不到ntdll.pdb,!envvar报错。
2.3) ServerTransport/ClientTransport
-server ServerTransport
-remote ClientTransport
关于ServerTransport/ClientTransport的语法,参看windbg帮助。
“npipe:pipe”要求LanmanServer服务启动中,涉及SMB认证,无谓地引入复杂性。像我,LanmanServer服务常年禁用中。若调试服务端、调试客户端都在本机,且LanmanServer服务启动中,用”npipe:pipe”也行
cdb.exe -server npipe:pipe=anyname,password=8766 -noinh -snul -hd -o -G notepad.exe
cdb.exe -remote npipe:server=localhost,pipe=anyname,password=8766 -noinh -snul -hd
C/S不在同一主机时,并不推荐”npipe:pipe”。
2.4) -noio
调试服务端指定-noio后,调试服务端本身不接受调试命令的输入,也不同步显示调试命令产生的输出,无法Ctrl-C终止调试服务端。调试Windows服务时,建议始终指定。
2.5) -noshell
调试服务端指定-noshell后,一上来就关闭调试服务端对.shell的支持。调试Windows服务时,建议始终指定。
2.6) IcfEnable (PFW放行)
Win10有PFW,cdb首次侦听8766/TCP时会弹框提示是否允许入连接,必须选”允许”,让相应规则进入wf.msc。
若通过IFEO间接启动cdb,并且是cdb首次侦听8766/TCP,情况就有些微妙了。假设wf.msc中无相应放行规则,按理要弹框选择的。但若IFEO的原始进程在Session 0中启动,cdb导致的弹框也在Session 0中,你看不到,没法选,8766/TCP被阻断中。
为解决上述问题,可提前增设PFW规则,避免弹框提示。在Session 1中用cdb触发弹框,选”允许”,这是一种办法。另一种办法是在管理员级cmd中执行
cdb.exe -server tcp:port=8766,password=8766,icfenable -noinh -snul -hd -o -G notepad.exe
-server中指定了IcfEnable,大小写不敏感。这条命令不会触发弹框,直接在wf.msc中增设名为”Debugger RPC Port Mapping”的8766/TCP放行规则。
$ netsh advfirewall firewall show rule name=”Debugger RPC Port Mapping”
Rule Name: Debugger RPC Port Mapping
Enabled: Yes
Direction: In
Profiles: Domain,Private,Public
Grouping:
LocalIP: Any
RemoteIP: Any
Protocol: TCP
LocalPort: 8766
RemotePort: Any
Edge traversal: No
Action: Allow
Ok.
IcfEnable添加到wf.msc的放行规则不会因调试终止而自动删除,始终存在,只能手工删除。只有在管理员级或SYSTEM级别时,指定IcfEnable才有效,否则即使指定IcfEnable,仍将弹框提示。
windbg帮助里说,IcfEnable用于”npipe:pipe”时会放行139、445/TCP,未实测确认。
2.7) 调试示例
在Guest中以管理员身份运行
cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G notepad.exe
在Host中
cdb.exe -remote tcp:server=192.168.65.136,port=8766,password=8766 -noinh -snul -hd
调试客户端接入后,发现调试服务端断在ibp(初始化断点)
# Child-SP RetAddr Call Site
00 000000c76437f4b0 00007fff88d83268 ntdll!LdrpDoDebuggerBreak+0x30
01 000000c76437f4f0 00007fff88d68145 ntdll!LdrpInitializeProcess+0x1be4
02 000000c76437f900 00007fff88d67fae ntdll!LdrpInitialize+0x141
03 000000c76437f980 0000000000000000 ntdll!LdrInitializeThunk+0xe
.prompt_allow +reg +ea +dis
bp /1 @$exentry “kpn”
2.7.1) 勿在初始化断点处设置硬件断点
在ibp用ba设置硬件断点,一般会失败报错
ba e1 /1 @$exentry “kpn”
^ Unable to set breakpoint error
The system resets thread contexts after the process
breakpoint so hardware breakpoints cannot be set.
Go to the executable’s entry point and set it then.
尽量避免在ibp对任何地址设置硬件断点,因为后面会过ZwContinue,该函数会切换CONTEXT,必然导致DR*寄存器被修改。理论上在ibp处不是不能设硬件断点,而是设了之后,很快就会被破坏。为了避免将来这种破坏引起误会,cdb干脆禁止在ibp处使用ba设置硬件断点,如果尝试ba命令,会提示到了@$exentry之后才可以设硬件断点。其实在@$exentry之前很多地方都可以正常使用ba设置硬件断点,比如”sxe cpr”、”sxe ld:ntdll”命中时、流程到达ntdll!RtlUserThreadStart时,这几处都可以ba。
反调试手段之一就是拦截ZwContinue,修改DR*、TF等。
假设前面那个测试环境是A环境,现在换到另一个B环境。在B环境中,在ibp用ba设置硬件断点,没有失败报错,bl可以看到硬件断点,当然,后来还是被ZwContinue破坏而失效。B环境发生的事很不友好,我在B环境中被坑了一把,当时忘了ibp处设置硬件断点的坑,发现ba断不下来,还奇怪呢,云海提醒之后才重新想起缘由。
A、B环境都是Win10企业版2016 LTSB 1607。A打过2021.10补丁,B打过2021.11补丁,ntoskrnl.exe不同,但具体到notepad.exe、ntdll.dll这两个模块,并无差别。A环境有kd接入,B环境未进入”Test Mode”。A、B所用cdb是同一版本。
云海在更早期的其他环境中测试,重现B环境出现的现象,看上去与最近这些补丁无关。
未深究造成A、B差异的原因,最靠谱的办法当然是调试cdb本身,回头有时间看看。
2.7.2) Detach
推荐流程
.endsrv 0 // 调试服务端不再侦听8766/TCP
.detach // 让被调试进程脱离调试后运行
qqd // 离开调试客户端操作界面
这样干之后,调试服务端cdb终止,notepad保持运行。就notepad调试示例而言,直
接qqd就可以了,不需要前两步。
3) ServicesPipeTimeout
参[2]
Windows的SCM(Service Control Manager)启动某个服务时缺省等待30秒,超时则认为启动失败,会有其他动作,比如杀掉目标进程重启服务。假设需要调试服务启动阶段代码,断点命中后的交互式调试很容易导致服务启动阶段超时被杀,可能上一步还在kpn,下一步发现目标进程不在了。这很影响调试,幸好有注册表设置这个超时。
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control]
“ServicesPipeTimeout”=dword:15752a00
reg.exe add “HKLM\SYSTEM\CurrentControlSet\Control” /v “ServicesPipeTimeout” /t REG_DWORD /d 0x15752a00 /f
reg.exe query “HKLM\SYSTEM\CurrentControlSet\Control” /v “ServicesPipeTimeout”
reg.exe delete “HKLM\SYSTEM\CurrentControlSet\Control” /v “ServicesPipeTimeout” /f
0x15752a00是360000000,单位是毫秒,换算过来就是100小时。需要重启OS使之生效。该值缺省30000,即30秒。
3.1) 热Patch让ServicesPipeTimeout生效
碰上一个场景,Guest接有kd,但未提前设置过ServicesPipeTimeout,因故不方便重启OS,想找个热Patch方案让ServicesPipeTimeout生效。此时确实有热Patch方案,简介如下
kd> !process 0 0 services.exe
PROCESS ffffda884002c480
SessionId: 0 Cid: 030c Peb: 13e8b6c000 ParentCid: 02ac
DirBase: 2198e3000 ObjectTable: ffffa08d0c9a0e80 HandleCount:
Image: services.exe
.process /i ffffda884002c480;g
!process -1 0
.reload /f /user
bp /p @$proc nt!NtCreateUserProcess
回到Guest,在管理员级cmd中执行
sc start spooler
前述内核态断点命中
Patch
ed services!g_dwScControlMessageTimeout 0n360000000
ed services!g_dwHandlerTimeout 0n360000000
eb services!g_fDefaultControlMessageTimeout 0
UnPatch
ed services!g_dwScControlMessageTimeout 0n30000
ed services!g_dwHandlerTimeout 0n30000
eb services!g_fDefaultControlMessageTimeout 1
禁用断点,继续执行
bd *
g
Win10无法用cdb调试services.exe,涉及PPL保护,回头单写一下此事。
4) IFEO (Image File Execution Options)
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\spoolsv.exe]
“Debugger”=”C:\temp\cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G -y \”srv\\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols\””
reg.exe add “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\spoolsv.exe” /v “Debugger” /t REG_SZ /d “C:\temp\cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G -y \”srv\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols\”” /f
reg.exe query “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\spoolsv.exe” /v “Debugger”
reg.exe delete “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\spoolsv.exe” /v “Debugger” /f
有几点微妙之处,后面逐一讨论。
4.1) cdb vs ntsd
windbg帮助里有
The only difference between NTSD and CDB is that NTSD spawns a new console
window while CDB inherits the window from which it was invoked. Since the
start command can also be used to spawn a new console window, the following
two constructions will give the same results
start cdb [parameters]
ntsd [parameters]
用ntsd的话,会额外产生一个conhost.exe进程。调试Windows服务时还是用cdb好了。
4.2) NT AUTHORITY\SYSTEM
spoolsv.exe是以”NT AUTHORITY\SYSTEM”身份启动的,通过IFEO启动cdb(或ntsd),cdb也是以SYSTEM身份执行,将涉及几个小问题。
4.2.1) -noshell
若IFEO中未指定-noshell,客户端cdb远程接入后可以用这类命令
.shell whoami
.shell echo %_NT_SYMBOL_PATH%
这是SYSTEM级别的shell。
4.2.2) _NT_SYMBOL_PATH环境变量
若_NT_SYMBOL_PATH不在系统级环境变量中,只在用户级环境变量中,SYSTEM账户就没有_NT_SYMBOL_PATH环境变量,可用.shell或!envvar检查之。
4.2.3) \vmware-host\Shared Folders
SYSTEM账户可以访问”\vmware-host\Shared Folders\sym”,但不能访问[net use Z: “\vmware-host\Shared Folders”]映射的Z盘,SYSTEM账户并未映射过盘符。可能SYSTEM账户干脆无法”net use”?
4.3) .sympath/-y
为使用符号,保险起见,可在IFEO中用-y指定符号路径。即使未在IFEO中使用-y,将来总是可以用.sympath设置符号路径
.sympath srv\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols
用.sympath时不要用双引号,用-y时要用双引号,注意转义。
4.4) 用gflags图形界面设置IFEO
前面直接操作注册表设置IFEO,也可以用windbg自带的gflags设置IFEO,参[3]、[6]、[7]。
a) 执行gflags
b) 切到”Image File”页
c) 在Image中输入spoolsv.exe,按TAB键
d) 勾中Debugger,输入
C:\temp\cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G -y “srv\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols”
4.4.1) 用gflags命令行设置IFEO (不推荐)
参[8],有人琢磨出用gflags命令行设置IFEO的办法
gflags.exe /p /enable spoolsv.exe /debug “C:\temp\cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G -y \”srv\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols\””
但上述gflags命令会额外设置几个注册表项,比如GlobalFlag、PageHeapFlags
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\spoolsv.exe]
“Debugger”=”C:\temp\cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G -y \”srv\\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols\””
“GlobalFlag”=”0x02000000”
“PageHeapFlags”=”0x2”
reg.exe query “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\spoolsv.exe” /v “Debugger”
下列gflags命令会同时删除上述三个注册表项
gflags.exe /p /disable spoolsv.exe
我们并不想设置GlobalFlag、PageHeapFlags,未找到”干净”的gflags命令行参数。只能用gflags的图形界面进行”干净”的IFEO设置。
5) 远程调试
5.1) 手工启动待调试服务
在Guest中以管理员身份运行
sc qc spooler
sc query spooler
sc queryex spooler
sc config spooler start= demand
sc stop spooler
sc start spooler
sc启动spooler服务时,由于IFEO,实际执行的是
C:\temp\cdb.exe -server tcp:port=8766,password=8766,icfenable -noshell -noio -noinh -snul -hd -o -G -y “srv\vmware-host\Shared Folders\symhttp://msdl.microsoft.com/download/symbols” spoolsv.exe
这将进入Debugging Server模式,cdb位于Session 0,不可见,等待调试客户端接入。由于未指定-g,cdb将停在ibp。
5.2) 调试客户端接入
cdb.exe -remote tcp:server=192.168.65.136,port=8766,password=8766 -noinh -snul -hd
# Child-SP RetAddr Call Site
00 000000000103f110 00007fff88d83268 ntdll!LdrpDoDebuggerBreak+0x30
01 000000000103f150 00007fff88d68145 ntdll!LdrpInitializeProcess+0x1be4
02 000000000103f560 00007fff88d67fae ntdll!LdrpInitialize+0x141
03 000000000103f5e0 0000000000000000 ntdll!LdrInitializeThunk+0xe
.prompt_allow +reg +ea +dis
bp /1 @$exentry “kpn”
bp sechost!StartServiceCtrlDispatcherW “kpn”
勿在ibp处ba设断,就用普通的bp设断
# Child-SP RetAddr Call Site
00 000000000087f818 00007ff7ed6c8143 sechost!StartServiceCtrlDispatcherW
01 000000000087f820 00007ff7ed6cdded spoolsv!main+0x93
02 000000000087f850 00007fff885b84d4 spoolsv!__mainCRTStartup+0x14d
03 000000000087f890 00007fff88d41791 KERNEL32!BaseThreadInitThunk+0x14
04 000000000087f8c0 0000000000000000 ntdll!RtlUserThreadStart+0x21
5.3) 无法完美退出远程调试
推荐流程
.endsrv 0 // 调试服务端不再侦听8766/TCP
.detach // 让被调试进程脱离调试后运行
Ctrl-B 回车 // 离开调试客户端操作界面
这样干之后,被调试进程正常跑,但服务端cdb不会结束,也在那儿,只是不能再调试目标进程。
与前面notepad调试示例不同,用IFEO调试spoolsv.exe时,如下操作序列会出幺蛾子
.endsrv 0
.detach
qqd
这样干之后,服务端cdb与spoolsv.exe都彻底终止。给服务端cdb指定-pd,现象依旧;当然,-pd实际就是.detach。是我哪里用得不对?
不知造成这种差异的原因是啥,与spoolsv.exe是服务进程相关,还是与IFEO相关?
6) Isolating the Service
打印服务本来就在单独的spoolsv.exe进程,但很多其他服务共用一个svchost.exe,比如
$ tasklist /svc /fi “services eq dnscache”
Image Name PID Services
========================= ========
svchost.exe 964 CryptSvc, Dnscache, LanmanWorkstation,
NlaSvc, TermService
$ sc qc dnscache
SERVICE_NAME: dnscache
TYPE : 20 WIN32_SHARE_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : C:\Windows\system32\svchost.exe -k NetworkService
LOAD_ORDER_GROUP : TDI
TAG : 0
DISPLAY_NAME : DNS Client
DEPENDENCIES : Tdx
: nsi
SERVICE_START_NAME : NT AUTHORITY\NetworkService
将Dnscache服务隔离出来,单独使用一个svchost.exe,不与其他服务共用,是比较稳妥的选择;好处在于,调试目标服务时不影响其他服务。官方文档提出三种隔离方案。
6.1) Moving the Service to its Own Group (推荐)
关注”svchost.exe -k”的参数,这是原始注册表设置
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost]
“NetworkService”=hex(7):43,00,72,00,79,00,70,00,74,00,53,00,76,00,63,00,00,00,\
6e,00,6c,00,61,00,73,00,76,00,63,00,00,00,6c,00,61,00,6e,00,6d,00,61,00,6e,\
00,77,00,6f,00,72,00,6b,00,73,00,74,00,61,00,74,00,69,00,6f,00,6e,00,00,00,\
57,00,69,00,6e,00,52,00,4d,00,00,00,57,00,45,00,43,00,53,00,56,00,43,00,00,\
00,4d,00,61,00,70,00,73,00,42,00,72,00,6f,00,6b,00,65,00,72,00,00,00,44,00,\
4e,00,53,00,43,00,61,00,63,00,68,00,65,00,00,00,44,00,48,00,43,00,50,00,00,\
00,54,00,65,00,72,00,6d,00,53,00,65,00,72,00,76,00,69,00,63,00,65,00,00,00,\
54,00,61,00,70,00,69,00,73,00,72,00,76,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost\NetworkService]
“CoInitializeSecurityParam”=dword:00000001
“DefaultRpcStackSize”=dword:0000001c
SvcHost下有名为NetworkService的键值,类型是REG_MULTI_SZ,内容是
CryptSvc
nlasvc
lanmanworkstation
WinRM
WECSVC
MapsBroker
DNSCache
DHCP
TermService
Tapisrv
这与前面tasklist的输出相符。SvcHost下还有名为NetworkService的子键。这是改动后的注册表设置。
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost]
“NetworkService”=hex(7):43,00,72,00,79,00,70,00,74,00,53,00,76,00,63,00,00,00,\
6e,00,6c,00,61,00,73,00,76,00,63,00,00,00,6c,00,61,00,6e,00,6d,00,61,00,6e,\
00,77,00,6f,00,72,00,6b,00,73,00,74,00,61,00,74,00,69,00,6f,00,6e,00,00,00,\
57,00,69,00,6e,00,52,00,4d,00,00,00,57,00,45,00,43,00,53,00,56,00,43,00,00,\
00,4d,00,61,00,70,00,73,00,42,00,72,00,6f,00,6b,00,65,00,72,00,00,00,44,00,\
48,00,43,00,50,00,00,00,54,00,65,00,72,00,6d,00,53,00,65,00,72,00,76,00,69,\
00,63,00,65,00,00,00,54,00,61,00,70,00,69,00,73,00,72,00,76,00,00,00,00,00
“TempGrp”=hex(7):44,00,4e,00,53,00,43,00,61,00,63,00,68,00,65,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost\NetworkService]
“CoInitializeSecurityParam”=dword:00000001
“DefaultRpcStackSize”=dword:0000001c
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost\TempGrp]
“CoInitializeSecurityParam”=dword:00000001
“DefaultRpcStackSize”=dword:0000001c
根据NetworkService组的设置仿造一个新组TempGrp,从前者删除DNSCache,在后者添加DNSCache,其余设置要保持二者间完全一样。
SvcHost下有名为TempGrp的键值,类型是REG_MULTI_SZ,内容是
DNSCache
SvcHost下还有名为TempGrp的子键。
改完注册表后,执行
sc config dnscache binpath= “C:\Windows\system32\svchost.exe -k TempGrp”
sc qc dnscache
重启OS使之生效。若充分理解上下文及各种边际效应,某些情况下可以只重启服务使之生效,Dnscache服务正是如此。
sc stop dnscache && sc start dnscache
sc queryex dnscache
tasklist /svc /fi “services eq dnscache”
Dnscache服务已经独占一个svchost.exe。
还原时,在NetworkService组中恢复DNSCache,删除TempGrp键值、子键,最后执行
sc config dnscache binpath= “C:\Windows\system32\svchost.exe -k NetworkService”
sc qc dnscache
这是官方推荐套路。
6.2) Changing the Service Type
可用如下命令让Dnscache服务独占一个svchost.exe
sc config dnscache type= own
sc stop dnscache && sc start dnscache
sc queryex dnscache
tasklist /svc /fi “services eq dnscache”
外在效果同TempGrp方案。但官方文档里说这样干会改变服务行为,并不推荐。个人觉得不妨一试,毕竟最简捷。type可选值有
type=
恢复操作
sc config dnscache type= share
6.3) Duplicating the SvcHost Binary
sc stop dnscache
copy C:\Windows\system32\svchost.exe X:\temp\svchost2.exe
sc config dnscache binpath= “X:\temp\svchost2.exe -k NetworkService”
sc qc dnscache
sc start dnscache
sc queryex dnscache
tasklist /svc /fi “services eq dnscache”
这种方案太直白了,无需解释。但官方文档里说这样干会改变服务行为,并不推荐。
恢复操作
sc stop dnscache
sc config dnscache binpath= “C:\Windows\system32\svchost.exe -k NetworkService”
sc qc dnscache
sc start dnscache
sc queryex dnscache
tasklist /svc /fi “services eq dnscache”
6.4) 杂议
前述三种服务隔离方案任选其一即可,官方推荐第一种,我觉得第二种挺好的。[5]的作者同时用到官方并不推荐的后两种服务隔离方案,没必要同时用。
7) Windows 2000比较特殊
前面说的是Win10,Windows 2000比较特殊,参[4]。
When we connect through Terminal Services, we are in a different Window
Station than the services, so we can’t attach to their processes. On
Windows 2003, we can cross the barrier between WinStations.
[4]演示了一些特别技巧处理此问题,包括remote.exe的使用。
8) 获取服务进程PID
一般用Process Explorer找,命令行多用这几种
tasklist /svc /fi “services eq dnscache”
sc queryex dnscache | findstr PID
都是系统自带工具。
参考资源
[1] Debugging a Service – [2021-01-08]
https://support.microsoft.com/kb/824344/en-us
https://docs.microsoft.com/en-US/windows/win32/services/debugging-a-service
DebugBreak function (debugapi.h)
https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-debugbreak
Debugging a Service Application – [2020-12-08]
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-a-service-application
(就是windbg帮助)
[2] A slow service does not start due to time-out error in Windows – [2021-09-24]
https://support.microsoft.com/kb/922918/en-us
https://docs.microsoft.com/en-US/troubleshoot/windows-server/system-management-components/service-not-start-events-7000-7011-time-out-error
[3] Running a Program in a Debugger – [2021-06-17]
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/running-a-program-in-a-debugger
(有gflags的图示)
[4] How to debug Windows services with Windbg – Alex (Alejandro Campos Magencio) [2008-08-19]
https://docs.microsoft.com/en-us/archive/blogs/alejacma/how-to-debug-windows-services-with-windbg
https://www.sysadmins.lv/retired-msft-blogs/alejacma/how-to-debug-windows-services-with-windbg.aspx
(现存最早的有效示例,remote.exe示例)
[5] HOWTO Debug a Windows Service Using windbg – sam [2010-08-03]
https://samscode.blogspot.com/2010/08/howto-debug-windows-service-using.html
(-server npipe:pipe=service_name_debug)
(sc config service_name type= own)
[6] How to debug a Windows service – Julien Crozon [2010-10-14]
https://bugslasher.net/2010/10/14/how-to-debug-a-windows-service/
(有gflags的图示,提到调试services.exe创建的子进程)
How to debug a process as soon as it starts with WinDbg or Visual Studio 2010 – Julien Crozon [2011-03-26]
https://bugslasher.net/2011/03/26/how-to-debug-a-process-as-soon-as-it-starts-with-windbg-or-visual-studio-2010/
[7] Debugging Windows services – Vetle kland [2019-01-25]
https://bordplate.no/blog/en/post/debugging-a-windows-service/
(有gflags的图示,作者未处理ServicesPipeTimeout)
[8] Debugging a Windows Service – Marc Durdin [2020-09-17]
https://marc.durdin.net/2020/09/debugging-a-windows-service/
(有gflags的命令行)
版权声明
本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。