wdf框架之WdfVersionBind函数分析(2)

WdfVersionBind详解

前篇,这篇一起来看下WdfVersionBind函数的第4个参数:WdfDriverGlobals。

经过前面一番波折,WdfVersionBind总算找到了Wdf01000.sys!_WDF_LIBRARY_INFO结构。接下去,它要调用_WDF_LIBRARY_INFO!LibraryCommission函数,为WdfDriverGlobals分配空间并初始化。因为_WDF_LIBRARY_INFO!LibraryCommission中保存的是函数指针,因此直接看到调试器以call eax的方式进行调用,如下表:

WdfVersionBind(x,x,x,x)+9B   024                 mov     eax, [ebp+WDFLDR_LIBRARY_MODULE_Ptr]
WdfVersionBind(x,x,x,x)+9E   024                 push    ecx             ; prepare to call WDF_LIBRARY_REGISTER_CLIENT
WdfVersionBind(x,x,x,x)+9F   028                 push    ebx
WdfVersionBind(x,x,x,x)+A0   02C                 push    esi
WdfVersionBind(x,x,x,x)+A1   030                 mov     eax, [eax+WDFLDR_LIBRARY_MODULE.LibraryInfo]
WdfVersionBind(x,x,x,x)+A4   030                 mov     eax, [eax+_WDF_LIBRARY_INFO.LibraryRegisterClient]
WdfVersionBind(x,x,x,x)+A7   030                 call    eax             ; call Wdf01000!LibraryRegisterClient
WdfVersionBind(x,x,x,x)+A7                                               ;
WdfVersionBind(x,x,x,x)+A7                                               ; NTSTATUS
WdfVersionBind(x,x,x,x)+A7                                               ; WDF_LIBRARY_REGISTER_CLIENT(
WdfVersionBind(x,x,x,x)+A7                                               ;      PWDF_BIND_INFO,PWDF_DRIVER_GLOBALS*,PCLIENT_INFO);
WdfVersionBind(x,x,x,x)+A9   024                 mov     edi, eax
既然是以call eax的方式调用,那么寄存器eax中必然保存着跳转目标的地址,可以借助windbg查看该地址对应的符号(也就是函数名。附注,wdf01000.sys将自己实现的函数地址填写到WdfLdr.sys:_WDF_LIBRARY_INFO结构中,那么一般来说,wdf01000.sys必然会导出这些函数----便于根据函数名查找地址。所以,这些导出函数一定会被windbg精确的匹配到):

kd> bp WDFLDR!WdfVersionBind+0xa7 ;在call eax处下断点
kd> g
Breakpoint 2 hit
WDFLDR!WdfVersionBind+0xa7:
8b40a317 ffd0            call    eax
kd> r eax ;查看eax中保存的转移地址
eax=8b975110
kd> ln 8b975110 ;查看该地址对应的符号
d:\th\minkernel\wdf\framework\kmdf\src\dynamic\version\version.cpp(449)
SrcSrv Command: 
(8b975110)   Wdf01000!LibraryRegisterClient   |  (8b97519c)   Wdf01000!FxLibraryCommonRegisterClient
Exact matches:
    Wdf01000!LibraryRegisterClient (void)
上面的输出分明指出WdfVersionBind会跳转到Wdf01000.sys!LibraryRegisterClient中。正好MS公开了这个函数的原型,真是得来全不费工夫:

extern "C"
_Must_inspect_result_
NTSTATUS
WDF_LIBRARY_REGISTER_CLIENT(
    __in  PWDF_BIND_INFO        Info,
    __deref_out   PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
    __deref_inout PVOID             * Context
    );
调用这个函数时(call eax),第二个参数(二级指针)指向空,即WdfDriverGlobals还没有分配到内存,

push    ecx             ; prepare to call WDF_LIBRARY_REGISTER_CLIENT
push    ebx ;WDF_LIBRARY_REGISTER_CLIENT函数的第二个参数
push    esi
mov     eax, [eax+WDFLDR_LIBRARY_MODULE.LibraryInfo]
mov     eax, [eax+_WDF_LIBRARY_INFO.LibraryRegisterClient]
call    eax
...
kd> r ebx
ebx=abd03070
kd> dd @ebx L1
abd03070  00000000 ;指针指向的的值为空
直到从FxLibraryCommonRegisterClient进入FxAllocateDriverGlobals才调用MxMemory::MxAllocatePoolWithTag真正分配内存。在以前的文章中也说过,WdfDriverGlobals只是作为结构体PFX_DRIVER_GLOBALS中最后一个域,返回给驱动,供其在整个驱动程序生命周期中使用。所以,我们在关注WdfDriverGlobals变量之余,还需要顺带关注一下WdfDriverGlobals变量的属主----PFX_DRIVER_GLOBALS  pFxDriverGlobals的内容。哎,写到这,我就想感叹一下MS:虽说它把WDF框架的代码(大部分)开源出来,但是,不支持编译!!!所以,在调试过程中即使有pdb文件做源码行索引,但依然无法与二进制文件一一对应起来,它这样的开源实在很影响学习!不过,好在有IDA,结合源码还是可以艰难的调试下去。比如查看pFxDriverGlobals的内容,倒也不是不可完成的任务,查看代码,可以看到这样的内容:

