wenmo8 发布的文章

正在悠哉,突然支持的同事过来说,某个用户软件启动不了了。详细情况是:由于出现某些问题,支持同事给这个客户重装了软件,然后就启动不了了,后来把安装目录改了名字,就能运行了。虽然客户能用了,但我很不理解为什么改了个目录名就能运行呢。于是恢复现场,重现故障,不管37二十一,抓个dmp先。

用windbg打开dmp

Windows 7 Version 7601 (Service Pack 1) MP (8 procs) Free x86 compatible
Product: WinNt, suite: SingleUserTS
Machine Name:
Debug session time: Tue Sep  1 14:42:17.000 2020 (UTC + 8:00)
System Uptime: 0 days 0:09:59.840
Process Uptime: 0 days 0:00:05.000
................................................................
...............................................................
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(202c.1094): Unknown exception - code c0000374 (first/second chance not available)
eax=00000000 ebx=00000000 ecx=7fffffff edx=00000000 esi=02630000 edi=0000202c
eip=7708f8d1 esp=0020e864 ebp=0020e8e8 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
ntdll!NtWaitForSingleObject+0x15:
7708f8d1 83c404          add     esp,4

可知,在id=1094的线程发生了c0000374(STATUS_HEAP_CORRUPTION ) 异常。

查看下栈,输入kv

0:000> kv
 # ChildEBP RetAddr  Args to Child              
00 0020e864 77118897 00000100 00000001 00000000 ntdll!NtWaitForSingleObject+0x15 (FPO: [3,0,0])
01 0020e8e8 771189c5 0020ea88 0020ead8 00000000 ntdll!RtlReportExceptionEx+0x14b (FPO: [Non-Fpo])
02 0020e940 7713ea7e 0020ea88 0020ead8 00000000 ntdll!RtlReportException+0x86 (FPO: [Non-Fpo])
03 0020e954 7713eafb c0000374 0020e988 770e4fb4 ntdll!RtlpTerminateFailureFilter+0x14 (FPO: [Non-Fpo])
04 0020e960 770e4fb4 00000000 0020efb4 7709d100 ntdll!RtlReportCriticalFailure+0x67 (FPO: [SEH])
05 0020e974 770e4e59 00000000 00000000 00000000 ntdll!_EH4_CallFilterFunc+0x12 (FPO: [Uses EBP] [0,0,4])
06 0020e99c 770d34a1 fffffffe 0020efa4 0020ead8 ntdll!_except_handler4+0x8e (FPO: [Non-Fpo])
07 0020e9c0 770d3473 0020ea88 0020efa4 0020ead8 ntdll!ExecuteHandler2+0x26 (FPO: [Uses EBP] [5,3,1])
08 0020e9e4 770d3414 0020ea88 0020efa4 0020ead8 ntdll!ExecuteHandler+0x24 (FPO: [5,0,3])
09 0020ea70 77080133 0020ea88 0020ead8 0020ea88 ntdll!RtlDispatchException+0x127 (FPO: [Non-Fpo])
0a 0020ea70 7713eaeb 0020ea88 0020ead8 0020ea88 ntdll!KiUserExceptionDispatcher+0xf (FPO: [2,0,0]) (CONTEXT @ 0020ead8)
0b 0020efb4 7713f9f1 c0000374 77174270 0020eff8 ntdll!RtlReportCriticalFailure+0x57 (FPO: [Non-Fpo])
0c 0020efc4 7713fad1 00000002 773ec360 00000000 ntdll!RtlpReportHeapFailure+0x21 (FPO: [Non-Fpo])
0d 0020eff8 770ed97c 00000009 006b0000 007149e2 ntdll!RtlpLogHeapFailure+0xa1 (FPO: [Non-Fpo])
0e 0020f028 6dd431f7 006b0000 00000000 007149e2 ntdll!RtlFreeHeap+0x64 (FPO: [Non-Fpo])
0f 0020f03c 6dd5c6d4 007149e2 00000000 0071c978 apphelp!SdbFree+0x22 (FPO: [Non-Fpo])
10 0020f080 6dd4db99 006b1ff6 0071c978 0020f288 apphelp!SdbpBuildLayerInfo+0x3d9 (FPO: [Non-Fpo])
11 0020f144 6dd4c490 006b1ff6 0071c978 0020f288 apphelp!SdbTraceQueryResult+0xd6 (FPO: [Non-Fpo])
12 0020f260 6dd4c3be 006b1ff6 0071c978 0020f288 apphelp!SeiInit+0xcb (FPO: [Non-Fpo])
13 0020f454 770d2cae 0020f560 00070000 00000000 apphelp!SE_InstallBeforeInit+0x67 (FPO: [Non-Fpo])
14 0020f470 770d2cd0 00718b90 0020f560 00070000 ntdll!LdrpLoadShimEngine+0xdc (FPO: [Non-Fpo])
15 0020f5f8 770b9f31 0020f66c 77070000 773edad0 ntdll!LdrpInitializeProcess+0x137f (FPO: [Non-Fpo])
16 0020f648 770a9799 0020f66c 77070000 00000000 ntdll!_LdrpInitialize+0x78 (FPO: [Non-Fpo])
17 0020f658 00000000 0020f66c 77070000 00000000 ntdll!LdrInitializeThunk+0x10 (FPO: [Non-Fpo])
看来是根兼容性有关阿。栈根我之前遇到问题一样(参考<记一次因兼容性问题崩溃>)。

