DbgPrint函数分析及DbgView使用.docx
- 文档编号:18519512
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:6
- 大小:18.60KB
DbgPrint函数分析及DbgView使用.docx
《DbgPrint函数分析及DbgView使用.docx》由会员分享,可在线阅读,更多相关《DbgPrint函数分析及DbgView使用.docx(6页珍藏版)》请在冰点文库上搜索。
DbgPrint函数分析及DbgView使用
DbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�21�0�2‐�0�2DbgPrint�0�2函数流程分析�0�2前言�0�2Windows下编写内核驱动时经常用到DbgPrint函数输出一些调试信息用来辅助调试。
当正在用WinDbg内核调试时调试信息会输出到WinDbg中。
或者利用一些辅助工具也能看到输出的调试信息比如Sysinternals公司的DebugView工具。
本文分析了Vista系统上DbgPrint系列函数的执行流程并揭示了DebugView工具的实现原理。
�0�2DbgPrint函数流程�0�2先看一下WDK中DbgPrint函数的原型�0�2�0�2ULONGDbgPrintINPCHARFormat...和printf的参数一样可以格式化字符串。
�0�2�0�2.text:
0049E123ULONGDbgPrintPCHFormat....text:
0049E123public_DbgPrint.text:
0049E123_DbgPrintprocnearCODEXREF:
sub_4046B211↑p.text:
0049E123.text:
0049E123Formatdwordptr8.text:
0049E123arglistbyteptr0Ch.text:
0049E123.text:
0049E123movediedi.text:
0049E125pushebp.text:
0049E126movebpesp.text:
0049E128pushTRUE.text:
0049E12Aleaeaxebparglist.text:
0049E12Dpusheax.text:
0049E12EpushebpFormat.text:
0049E131movecxoffset_C_00CNPNBAHCAAFNODOBFM.text:
0049E136push3DPFLTR_INFO_LEVEL3.text:
0049E138push65hDPFLTR_DEFAULT_ID1010x65.text:
0049E13AcallvDbgPrintExWithPrefixInternalxxxxxx.text:
0049E13Fpopebp.text:
0049E140retn.text:
0049E140_DbgPrintendp从反汇编代码来看DbgPrint函数很简单传递参数直接调用vDbgPrintExWithPrefixInternal函数。
传递的ComponentId为DPFLTR_DEFAULT_IDLevel为DPFLTR_INFO_LEVEL。
查看DbgPrintEx函数的文档可以知道这两个参数的意义。
�0�2DbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�22�0�2‐�0�2�0�2.text:
0046EBF4__stdcallvDbgPrintExWithPrefixInternalxxxxxxprocnear.text:
0046EBF4CODEXREF:
_DbgPrintEx19↑p.text:
0046EC11.text:
0046EC17pushebpulLevel.text:
0046EC1ApushebpulComponentId.text:
0046EC1DcallNtQueryDebugFilterStatexx.text:
0046EC22testeaxeax.text:
0046EC24jnzshortloc_46EC2D.text:
0046EC26.text:
0046EC26loc_46EC26:
.text:
0046EC26xoreaxeax.text:
0046EC28jmp_exit�0�2.text:
0046EBA8__stdcallNtQueryDebugFilterStatexxprocnear.text:
0046EBA8.text:
0046EBA8ulComponentIddwordptr8.text:
0046EBA8ulLeveldwordptr0Ch.text:
0046EBA8.text:
0046EBA8movediedi.text:
0046EBAApushebp.text:
0046EBABmovebpesp.text:
0046EBC0movecxebpulLevel.text:
0046EBCCxoreaxeax.text:
0046EBCEinceax.text:
0046EBCFshleaxcl.text:
0046EBD1test_Kd_WIN2000_Maskeax.text:
0046EBD7jnzshortloc_46EBE8.text:
0046EBD9movecx_KdComponentTableedx4.text:
0046EBE0testecxeax.text:
0046EBE2jnzshortloc_46EBE8.text:
0046EBE4xoreaxeax.text:
0046EBE6jmpshortloc_46EBEBvDbgPrintExWithPrefixInternal函数首先调用NtQueryDebugFilterState函数检查ComponentId和Level值判断当前输出是否需要屏蔽。
DbgPrint传入的值分别是65h和3�0�265h定为的ntKd_DEFAULT_Mask的值和3被移位后的8比较从而确定此次输出是否需要屏蔽。
所以Vista系统上用WinDbg内核调试时缺省看不到DbgPrint输出的调试字符串可以用ed�0�2ntKd_DEFAULT_Mask�0�20x8命令或者修改注册表打开DbgPrint调试输出。
�0�2DbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�23�0�2‐�0�2�0�2.text:
0046EC5DpushebpntStatus2cbDest.text:
0046EC63pushebppszDestpszDest.text:
0046EC69movecx512.text:
0046EC6Esubecxesi.text:
0046EC70leaediebpesiszBuffer.text:
0046EC77callRtlStringCbVPrintfAxxxx.text:
0046ECB2leaecxebpszBuffer.text:
0046ECB8movebpasBuffer.Bufferecx.text:
0046ECBEmovebpasBuffer.Lengthax.text:
0046ECC5cmp_KeBugCheckActive0.text:
0046ECCCjnzshortloc_46ED09.text:
0046ECCC.text:
0046ECCEmovesi_RtlpDebugPrintCallback.text:
0046ECD4testesiesi.text:
0046ECD6jzshortloc_46ED09.text:
0046ECD6.text:
0046ECD8callds:
KeGetCurrentIrql.text:
0046ECDEmovblal.text:
0046ECE0cmpblPROFILE_LEVEL.text:
0046ECE3jnbshortloc_46ECED.text:
0046ECE3.text:
0046ECE5movclPROFILE_LEVEL.text:
0046ECE7callds:
KfRaiseIrqlx.text:
0046ECED.text:
0046ECEDloc_46ECED:
.text:
0046ECEDpushebpulLevel.text:
0046ECF0pushebpulComponentId.text:
0046ECF3leaeaxebpasBuffer.text:
0046ECF9pusheax.text:
0046ECFAcallesiDbgPrintCallbackPANSI_STRINGpasBufferULONGulComponentIdULONGulLevel.text:
0046ECFCcmpblPROFILE_LEVEL.text:
0046ECFFjnbshortloc_46ED09.text:
0046ECFF.text:
0046ED01movclbl.text:
0046ED03callds:
KfLowerIrqlx如果此次输出不需要屏蔽vDbgPrintExWithPrefixInternal继续执行。
调用RtlStringCbVPrintfA函数格式化字符串再判断是否正在蓝屏过程中然后提高IRQL调用输出回调函数。
调试输出回调是Vista的新增功能XP中没有见到。
NTSTATUS�0�2DbgSetDebugPrintCallbackPDBGPRINT_CALLBACE�0�2pDbgCallback�0�2BOOLEAN�0�2bSet函数用来设置和取消回调函数只能设置一个函数函数地址保存在RtlpDebugPrintCallback内部变量中。
回调函数返回后降低IRQL。
�0�2DbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�24�0�2‐�0�2�0�2.text:
0046ED09movzxeaxebpasBuffer.Length.text:
0046ED10movebppszDesteax.text:
0046ED16moveaxebpasBuffer.Buffer.text:
0046ED1Cmovebpvar_234eax.text:
0046ED22pushedi.text:
0046ED23pushebx.text:
0046ED24moveax1eaxBREAKPOINT_PRINT .text:
0046ED29movecxebpvar_234ecxpszBuffer.text:
0046ED2FmovedxebppszDestedxulBufLength.text:
0046ED35movebxebpulComponentId.text:
0046ED38movediebpulLevel.text:
0046ED3Bint2DhInternalroutineforMSDOSIRET.text:
0046ED3Dint3TraptoDebuggervDbgPrintExWithPrefixInternal函数接着执行通过int2d调用调试服务把字符串输出到调试器。
int2d的服务例程为KiDebugService函数。
�0�2�0�2.text:
0044737C_KiDebugService:
DATAXREF:
INIT:
0070A35C↓o.text:
004473EAincdwordptrebp68h.text:
004473EAincdwordptrebp68h_KTRAP_FRAME.Eip.text:
004473EDmoveaxebp44h_KTRAP_FRAME.Eax.text:
004473F0movecxebp40h_KTRAP_FRAME.Ecx.text:
004473F3movedxebp3Ch_KTRAP_FRAME.Edx.text:
004473F6jmploc_447527�0�2.text:
00447527.text:
00447527loc_447527:
CODEXREF:
.text:
004473F6↑j.text:
00447527.text:
00447543movesiecx.text:
00447545movediedx.text:
00447547movedxeax.text:
00447549movebxebp68h_KTRAP_FRAME.Eip.text:
0044754Cdecebx.text:
0044754Dmovecx3.text:
00447552moveaxSTATUS_BREAKPOINT.text:
00447557callCommonDispatchException�0�2.text:
00446D70CommonDispatchExceptionprocnear.text:
00446D70.text:
00446D70stExceptionRecordEXCEPTION_RECORDptr-50h.text:
00446D70.text:
00446D70subesp50h.text:
00446D73movesp50hstExceptionRecord.ExceptionCodeeax.text:
00446D76xoreaxeax.text:
00446D78movesp50hstExceptionRecord.ExceptionFlagseax.text:
00446D7Cmovesp50hstExceptionRecord.ExceptionRecordeax.text:
00446D80movesp50hstExceptionRecord.ExceptionAddressebx.text:
00446D84movesp50hstExceptionRecord.NumberParametersecx.text:
00446D88cmpecx0DbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�25�0�2‐�0�2�0�2.text:
00446D8Bjzshortloc_446D99.text:
00446D8Dleaebxesp50hstExceptionRecord.ExceptionInformation.text:
00446D91movebxedx.text:
00446D93movebx4esi.text:
00446D96movebx8edi.text:
00446D99.text:
00446D99.text:
00446DA8moveaxebp6Ch_KTRAP_FRAME.SegCs.text:
00446DAB.text:
00446DABloc_446DAB:
CODEXREF:
CommonDispatchException36↑j.text:
00446DABandeax1.text:
00446DAEpush1char.text:
00446DB0pusheaxint.text:
00446DB1pushebpBugCheckParameter3.text:
00446DB2push0int.text:
00446DB4pushecxvoid.text:
00446DB5callKiDispatchExceptionxxxxxKiDebugService先构建一个陷阱帧KTRAP_FRAME然后设置参数调用CommonDispatchExceptionCommonDispatchException会构建一个异常纪录EXCEPTION_RECORD然后调用KiDispatchException函数走异常处理流程异常代码为STATUS_BREAKPOINT。
从int2d‐gtKiDebugService‐gtCommonDispatchException‐gtKiDispatchException这个流程一路看下来会发现int2d时提供的三个参数存放在异常纪录的ExceptionInformation数组里面分别是�0�2ExceptionInformation0表示BREAKPOINT_PRINT功能号。
ExceptionInformation1表示调试信息字符串地址。
ExceptionInformation2表示调试信息字符串长度。
进入KiDispatchException后的代码比较复杂当前只是分析DbgPrint的流程其他代码暂时不管只需要知道KiDispatchException会调用KiDebugRoutine把异常提交给内核调试引擎处理。
当处于内核调试时KiDebugRoutine指向KdpTrap函数没有调试时KiDebugRoutine指向KdpStub函数。
先来看看KdpStub函数。
�0�2�0�2.text:
0042A2DC__stdcallKdpStubxxxxxxprocnear.text:
0042A2DC.text:
0042A2DCTrapFramedwordptr8.text:
0042A2DCExceptionFramedwordptr0Ch.text:
0042A2DCExceptionRecorddwordptr10h.text:
0042A2DCContextRecorddwordptr14h.text:
0042A2DCPreviousModedwordptr18h.text:
0042A2DCbSecondChancedwordptr1Ch.text:
0042A2DC.text:
0042A2DCmovediedi.text:
0042A2DEpushebp.text:
0042A2DFmovebpesp.text:
0042A2E1pushebx.text:
0042A2E2pushesi.text:
0042A2E2.text:
0042A2E3movesiebpExceptionRecord.text:
0042A2E6xorebxebx.text:
0042A2E8cmpesiEXCEPTION_RECORD.ExceptionCodeSTATUS_BREAKPOINTDbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�26�0�2‐�0�2�0�2.text:
0042A2EEjnzshort_elseif.text:
0042A2EE.text:
0042A2F0cmpesiEXCEPTION_RECORD.NumberParametersebx.text:
0042A2F3jbeshort_elseif.text:
0042A2F3.text:
0042A2F5moveaxesiEXCEPTION_RECORD.ExceptionInformation.text:
0042A2F8cmpeaxBREAKPOINT_LOAD_SYMBOLS.text:
0042A2FBjzshortloc_42A30C.text:
0042A2FDcmpeaxBREAKPOINT_UNLOAD_SYMBOLS.text:
0042A300jzshortloc_42A30C.text:
0042A302cmpeaxBREAKPOINT_COMMAND_STRING.text:
0042A305jzshortloc_42A30C.text:
0042A307cmpeaxBREAKPOINT_PRINT .text:
0042A30Ajnzshort_elseif.text:
0042A30C.text:
0042A30CmoveaxebpContextRecord.text:
0042A30FinceaxCONTEXT._Eip.text:
0042A315moval1returnTRUE.text:
0042A317jmpshort_exitKdpStub先判断异常代码是不是STATUS_BREAKPOINTint3断点异常也是这个异常代码但第一个参数是BREAKPOINT_BREAK然后判断参数个数。
对于当前支持的四种调试服务包括输出调试字符串都是把eip加一跳过int2d后面带的int3指令然后从异常处理中返回继续执行。
�0�2当正在调试时KiDispatchException调用的就是KdpTrap函数。
�0�2�0�2PAGEKD:
006AB5EB__stdcallKdpTrapxxxxxxprocnearPAGEKD:
006AB6A1loc_6AB6A1:
CODEXREF:
KdpTrapxxxxxx3A↑jPAGEKD:
006AB6A1movedxebxCONTEXT._EbxPAGEKD:
006AB6A7leaecxebpbReturnPAGEKD:
006AB6AApushecxPAGEKD:
006AB6ABpushebpExceptionFramePAGEKD:
006AB6AEmovzxecxwordptreax1ChExceptionInformation2PAGEKD:
006AB6B2pushebpTrapFramePAGEKD:
006AB6B5pushdwordptrebpPreviousModePAGEKD:
006AB6B8pushecxPAGEKD:
006AB6B9pushdwordptreax18hExceptionInformation1PAGEKD:
006AB6BCmovecxebxCONTEXT._EdiPAGEKD:
006AB6C2callKdpPrintxxxxxxxxKdpTrap也会和KdpStub一样判断异常代码和参数个数以及调试服务号根据调试服务号的不同调用不同的处理函数。
针对BREAKPOINT_PRINT输出调试信息的情况调用的是KdpPrint函数。
�0�2KdpPrint也会根据ComponentId和Level值判断一下是否需要屏蔽此次输出。
然后判断特权模式如果是用户模式还需要探测字符串内存保证可读。
�0�2DbgPrint�0�2函数流程分析�0�2by�0�2小喂�0�2�0�2‐�0�27�0�2‐�0�2�0�2PAGEKD:
006AC921movebpasBuffer.BufferediPAGEKD:
006AC924movebpasBuffer.LengthbxPAGEKD:
006AC928leaeaxebpasBufferPAGEKD:
006AC92BpusheaxPAGEKD:
006AC92CcallKdpLogDbgPrintxPAGEKD:
006AC931cmp_KdDebuggerNotPresent0PAGEKD:
006AC938jnzshortloc_6AC984PAGEKD:
006AC93ApushebpExceptionFramePAGEKD:
006AC93DpushebpTrapFramePAGEKD:
006AC940callKdEnterDebuggerxxPAGEKD:
006AC945movebp-2
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DbgPrint 函数 分析 DbgView 使用