PWDF_DRIVER_GLOBALS
FxAllocateDriverGlobals(
    VOID
    )
{
	...
	return &pFxDriverGlobals->Public; //Public即为WdfDriverGlobals变量
}
借助这段代码,在IDA中可以找到对应的汇编代码,阅读后了解到pFxDriverGlobals的地址保存在edi中,因此,在蓝线处下断点,从中获取pFxDriverGlobals的内存分布


kd> bp Wdf01000!FxAllocateDriverGlobals+FB ;在lea eax,[edi+0F8h]处下断
kd> g
Breakpoint 4 hit
Wdf01000!FxAllocateDriverGlobals+0xfb:
8b975561 8d87f8000000    lea     eax,[edi+0F8h]
kd> r edi ;查看pFxDriverGlobals的地址值及内容
edi=a63884d0
kd> dt PFX_DRIVER_GLOBALS @edi ;此时,大部分结构体域还没有完成初始化工作
Wdf01000!PFX_DRIVER_GLOBALS
0xa3b7ac68 
   +0x000 Linkage          : _LIST_ENTRY [ 0xa94a1ce0 - 0xa63884d0 ] ;Linkage用来将所有的Wdf Client模块加入系统双向链表FxLibraryGlobals.FxDriverGlobalsList
   +0x008 Refcnt           : 0n1
   +0x00c DestroyEvent     : MxEvent
   +0x020 WdfHandleMask    : 0xfffffff8
   +0x024 WdfVerifierAllocateFailCount : 0n-1
   +0x028 Tag              : 0x75414550
   +0x02c Driver           : 0xa3b7a5d8 FxDriver
   +0x030 DebugExtension   : (null) 
   +0x034 LibraryGlobals   : 0x8b9e3578 FxLibraryGlobalsType
   +0x038 WdfLogHeader     : 0xa5c40000 Void
   +0x03c FxPoolFrameworks : FX_POOL
   +0x098 FxPoolTrackingOn : 0 ''
   +0x09c ThreadTableLock  : MxLock
   +0x0a4 ThreadTable      : (null) 
   +0x0a8 WdfBindInfo      : 0xabbd1000 _WDF_BIND_INFO
   +0x0ac ImageAddress     : 0xabbb0000 Void
   +0x0b0 ImageSize        : 0xb6000
   +0x0b4 FxVerifierOn     : 0 ''
   +0x0b5 FxVerifyDownlevel : 0 ''
   +0x0b6 FxVerifierDbgBreakOnError : 0 ''
   +0x0b7 FxVerifierDbgBreakOnDeviceStateError : 0 ''
   +0x0b8 FxVerifierHandle : 0 ''
   +0x0b9 FxVerifierIO     : 0 ''
   +0x0ba FxVerifierLock   : 0 ''
   +0x0bb FxVerifyOn       : 0 ''
   +0x0bc FxVerboseOn      : 0 ''
   +0x0bd FxRequestParentOptimizationOn : 0x1 ''
   +0x0be FxDsfOn          : 0 ''
   +0x0bf FxForceLogsInMiniDump : 0 ''
   +0x0c0 FxTrackDriverForMiniDumpLog : 0x1 ''
   +0x0c1 IsUserModeDriver : 0 ''
   +0x0c4 RemoveLockOptionFlags : 0
   +0x0c8 BugCheckDriverInfoIndex : 0x14
   +0x0cc BugCheckCallbackRecord : _KBUGCHECK_REASON_CALLBACK_RECORD
   +0x0e8 FxEnhancedVerifierOptions : 0
   +0x0ec FxVerifierDbgWaitForSignalTimeoutInSec : 0x3c
   +0x0f0 DbgWaitForWakeInterruptIsrTimeoutInSec : 0x3c
   +0x0f4 TelemetryContext : 0x93b7eed8 _FX_TELEMETRY_CONTEXT
   +0x0f8 Public           : _WDF_DRIVER_GLOBALS
kd> dt _WDF_DRIVER_GLOBALS @edi+0xf8
Wdf01000!_WDF_DRIVER_GLOBALS
   +0x000 Driver           : (null) 
   +0x004 DriverFlags      : 0
   +0x008 DriverTag        : 0
   +0x00c DriverName       : [32]  ""
   +0x02c DisplaceDriverUnload : 0 ''
等到执行流从FxAllocateDriverGlobals返回,FxLibraryCommonRegisterClient对Wdf01000!_WDF_DRIVER_GLOBALS进一步初始化,最终返回给WdfVersionBind。然后由WdfVersionBind调用我们自己的DriverEntry入口。





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值