1:背景
1. 讲述你的故事前几天,一个朋友在微信上找到我,说他分析了这个软件后,不知道怎么回事。他让我看一下。当然,并非所有转储都可以处理。既然转储已经可用,我只能尽力帮助其他人缩小问题的范围。分析。
2:WinDbg分析
1、为什么不同类型的程序解决问题的方式不同?我的一个朋友也说,既然是表单程序,就关注主线程,用k命令。
0
:000
k25
# 子SP RetAddr 调用站点
00
00000000
`007f
c8d8 00007f
fd`87439b
13 ntdll!NtWaitForAlertByThreadId+0x14
01
00000000
`007f
c8e0 00007f
fd`87439
a06 ntdll!RtlpWaitOnAddressWithTimeout+0x43
02
00000000
`007f
c910 00007f
FD`8743987
d ntdll!RtlpWaitOnAddress+0xae
03
00000000
`007f
c980 00007f
fd`87435f
dc ntdll!RtlpWaitOnCriticalSection+0xd9
04
00000000
`007f
c9f0 00007f
fd`87435
ef0 ntdll!RtlpEnterCriticalSectionContished+0xdc
05
00000000
`007f
ca20 00007f
FD`536839
ea ntdll!RtlEnterCriticalSection+0x40
06
00000000
`007f
ca50 00007f
FD`5368470
AcLayers!NS_VirtualRegistry:CRegLock:CRegLock+0x1a
07
00000000
`007f
ca90 00007f
fd`536726
d2 AcLayers!NS_VirtualRegistry:APIHook_RegOpenKeyExW+0x2a
08
00000000
`007f
CB10 00007f
fd`778e550
b AcLayers!NS_WRPMitigation:APIHook_RegOpenKeyExW+0x42
09
00000000
`007f
CB60 00007f
fd`778e5437
xxx!GetCodePageForFont+0xa7
0
00000000
`007f
CC90 00007f
fd`778e5296
xxx!CToolTipsMgr: 新字体+0x113
0b
00000000
`007f
cda0 00007f
fd`778e18
f9 xxx!CToolTipsMgr:LoadTheme+0xb2
0
c00000000
`007f
cdd0 00007f
fd`84b
9ca66 xxx!CToolTipsMgr:s_ToolTipsWndProc+0x1b9
0
d 00000000
`007f
ce10 00007f
fd`84b
9c34b user32!UserCallWinProcCheckWow+0x266
0
00000000
`007f
cf90 00007f
fd`4f
36b1cc user32!CallWindowProcW+0x8b
0f
00000000
`007f
CFE0 00007f
fd`4f
39ccac System_Windows_Forms_ni!System.Windows.Forms.NativeWindow.DefWndProc+0x9c
十
00000000
`007f
d090 00007f
fd`4f
39cc05 System_Windows_Forms_ni!System.Windows.Forms.ToolTip.WndProc+0x9c
11
00000000
`007f
d260 00007f
fd`4f
36a3a3 System_Windows_Forms_ni!System.Windows.Forms.ToolTip.ToolTipNativeWindow.WndProc+0x15
12
00000000
`007f
d290 00007f
fd`4f
9e1161 System_Windows_Forms_ni!System.Windows.Forms.NativeWindow.Callback+0xc3
13
00000000
`007f
d330 00007f
FD`52
c8222e System_Windows_Forms_ni+0x8d1161
14
00000000
`007f
d3a0 00007f
fd`84b
9ca66 clr!UMThunkStub+0x6e
15
00000000
`007f
d430 00007f
fd`84b
9c78c user32!UserCallWinProcCheckWow+0x266
16
00000000
`007f
d5b0 00007f
fd`84b
b3b32 user32!DispatchClientMessage+0x9c
17 号
00000000
`007f
d610 00007f
FD`874
c22c4 user32!__fnINLPCREATESTRUCT+0xa2
18
00000000
`007f
d670 00007f
FD`836
a1f24 ntdll!KiUserCallbackDispatcherContinue19
00000000
`007f
d7e8 00007f
fd`84b
a15df win32u!NtUserCreateWindowEx+0x14
1
00000000
`007f
d7f0 00007f
fd`84b
a11d4 user32!VerNtUserCreateWindowEx+0x20f
1b
00000000
`007f
db80 00007f
fd`84b
a1012 user32!CreateWindowInternal+0x1b4
1
c 00000000
`007f
dce0 00007f
fd`4f
3e8098 user32!CreateWindowExW+0x82
1
d 00000000
`007f
dd70 00007f
fd`4f
3696f0系统_Windows_Forms_ni+0x2d8098
.从六角图中我们可以看到问题是主线程卡在NtWaitForAlertByThreadId。 接下来仔细解读线程堆栈。
发送客户端消息
该方法表示其他线程通过Invoke发送的信息已经从队列中取出并正在处理。
加载主题
该方法表明正在使用主线程更新表单样式。
APIHook_RegOpenKeyExW
首先,我们来谈谈AcLayers.dll。技术术语是垫片。有关详细信息,请参阅《软件调试》。这主要用于解决系统级兼容性问题。查询注册表时的操作。
在非托管代码中,锁定通常使用临界区来实现。那么谁持有锁等待的临界区呢?
2. 谁持有临界区的锁?如果想要获取锁持有信息,可以使用!cs -l 或!locks,但要注意,它们在实际转储分析过程中可能不准确。唯一的方法就是从线程堆栈中提取它。实际提取的方法是找到ntdll!RtlEnterCriticalSection方法的第一个参数。方法签名是:
VOID RtlEnterCriticalSection
(PRTL_CRITICAL_SECTION 临界区
)
; 现在反汇编00007ffd536839ea中的代码,看看rcx寄存器是如何传递的。
0
:000
UB 00007f
FD`536839
eaAcLayers!NS_VirtualRegistry:OPENKEY:AddEnumEntries+0x11a
:00007f
FD`536839
ce cc 整数
3
00007f
FD`536839
cf cc 整数
3
AcLayers!NS_VirtualRegistry:CRegLock:CRegLock:00007f
FD`536839
d0 48895
c2408 mov qword ptr [rsp+8
],rbx00007f
FD`536839
d5 57
请按rdi00007f
FD`536839
d6 4883
ec30 子RSP,30
h00007f
FD`536839
达488b
f9 mov rdi,rcx00007f
FD`536839
dd488
d0d4c7f0300 lea rcx,[AcLayers!NS_VirtualRegistry:csRegCriticalSection(00007f)
fd`536b
b930)]00007f
fd`536839e4
ff15ae660100 调用qword ptr [AcLayers!_imp_EnterCriticalSection (00007f)
FD`5369
a098)]从六芒星上看,这个rcx就是全局变量AcLayers!NS_VirtualRegistry:csRegCriticalSection。 然后观察谁拿着它。
0
:000
!cs AcLayers!NS_VirtualRegistry:csRegCriticalSection——————————————————– — —–关键部分=0x00007ffd536bb930
(AcLayers!NS_VirtualRegistry:csRegCriticalSection+0x0
) 调试信息=0x000000001c4e58e0
LOCKED 锁定计数=0x2
服务员沃肯=NoOwningThread=0x0000000000001d20
递归数=0x1
锁定信号量=0xFFFFFFFF
自旋计数=0x00000000020007ce
这也是吉祥卦。可以看到当前线程是1d20。那么这个线程在做什么呢?
3. 1d20 让我们更进一步,查看线程堆栈,看看为什么线程持有锁而不释放它们。
0
:000
~~[1
d20]sntdll!NtDelayExecution+0x14
:00007f
fd`874b
ec14 c3 ret0
:028
kL# 子SP RetAddr 调用站点
00
00000000
`33
CCD948 00007f
FD`83955381
ntdll!NtDelayExecution+0x14
01
00000000
`33
CCD950 00007f
fd`6
d4a2361 基于内核!SleepEx+0xa1
02
00000000
`33
ccd9f0 00007f
FD`8520
a75c 性能!CloseLagPerfData+0x21
03
00000000
`33
ccda30 00007f
fd`85209
ccd advapi32!CloseExtObjectLibrary+0xec
04
00000000
`33
CCDA90 00007f
FD`8396
dc6a advapi32!PerfRegCloseKey+0x15d
05
00000000
`33
ccdae0 00007f
fd`839715e6
KERNELBASE!BaseRegCloseKeyInternal+0x72
06
00000000
`33
ccdb10 00007f
FD`83935209
KERNELBASE!关闭预定义句柄+0x96
07
00000000
`33
ccdb40 00007f
fd`53685
基于d71 内核!RegCloseKey+0x149
08
00000000
`33
ccdba0 00007f
fd`53683
ae5 AcLayers!NS_VirtualRegistry:CVirtualRegistry:CloseKey+0xbd
09
00000000
`33
ccdbf0 00007f
FD`51
c7737e AcLayers!NS_VirtualRegistry:APIHook_RegCloseKey+0x25
0
00000000
`33
ccdc30 00007f
fd`51b
f4be2 mscorlib_ni+0x58737e
0b
00000000
`33
ccdce0 00007f
FD`513
c356a mscorlib_ni!Microsoft.Win32.RegistryKey.Dispose+0x72
0
c 00000000
`33
ccdd20 00007f
FD`513
c34b9 System_ni!System.Diagnostics.PerformanceCounterLib.GetStringTable+0x41a
.13
00000000
`33
CCE050 00007f
fd`513b
fe3c System_ni!System.Diagnostics.PerformanceCounter.ctor+0xd7
14
00000000
`33
cce0a0 00007f
fc`f45cb2ce System_ni!System.Diagnostics.PerformanceCounter.ctor+0x1c
15
00000000
`33
cce0d0 00007f
fc`f45cb14c0x00007ffc
`f45cb2ce16
00000000
`33
CCE120 00007f
fc`f45cb0230x00007ffc
`f45cb14c . 从六角星图来看,当使用CloseLagPerfData 方法关闭某些内容时,该线程似乎正在休眠并等待。您可以反汇编00007ffd6d4a2361处的代码并检查等待时间。
0
:028
UB 00007f
fd`6
d4a2361perfts!CloseLagPerfData+0x5
:00007f
fd`6
d4a2345 55
请按rbp00007f
fd`6
d4a2346 488b
ec mov rbp,rsp00007f
fd`6
d4a2349 4883
ec30 子RSP,30
h00007f
fd`6
d4a234d e8720e0000 呼叫性能!LagCounterManager: 清理(00007f)
fd`6
d4a31c4)00007f
fd`6
d4a2352 33
db 异或ebx, ebx00007f
fd`6
d4a2354 eb0b jmp perfts!CloseLagPerfData+0x21
(00007f
fd`6
d4a2361)00007f
fd`6
d4a2356 b964000000 mov ecx,64
h00007f
fd`6
d4a235b ff15c74e0000 调用qword ptr [perfts!_imp_Sleep (00007f)
fd`6
d4a7228)]. 从六卦mov ecx,64h,我们知道Sleep(100)毫秒。我没有时间详述,但我可以看出,上层柜台阶级无论如何都是罪魁祸首。性能计数器。学习一下4S店的工作原理,问问朋友是否可以避免调用PerformanceCounter类。这是屏幕截图:
删除后,我的朋友报告说问题消失了。
3:总结
奇怪的是,我最近发现了两个PerformanceCounter导致程序冻结的案例。我把我的经验留下来,希望以后少有人落入这个陷阱。
本文和图片来自网络,不代表火豚游戏立场,如若侵权请联系我们删除:https://www.huotun.com/game/670344.html