于是远程客户机设置兼容性,发现设置过兼容性,但不行。于是我打开注册表HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers,发现里面有很多个关于我们程序设置项,先手动删掉这些项。在双击程序,成功跑起来了。

到了这里,我又有点迷惑了,之前是需要设置兼容,为什么这次又要删掉兼容的设置项呢,看来需要研究下,因为这是个问题,我还不懂。有知道的朋友也可以直接告诉我。

 

为了开始调试工作,我想向您提供一个工具列表。

以下工具是“Debugging Tools for Windows”的一部分–您肯定需要这些工具:

· windbg

· cdb

· ntsd

· tlist

· gflags

· adplus

· UMDH

· symcheck

Sysinternals提供了一些我们需要的优秀工具:

· Process Explorer

· Process Monitor

· Regmon

· Filemon

· DbgView

· Handle.exe

· Tcpview

· LiveKD

· AutoRuns

· WinObj

“MPS Reports”(MPSRPT_SETUPPerf.EXE)中包含许多工具,但我在这里专门列出Checksym

· Checksym

“WindowsServer2003ResourceKitTools”是另一个很棒的工具集。

桌面堆可能不是你花很多时间考虑的事情,这是件好事。但是,有时您可能会遇到由于桌面堆耗尽而导致的问题,然后了解此资源会有所帮助。让我先说一下,在Vista中,内核地址空间的情况发生了显著的变化,而我今天所说的大部分内容并不适用于Vista。

我想提供一些关于桌面堆的后续信息。在第一篇文章中,我没有讨论64位Windows、3GB或Vista上与桌面堆相关的内存范围的大小。所以,不用再多说了,下面是各种平台上的相关大小。

Windows XP (32-bit)

· 48 MB = SessionViewSize (default registry value, set for XP Professional, x86)

· 20 MB = SessionViewSize (if no registry value is defined)

· 3072 KB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 512 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 128 KB = Winlogon desktop heap size

· 64 KB = Disconnect desktop heap size

Windows Server 2003 (32-bit)

· 48 MB = SessionViewSize (default registry value)

· 20 MB = SessionViewSize (if no registry value is defined; this is the default for Terminal Servers)

· 3072 KB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 512 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 128 KB = Winlogon desktop heap size

· 64 KB = Disconnect desktop heap size

Windows Server 2003 booted with 3GB (32-bit)

· 20 MB = SessionViewSize (registry value has no effect)

· 3072 KB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 512 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 128 KB = Winlogon desktop heap size

· 64 KB = Disconnect desktop heap size

在运行3GB时,您还可能看到堆大小减小。在初始化窗口管理器期间,尝试保留足够的会话视图空间,以容纳给定会话的预期桌面堆数。如果在SharedSection注册表值中指定的堆大小已增大,则保留会话视图空间的尝试可能会失败。当这种情况发生时,窗口管理器会回到桌面堆的一对“安全”大小(交互式为512KB,非交互式为128KB),并再次尝试保留会话空间,使用这些较小的数字。这可以确保即使注册表值对于20MB会话视图空间来说太大,系统仍然能够引导。

Windows Server 2003 (64-bit)

· 104 MB = SessionViewSize (if no registry value is defined; which is the default)

· 20 MB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 768 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 192 KB = Winlogon desktop heap size

· 96 KB = Disconnect desktop heap size

Windows Vista RTM (32-bit)

· Session View space is now a dynamic kernel address range. The SessionViewSize registry value is no longer used.

· 3072 KB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 512 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 128 KB = Winlogon desktop heap size

· 64 KB = Disconnect desktop heap size

Windows Vista (64-bit) and Windows Server 2008 (64-bit)

· Session View space is now a dynamic kernel address range. The SessionViewSize registry value is no longer used.

· 20 MB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 768 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 192 KB = Winlogon desktop heap size

· 96 KB = Disconnect desktop heap size

 

Windows Vista SP1 (32-bit) and Windows Server 2008 (32-bit)

· Session View space is now a dynamic kernel address range. The SessionViewSize registry value is no longer used.

· 12288 KB = Interactive desktop heap size (defined in the registry, SharedSection 2nd value)

· 512 KB = Non-interactive desktop heap size (defined in the registry, SharedSection 3nd value)

· 128 KB = Winlogon desktop heap size

· 64 KB = Disconnect desktop heap size

windowsvista引入了一个新的公共API函数:CreateDesktopEx,它允许调用者指定桌面堆的大小。
此外,GetUserObjectInformation现在包含一个新的标志,用于检索桌面堆大小(UOI_HEAPSIZE)。

 

什么是LPC

