2024年4月21日发(作者:)

DbgPrint 函数流程分析 by 小喂 ‐ 1 ‐

DbgPrint 函数流程分析

前言

Windows下编写内核驱动时经常用到DbgPrint函数输出一些调试信息,用来辅助调试。当正在用WinDbg内核调

试时,调试信息会输出到WinDbg中。或者利用一些辅助工具也能看到输出的调试信息,比如Sysinternals公司的

DebugView工具。本文分析了Vista系统上DbgPrint系列函数的执行流程,并揭示了DebugView工具的实现原理。

DbgPrint函数流程

先看一下WDK中DbgPrint函数的原型:

ULONG

DbgPrint (

IN PCHAR Format,

...

);

和printf的参数一样,可以格式化字符串。

.text:0049E123 ; ULONG DbgPrint(PCH Format,...)

.text:0049E123 public _DbgPrint

.text:0049E123 _DbgPrint proc near ; CODE XREF: sub_4046B2+11↑p

.text:0049E123

.text:0049E123 Format = dword ptr 8

.text:0049E123 arglist = byte ptr 0Ch

.text:0049E123

.text:0049E123 mov edi, edi

.text:0049E125 push ebp

.text:0049E126 mov ebp, esp

.text:0049E128 push TRUE

.text:0049E12A lea eax, [ebp+arglist]

.text:0049E12D push eax

.text:0049E12E push [ebp+Format]

.text:0049E131 mov ecx, offset ??_C@_00CNPNBAHC@?$AA@FNODOBFM@

.text:0049E136 push 3 ; DPFLTR_INFO_LEVEL = 3

.text:0049E138 push 65h ; DPFLTR_DEFAULT_ID = 101 = 0x65

.text:0049E13A call vDbgPrintExWithPrefixInternal(x,x,x,x,x,x)

.text:0049E13F pop ebp

.text:0049E140 retn

.text:0049E140 _DbgPrint endp

从反汇编代码来看,DbgPrint函数很简单,传递参数直接调用vDbgPrintExWithPrefixInternal函数。传递的

ComponentId为DPFLTR_DEFAULT_ID,Level为DPFLTR_INFO_LEVEL。查看DbgPrintEx函数的文档可以知道这两个参数的

意义。

DbgPrint 函数流程分析 by 小喂 ‐ 2 ‐

.text:0046EBF4 __stdcall vDbgPrintExWithPrefixInternal(x, x, x, x, x, x) proc near

.text:0046EBF4 ; CODE XREF: _DbgPrintEx+19↑p

.text:0046EC11

.text:0046EC17 push [ebp+ulLevel]

.text:0046EC1A push [ebp+ulComponentId]

.text:0046EC1D call NtQueryDebugFilterState(x,x)

.text:0046EC22 test eax, eax

.text:0046EC24 jnz short loc_46EC2D

.text:0046EC26

.text:0046EC26 loc_46EC26:

.text:0046EC26 xor eax, eax

.text:0046EC28 jmp _exit

vDbgPrintExWithPrefixInternal函数首先调用NtQueryDebugFilterState函数检查ComponentId和Level值判断当前输

出是否需要屏蔽。DbgPrint传入的值分别是65h和3, 65h定为的nt!Kd_DEFAULT_Mask的值和3被移位后的8比较,

从而确定此次输出是否需要屏蔽。所以Vista系统上用WinDbg内核调试时缺省看不到DbgPrint输出的调试字符串,可

以用ed nt!Kd_DEFAULT_Mask 0x8命令或者修改注册表打开DbgPrint调试输出。

.text:0046EBA8 __stdcall NtQueryDebugFilterState(x, x) proc near

.text:0046EBA8

.text:0046EBA8 ulComponentId = dword ptr 8

.text:0046EBA8 ulLevel = dword ptr 0Ch

.text:0046EBA8

.text:0046EBA8 mov edi, edi

.text:0046EBAA push ebp

.text:0046EBAB mov ebp, esp

.text:0046EBC0 mov ecx, [ebp+ulLevel]

.text:0046EBCC xor eax, eax

.text:0046EBCE inc eax

.text:0046EBCF shl eax, cl

.text:0046EBD1 test _Kd_WIN2000_Mask, eax

.text:0046EBD7 jnz short loc_46EBE8

.text:0046EBD9 mov ecx, _KdComponentTable[edx*4]

.text:0046EBE0 test [ecx], eax

.text:0046EBE2 jnz short loc_46EBE8

.text:0046EBE4 xor eax, eax

.text:0046EBE6 jmp short loc_46EBEB