LPC (Local procedure calls)(二)内核调试扩展
我们将讨论调试器扩展,这些扩展允许您查看与LPC相关的问题。
LPC Kernel Debugger Extensions
Command |
Description |
!lpc |
Display the list and description of all the !lpc commands |
!lpc message [MessageId] |
Display the message with a given ID and all related information by attempting to match the given Message ID to the EHTREAD->LpcReceivedMessageId and to the ETHREAD->LpcReplyMessageId of all threads in the system. If the MessageId parameter is omitted then it attempts to display all the outstanding messages in the system by searching for the tag ‘LpcM’ in the pools. |
!lpc port [PortAddress] |
Displays port information. If a server connection port address is specified then only information about that port is displayed. If either a client or server communication port is specified it prints information about the specified communication port, the peer communication port and the server connection port. If the PortAddress parameter is omitted then it attempts to walk the list of all objects of type “Port” and “WaitablePort” and display them. Note that for this feature to work the GFlags option “+otl” i.e. “Maintain a list of objects for each type” must be enabled. |
!lpc scan PortAddress |
Displays port information. It attempts to walk the list of all objects of type “Port” and “WaitablePort” and display the one matching the specified port address. Note that for this feature to work the GFlags option “+otl” i.e. “Maintain a list of objects for each type” must be enabled. |
!lpc thread [ThreadAddr] |
If ThreadAddr is specified it walks the list of threads in the ETHREAD-> LpcReplyChain to locate the list head i.e. a “Port” or “WaitablePort” object on which the thread is waiting for a reply. If the ThreadAddr parameter is omitted then it attempts to find all LPC server threads by looking for threads with a non-NULL EHTREAD->LpcReceivedMessageId and all client threads by looking for threads with a non-NULL ETHREAD->LpcReplyMessageId and displays them. |
!lpc PoolSearch |
Toggles a setting that controls whether the “lpc message” command will search for LPC message tag (‘LpcM’) in the kernel pools or not. |
LPC Kernel Debugger Extension Usage
来自调用堆栈的LPC连接端口信息
在LPC数据传输或LPC连接上阻塞的任何客户端或服务器线程的调用堆栈上,将有一个包含函数NtRequestWaitReplyPort()或NtReplyWaitReceivePortEx()之一的帧。其中任何一个函数的第一个参数是它们被阻塞的端口的句柄。
kd> !thread 810de2a8
THREAD 810de2a8 Cid 01dc.01f4 Teb: 7ffde000 Win32Thread:00000000 WAIT: (WrLpcReceive) UserMode Non-Alertable81131188 Semaphore Limit 0x7fffffff810de398 NotificationTimer
Not impersonating
DeviceMap e196c460
Owning Process 810ddda0 Image: rpclpcs.exe
Wait Start TickCount64666666 Ticks: 402 (0:00:00:04.025)
Context Switch Count2UserTime00:00:00.000KernelTime00:00:00.000Win32 Start Address0x77e76bf0Start Address0x7c810856Stack Init f8e28000 Current f8e27c4c Base f8e28000 Limit f8e25000 Call0Priority8 BasePriority 8 PriorityDecrement 0 DecrementCount 0ChildEBP RetAddr Args to Child
f8e27c64 804dc6a6 810de318 810de2a8 804dc6f2 nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4])
f8e27c70 804dc6f2 e1084108 8055a540 e1084108 nt!KiSwapThread+0x46 (FPO: [0,0,0])
f8e27c98 8056a50a00000001 00000010 00000001 nt!KeWaitForSingleObject+0x1c2 (FPO: [Non-Fpo])
f8e27d48 804df06b 000007c4 002bff7000000000 nt!NtReplyWaitReceivePortEx+0x3dc (FPO: [Non-Fpo])
f8e27d48 7c90eb94 000007c4 002bff7000000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f8e27d64)
002bff8000000000 00000000 00000000 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
kd> !handle 7c4 3810ddda0
processor number0, process 810ddda0
PROCESS 810ddda0 SessionId:0Cid: 01dc Peb: 7ffd9000 ParentCid: 01b4
DirBase: 058cd000 ObjectTable: e1a13278 HandleCount:18.
Image: rpclpcs.exe
Handle table at e107d000 with18 Entries inuse
07c4: Object: e1084108 GrantedAccess: 001f0001 Entry: e107df88
Object: e1084108 Type: (812b5c80) Port
ObjectHeader: e10840f0 (old version)
HandleCount:1 PointerCount: 4Directory Object: e14c72c8 Name: rpclpc
kd> !lpc port e1084108
Server connection port e1084108 Name: rpclpc
Handles:1 References: 4Server process : 810ddda0 (rpclpcs.exe)
Queue semaphore :81131188Semaphore state0 (0x0)
The message queue is empty
The LpcDataInfoChainHead queue is empty
LPC Messages that are waiting to be picked up by the server thread
MBR反汇编
关于MBR的反汇编,我想花点时间向您展示一下快速而肮脏的方法。
首先,使用低级扇区编辑器(如Microsoft资源工具包实用程序DiskProbe)将MBR转储到文件中。保存文件后,启动一个程序(如记事本)并使用Windbg(Windows调试器)附加到它。
接下来,找到一个有效但未占用的内存范围(默认堆是一个很好的候选者)。内存范围至少需要512(0x200)字节。例如,我在这里找到了我的:
000120a0 00000000 00000000 00000000 00000000000120b000000000 00000000 00000000 00000000000120c000000000 00000000 00000000 00000000000120d000000000 00000000 00000000 00000000000120e000000000 00000000 00000000 00000000000120f000000000 00000000 00000000 00000000 00012100 00000000 00000000 00000000 00000000 00012110 00000000 00000000 00000000 00000000 00012120 00000000 00000000 00000000 00000000...
非分页池的消耗
我最近在处理一个问题,服务器在几天内耗尽了NonPagedPool。通常,我们只需要使用像PoolMon这样的工具来识别有问题的pool标记,然后使用本文中的方法找到使用该pool标记的驱动程序。然而,让这个案例有趣的是pool标记,而且我们无法使用常规方法识别驱动程序。你一会儿就会明白我的意思了。支持给我提供了服务器处于状态时的内核转储,这就是我发现的。
让我们先看看虚拟内存的使用情况:
2: kd> !vm*** Virtual Memory Usage ***Physical Memory:851420 ( 3405680Kb)
Page File: \??\C:\pagefile.sys
Current:3584000 Kb Free Space: 3568552Kb
Minimum:3584000 Kb Maximum: 3584000Kb
Available Pages:573277 ( 2293108Kb)
ResAvail Pages:800628 ( 3202512Kb)
Locked IO Pages:1067 ( 4268Kb)
Free System PTEs:25102 ( 100408Kb)
Free NP PTEs:335 ( 1340Kb)
Free Special NP:0 ( 0Kb)
Modified Pages:22 ( 88Kb)
Modified PF Pages:22 ( 88Kb)
NonPagedPool Usage:31369 ( 125476Kb) ß Very high
NonPagedPool Max:31986 ( 127944Kb)********** Excessive NonPaged Pool Usage *****PagedPool0 Usage: 19071 ( 76284Kb)
PagedPool1 Usage: 735 ( 2940Kb)
PagedPool2 Usage: 747 ( 2988Kb)
PagedPool3 Usage: 720 ( 2880Kb)
PagedPool4 Usage: 746 ( 2984Kb)
PagedPool Usage:22019 ( 88076Kb)
PagedPool Maximum:38912 ( 155648Kb)********** 3 pool allocations have failed **********
Kernel Stack Overflows
今天我想谈谈一个常见的错误,我们在日常工作钟许多案例中都看到了这一点。它涉及到驱动程序占用内核堆栈上的过多空间,从而导致内核堆栈溢出,然后将通过以下错误检查之一使系统崩溃:
1. STOP 0x7F: UNEXPECTED_KERNEL_MODE_TRAP当参数1设置为EXCEPTION_DOUBLE_FAULT时,这是由于覆盖内核堆栈的末尾而导致的。
2. STOP 0x1E: KMODE_EXCEPTION_NOT_HANDLED, 0x7E: SYSTEM_THREAD_EXCEPTION_NOT_HANDLED, or 0x8E: KERNEL_MODE_EXCEPTION_NOT_HANDLED, 异常代码为STATUS_ACCESS_VIOLATION,表示内存访问冲突。
3. STOP 0x2B: PANIC_STACK_SWITCH, 这通常发生在内核模式驱动程序使用太多堆栈空间时。
内核堆栈概述
系统中的每个线程都分配有一个内核模式堆栈。运行在任何内核模式线程(无论是系统线程还是驱动程序创建的线程)上的代码都使用该线程的内核模式堆栈,除非该代码是DPC,在这种情况下,它在某些平台上使用处理器的DPC堆栈。堆栈负增长。这意味着堆栈的开始(底部)的地址高于堆栈的结束(顶部)。例如,让我们保持堆栈的开头是0x80f1000,这是堆栈指针(ESP)指向的位置。如果将一个DWORD值推送到堆栈上,它的地址将是0x80f0ffc。下一个DWORD值将存储在0x80f0ff8,以此类推,直到分配的堆栈的限制(顶部)。堆栈顶部以保护页为边界,以检测溢出。
内核模式堆栈的大小因不同的硬件平台而异。例如:
- 在基于x86的平台上,内核模式堆栈是12K。
- 在基于x64的平台上,内核模式堆栈为24K(基于x64的平台包括使用AMD64体系结构的处理器和使用Intel EM64T体系结构的处理器的系统)。
- 在基于安腾的平台上,内核模式堆栈是32K,有一个32K后备存储。(如果处理器的寄存器文件中的寄存器用完,它将使用后备存储器来保存寄存器的内容,直到分配函数返回为止。这不会直接影响堆栈分配,但操作系统在基于安腾的平台上使用的寄存器比在其他平台上使用的寄存器多,这使得驱动程序可以使用的堆栈相对更多。)
如何与转储文件建立丰富多彩的关系
我每天都看很多转储文件。在这种情况下,我喜欢充分利用windbg可定制的外观和感觉。实际上,我在DMP文件和CMD文件之间有一个关联设置,每当我双击一个转储文件时,这个文件就会加载我自定义的颜色工作区。我喜欢有彩色源代码和调试命令窗口输出的黑色背景。
下面是我典型的调试会话的快照。
下面告诉你的设置方法。