LPC(Local-Process-communicationandnotlocalprocedure-Calls)是一种在NT内核中实现的基于消息的高速通信机制。LPC可用于两个用户模式进程之间、用户模式进程与内核模式驱动程序之间或两个内核模式驱动程序之间的通信。一个例子是通过LPC通信的两个用户模式进程。像CSRSS.exe与SMSS.exe通信,在创建登录会话或任何与LSASS.exe。出于安全原因,通过lsa认证端口。用户模式进程与内核模式驱动程序通信的另一个例子是 KSecDD.sys司与LSASS.exe通信用于在读/写加密文件期间对EFS密钥进行加密和解密。
LPC使用两种不同的机制在客户端和服务器进程之间传递数据。它使用LPC消息缓冲区(对于小于304字节的数据),或者使用映射到客户机和服务器地址空间的共享内存部分(对于大于304字节的数据)。
除了用作在同一系统上运行的进程之间选择远程过程调用的协议外,LPC还用于整个系统,例如用于Win32应用程序与CSRSS.exe文件,安全参考监视器与LSASS的通信,WinLogon与LSASS的通信等。
LPC强制客户机进程和服务器进程之间的同步通信模型。Vista反对使用一种称为异步本地进程间通信(ALPC)的新机制来使用LPC。与LPC相比,ALPC有一个固有的优势,即从客户端到服务器的所有调用都是异步的,即客户端不需要阻塞/等待服务器响应消息。在Vista中,对lpcapis的旧应用程序调用会自动重定向到更新的alpcapi。

LPC APIs

LPC api是本机api,即它们在用户模式下通过NTDLL.dll在内核模式下NTOSKRNL.exe文件. lpcapis没有在Win32级别公开,因此Win32应用程序不能直接使用LPC工具。然而,在使用RPC时,Win32应用程序可以通过协议序列“ncalrpc”将LPC指定为其底层传输,从而间接地使用LPC。所有lpcapis都以单词“Port”结尾,这意味着LPC通信端点。

API

Description

NtCreatePort

Used by server to create a connection port

NtConnectPort

Used by client to connect to a connection port

NtListenPort

Used by server to listen for connection requests on the connection port.

NtAcceptConnectPort

Used by server to accept connection requests on the connection port

NtCompleteConnectPort

Used by server to complete the acceptance of a connection request

NtRequestPort

Used to send a datagram message that does not have a reply

NtRequestWaitReplyPort

Used to send a message and wait for a reply

NtReplyPort

Used to send a reply to a particular message

NtReplyWaitReplyPort

Used to send a reply to a particular message and wait for a reply to a previous message

NtReplyWaitReceivePort

Used by server to send a reply to the client and wait to receive a message from the client

NtImpersonateClientOfPort

Used by server thread to temporarily borrow the security context of a client thread

下图说明了LPC服务器进程侦听来自潜在客户端的连接请求所采取的步骤,以及客户端连接到侦听服务器所采取的步骤。

 

 

                              LPC客户机-服务器连接建立顺序

注意:许多服务器进程使用NtReplyWaitReceivePort()API而不是NtListenPort()。NtListenPort()除去连接请求之外的所有LPC消息。因此NtListenPort()只能用于第一个连接。对于以后的连接请求,使用NtReplyWaitReceivePort()。

下图说明了LPC客户机向已建立连接的LPC服务器发送请求所采取的步骤,以及服务器响应消息所采取的步骤。

 

 

                            客户端-服务器数据传输序列

 

LPC Data Structures

LPC Port Data Structure

LPC Port被称为端口。LPC实现使用相同的端口结构来表示各种类型的端口。LPC使用的端口是服务器连接端口,这些端口是由服务器进程创建的用于接受来自客户端的传入连接的命名端口。客户机通信端口由客户机进程创建以连接到服务器进程和服务器进程创建的服务器通信端口。

 

 

                   LPC端口类型及其关系

LPCP_PORT_OBJECT是LPC用来表示LPC端口的内部数据结构。LPCP_PORT_对象是从带有标记“PORT”的分页池中分配的。

kd> dt nt!_LPCP_PORT_OBJECT+0x000ConnectionPort : Ptr32 _LPCP_PORT_OBJECT+0x004ConnectedPort : Ptr32 _LPCP_PORT_OBJECT+0x008MsgQueue : _LPCP_PORT_QUEUE+0x018Creator : _CLIENT_ID+0x020ClientSectionBase : Ptr32 Void+0x024ServerSectionBase : Ptr32 Void+0x028PortContext : Ptr32 Void+0x02cClientThread : Ptr32 _ETHREAD+0x030SecurityQos : _SECURITY_QUALITY_OF_SERVICE+0x03cStaticSecurity : _SECURITY_CLIENT_CONTEXT+0x078LpcReplyChainHead : _LIST_ENTRY+0x080LpcDataInfoChainHead : _LIST_ENTRY+0x088ServerProcess : Ptr32 _EPROCESS+0x088MappingProcess : Ptr32 _EPROCESS+0x08cMaxMessageLength : Uint2B+0x08eMaxConnectionInfoLength : Uint2B+0x090Flags : Uint4B+0x094 WaitEvent : _KEVENT