Wdf框架中WdfDriverGlobals对象的创建
2017-11-21 16:41
621 查看
前面写过一篇<WDF基本对象和句柄定义>,反响一般,不过这不会成为阻挡我继续写下去的绊脚石~本篇我们继续来分析Wdf框架。
WdfDriverGlobals对象的身影活跃在wdf框架的各个角落,几乎每个DDI接口内部都会使用它:
FxAllocateDriverGlobals函数本身不是很复杂,除了函数返回值,其他并不值得用大篇段落介绍。请注意代码中pFxDriverGlobals的类型为PFX_DRIVER_GLOBALS,而函数的返回类型为PWDF_DRIVER_GLOBALS。WDF_DRIVER_GLOBALS作为FX_DRIVER_GLOBALS结构的最后一部分,保存在其Public域内:
前面说了函数FxLibraryCommonRegisterClient调用FxAllocateDriverGlobals分配内存,但纵览整份WDF框架的源码都没有发现哪里调用FxLibraryCommonRegisterClient这个函数。Wdf框架总不可能一直在传递空的DriverGlobals对象,要不然OS早崩溃了。所以,我初步断定,很可能MS并没有把调用FxLibraryCommonRegisterClient函数的代码开源出来,原因不详。虽然MS不开源,但是根据调用栈来反推调用函数得源码应该不难。这就得靠windbg动态调试来做到了:
pseudocode),可以得到如下伪代码:
根据上面WdfVersionBind的伪代码,大概可以猜到Wdf01000.sys的模块信息存放在变量_LIBRARY_MODULE *Module;中。所以,我们可以在调用LibraryLinkInClient时,查看Module信息(fastcall,参数Library存放在rcx中)。
IDA分析得出的LibraryLinkInClient函数原型:
WdfDriverGlobals对象的身影活跃在wdf框架的各个角落,几乎每个DDI接口内部都会使用它:
_Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS WDFEXPORT(WdfDriverCreate)( PWDF_DRIVER_GLOBALS DriverGlobals, MdDriverObject DriverObject, PCUNICODE_STRING RegistryPath, PWDF_OBJECT_ATTRIBUTES DriverAttributes, PWDF_DRIVER_CONFIG DriverConfig, WDFDRIVER* Driver ) { ... pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); ... }不得不说,WdfDriverGlobals有着举足轻重的作用。在好奇心的驱使下,我查找了该对象的分配和创建过程:
NTSTATUS FxLibraryCommonRegisterClient( __inout PWDF_BIND_INFO Info, __deref_out PWDF_DRIVER_GLOBALS *WdfDriverGlobals, __in_opt PCLIENT_INFO ClientInfo ) { NTSTATUS status; UNICODE_STRING serviceName = { 0 }; ASSERT(Info->FuncCount); *WdfDriverGlobals = NULL; ... *WdfDriverGlobals = FxAllocateDriverGlobals(); if (*WdfDriverGlobals) { ...虽然SourceInsight中可以找到大量对WdfDriverGlobals的引用,但唯有这处比较特别:FxLibraryCommonRegisterClient函数的第二个参数是一个二级指针类型。这涉及到每个C语言入门者都会遇到的难题:如何在函数内部为指针分配内存并回传给调用者,答案之一是通过二级指针实现。因此,我比较确定这个函数的作用之一就是调用FxAllocateDriverGlobals函数为WdfDriverGlobals分配内存并初始化。
PWDF_DRIVER_GLOBALS FxAllocateDriverGlobals( VOID ) { PFX_DRIVER_GLOBALS pFxDriverGlobals; KIRQL irql; NTSTATUS status; //MxAllocatePoolWithTag内部调用ExAllocatePoolWithTag,分配非分页内存 pFxDriverGlobals = (PFX_DRIVER_GLOBALS) MxMemory::MxAllocatePoolWithTag(NonPagedPool, sizeof(FX_DRIVER_GLOBALS), FX_TAG); if (pFxDriverGlobals == NULL) { return NULL; } //准备初始化 RtlZeroMemory(pFxDriverGlobals, sizeof(FX_DRIVER_GLOBALS)); ... return &pFxDriverGlobals->Public; //<----敲黑板 划重点 请各位注意函数的返回值 }
FxAllocateDriverGlobals函数本身不是很复杂,除了函数返回值,其他并不值得用大篇段落介绍。请注意代码中pFxDriverGlobals的类型为PFX_DRIVER_GLOBALS,而函数的返回类型为PWDF_DRIVER_GLOBALS。WDF_DRIVER_GLOBALS作为FX_DRIVER_GLOBALS结构的最后一部分,保存在其Public域内:
typedef struct _FX_DRIVER_GLOBALS { public: ULONG __inline AddRef( __in_opt PVOID Tag = NULL, __in LONG Line = 0, __in_opt PSTR File = NULL ); ... PFX_TELEMETRY_CONTEXT TelemetryContext; DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) WDF_DRIVER_GLOBALS Public; } FX_DRIVER_GLOBALS, *PFX_DRIVER_GLOBALS;我们可能以WDF_DRIVER_GLOBALS*作为参数调用DDI接口,而DDI接口内部会通过GetFxDriverGlobals宏(确切的说是CONTAINING_RECORD宏),根据DriverGlobals的地址以及DriverGlobals对应的Public域在结构中的偏移计算出调用FxAllocateDriverGlobals时分配的对象的起始地址。不过,真不知道MS为什么要大费周章的这么折腾...
__inline PFX_DRIVER_GLOBALS GetFxDriverGlobals( __in PWDF_DRIVER_GLOBALS DriverGlobals ) { return CONTAINING_RECORD( DriverGlobals, FX_DRIVER_GLOBALS, Public ); }
前面说了函数FxLibraryCommonRegisterClient调用FxAllocateDriverGlobals分配内存,但纵览整份WDF框架的源码都没有发现哪里调用FxLibraryCommonRegisterClient这个函数。Wdf框架总不可能一直在传递空的DriverGlobals对象,要不然OS早崩溃了。所以,我初步断定,很可能MS并没有把调用FxLibraryCommonRegisterClient函数的代码开源出来,原因不详。虽然MS不开源,但是根据调用栈来反推调用函数得源码应该不难。这就得靠windbg动态调试来做到了:
kd> x Wdf01000!FxLibraryCommonRegisterClient ;查找符号 fffff80e`55b25a64 Wdf01000!FxLibraryCommonRegisterClient (struct _WDF_BIND_INFO *, struct _WDF_DRIVER_GLOBALS **, struct _CLIENT_INFO *) kd> bu Wdf01000!FxLibraryCommonRegisterClient ;系统启动时,Wdf01000.sys还没加载,所以要下延迟断点 kd> g Breakpoint 0 hit Wdf01000!FxLibraryCommonRegisterClient: fffff80e`55b25a64 4c8bdc mov r11,rsp kd> kb RetAddr : Args to Child : Call Site fffff80e`55b25a26 : 00000010`00000b32 ffffbe0a`67727453 00000000`00000002 fffff803`f6ed529d : Wdf01000!FxLibraryCommonRegisterClient [minkernel\wdf\framework\kmdf\src\librarycommon\fxlibrarycommon.cpp @ 344] fffff80e`55c0d3a5 : 00000000`00000000 fffff80e`57704148 fffff80e`57704160 fffff803`f6a21832 : Wdf01000!LibraryRegisterClient+0x56 [minkernel\wdf\framework\kmdf\src\dynamic\version\version.cpp @ 517] fffff80e`57702634 : ffffe201`0425e230 00000000`00000000 00000000`00000078 00000000`00000000 : WDFLDR!WdfVersionBind+0xd5 [minkernel\wdf\framework\kmdf\src\dynamic\loader\wdfldr.cpp @ 1954] fffff803`f6e6257a : 00000000`00000000 ffffbe0a`add31440 ffffae09`6c7f6e60 ffffffff`800000f0 : CompositeBus!FxDriverEntryWorker+0x74 fffff803`f6e64c8b : 00000000`00000000 00000000`00000000 00000000`00000004 ffffe201`00000004 : nt!IopLoadDriver+0x4da fffff803`f6e652a8 : ffffffff`80000001 ffffbe0a`add316d0 ffffffff`800000ec 00000000`00000000 : nt!PipCallDriverAddDeviceQueryRoutine+0x1b3 fffff803`f6e68009 : 00000000`00000000 ffffbe0a`add316b0 00000000`6e657050 00000000`0000001a : nt!PnpCallDriverQueryServiceHelper+0xcc fffff803`f6e718b8 : ffffae09`6ada0d20 ffffbe0a`add318f0 ffffae09`6ada0d20 ffffae09`6ad9fd20 : nt!PipCallDriverAddDevice+0x385 fffff803`f6fdd495 : ffffae09`6c775b30 ffffbe0a`add31b19 ffffae09`6c775b30 ffffae09`6c775b80 : nt!PipProcessDevNodeTree+0x164 fffff803`f6b17f94 : ffffae01`00000003 ffffae09`00000000 ffffae09`00000000 00000000`00000000 : nt!PiProcessStartSystemDevices+0x59 fffff803`f6a5a645 : ffffae09`6acde700 ffffae09`6ac7b6e0 fffff803`f6d7a960 ffffae09`0000000c : nt!PnpDeviceActionWorker+0x474 fffff803`f6ae33a7 : 00000000`00000000 00000000`00000080 ffffae09`6ac84480 ffffae09`6acde700 : nt!ExpWorkerThread+0xf5 fffff803`f6b68d66 : fffff803`f5e90180 ffffae09`6acde700 fffff803`f6ae3360 00000000`00000000 : nt!PspSystemThreadStartup+0x47 00000000`00000000 : ffffbe0a`add32000 ffffbe0a`add2c000 00000000`00000000 00000000`00000000 : nt!KiStartSystemThread+0x16最底部的nt!KiStartSystemThread显示当前系统还在启动阶段,在此阶段中,Wdfldr.sys!WdfVersionBind调用函数FxLibraryCommonRegisterClient,并最终分配全局(全局这个词有待考证,每个OS中已加载的driver都有各自的WdfDriverGlobals实例<----这句话我仍在调研中,如果有结果,会在后续的文章中更新)对象WdfDriverGlobals。正是这WdfLdr的代码,MS没有公开。好在有pdb文件,可以用IDA逆向分析。加载WdfLdr.sys并设置pdb路径后,F5(Generate
pseudocode),可以得到如下伪代码:
__int64 __fastcall WdfVersionBind(_DRIVER_OBJECT *DriverObject, _UNICODE_STRING *RegistryPath, _WDF_BIND_INFO *Info, void ***Globals) { void ***v4; // rsi@1 _WDF_BIND_INFO *v5; // rdi@1 _UNICODE_STRING *v6; // rbp@1 int (__cdecl *v7)(_WDF_BIND_INFO *, void ***, void **); // rax@3 _CLIENT_MODULE *v8; // rcx@3 __int64 result; // rax@3 _LIBRARY_MODULE *Module; // [sp+30h] [bp-38h]@1 _CLIENT_MODULE *v11; // [sp+38h] [bp-30h]@3 int v12; // [sp+40h] [bp-28h]@1 _UNICODE_STRING *v13; // [sp+48h] [bp-20h]@1 v12 = 16; v4 = Globals; Module = 0i64; v5 = Info; v13 = 0i64; v6 = RegistryPath; if ( WdfLdrDiags & 1 ) { DbgPrint("WdfLdr: WdfVersionBind - "); DbgPrint("WdfLdr: WdfVersionBind: enter\n"); } v11 = 0i64; JUMPOUT(v4, 0i64, sub_1C000D920); JUMPOUT(v5, 0i64, sub_1C000D920); JUMPOUT(v5->FuncTable, 0i64, sub_1C000D920); JUMPOUT(ReferenceVersion(v5, &Module), 0, sub_1C000D8DC); JUMPOUT(LibraryLinkInClient(v5->Module, v6, v5, 0i64, &v11), 0, sub_1C000D87C); v13 = v6; v7 = Module->LibraryInfo->LibraryRegisterClient; LODWORD(result) = _guard_dispatch_icall_fptr(v5, v4); JUMPOUT(result, 0, sub_1C000D8AC); v8 = v11; v11->Globals = *v4; v8->Context = &v12; JUMPOUT(result, 0, &loc_1C000D8E1); JUMPOUT(WdfLdrDiags & 1, 0, sub_1C000D8FE); return (unsigned int)result; }伪代码行中
v7 = Module->LibraryInfo->LibraryRegisterClient;LibraryRegisterClient应该就是我们的FxLibraryCommonRegisterClient函数,如果是这样的话,Module可能包含了Wdf01000.sys的信息。让我么来验证一下:
根据上面WdfVersionBind的伪代码,大概可以猜到Wdf01000.sys的模块信息存放在变量_LIBRARY_MODULE *Module;中。所以,我们可以在调用LibraryLinkInClient时,查看Module信息(fastcall,参数Library存放在rcx中)。
IDA分析得出的LibraryLinkInClient函数原型:
__int64 __fastcall LibraryLinkInClient(_LIBRARY_MODULE *Library, _UNICODE_STRING *RegistryPath, _WDF_BIND_INFO *Info, void *Context, _CLIENT_MODULE **Client)接下来,一起验证一下IDA伪代码中的v7 = Module->LibraryInfo->LibraryRegisterClient;调用的的确是Wdf01000.sys中的FxLibraryCommonRegisterClient
kd> bp WDFLDR!LibraryLinkInClient kd> g Breakpoint 2 hit WDFLDR!LibraryLinkInClient: fffff80e`55c024a0 48895c2408 mov qword ptr [rsp+8],rbx kd> dt WDFLDR!_LIBRARY_MODULE @rcx ;查看LibraryLinkInClient的第一个参数。参数类型为LIBRARY_MODULE,保存在rcx中 +0x000 LibraryRefCount : 0n1 +0x008 LibraryListEntry : _LIST_ENTRY [ 0xfffff80e`55c0a238 - 0xfffff80e`55c0a238 ] +0x018 ClientRefCount : 0n10 +0x01c IsBootDriver : 0x1 '' +0x01d ImplicitlyLoaded : 0x1 '' +0x020 Service : _UNICODE_STRING "\Registry\Machine\System\CurrentControlSet\Services\Wdf01000" +0x030 ImageName : _UNICODE_STRING "Wdf01000.sys" ;模块信息为Wdf01000.sys +0x040 ImageAddress : 0xfffff80e`55b10000 Void +0x048 ImageSize : 0xe3000 +0x050 LibraryFileObject : 0xffffae09`6ac7a210 _FILE_OBJECT +0x058 LibraryDriverObject : 0xffffae09`6b9b4b20 _DRIVER_OBJECT +0x060 LibraryInfo : 0xfffff80e`55bcf140 _WDF_LIBRARY_INFO ;Wdf01000.sys设置的回调函数的地址 +0x068 ClientsListHead : _LIST_ENTRY [ 0xffffae09`6c767110 - 0xffffae09`6af091b0 ] +0x078 ClientsListLock : _ERESOURCE +0x0e0 Version : _WDF_VERSION +0x0f0 LoaderEvent : _KEVENT +0x108 LoaderThread : (null) +0x110 ClassListHead : _LIST_ENTRY [ 0xffffae09`6ba1bd08 - 0xffffae09`6ba1bd08 ] ;显示Wdf01000.sys设置的回调函数 kd> dt _WDF_LIBRARY_INFO 0xfffff80e`55bcf140 Wdf01000!_WDF_LIBRARY_INFO +0x000 Size : 0x38 +0x008 LibraryCommission : 0xfffff80e`55b46870 long Wdf01000!LibraryCommission+0 +0x010 LibraryDecommission : 0xfffff80e`55b759c0 long Wdf01000!LibraryDecommission+0 +0x018 LibraryRegisterClient : 0xfffff80e`55b259d0 long Wdf01000!LibraryRegisterClient+0 ;这是我们上文分析的创建WdfDriverGlobals的函数入口 +0x020 LibraryUnregisterClient : 0xfffff80e`55b759e0 long Wdf01000!LibraryUnregisterClient+0 +0x028 Version : _WDF_VERSION kd> .srcfix C:\srcfix\Windows-Driver-Frameworks-master\src\framework ;设置Wdf框架源码路径 Source search path is: SRV*;C:\srcfix\Windows-Driver-Frameworks-master\src\framework kd> lsa Wdf01000!LibraryRegisterClient ;显示源码,WDFLDR!_LIBRARY_MODULE->_WDF_LIBRARY_INFO->LibraryRegisterClient指向Wdf01000!LibraryRegisterClient 458: clientInfo = (PCLIENT_INFO)*Context; 459: *Context = NULL; 460: 461: ASSERT(Info->Version.Major == WdfLibraryInfo.Version.Major); > 462:windbg显示的信息和前面我的猜测有点出路,看来要结合SourceInsight看看是不是遗漏什么。原来Wdf01000.sys在DriverEntry中通过WdfLdr!WdfRegisterLibrary注册了WdfLibraryInfo结构:
extern "C" { #pragma prefast(suppress:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "kernel component."); WDF_LIBRARY_INFO WdfLibraryInfo = { sizeof(WDF_LIBRARY_INFO), (PFNLIBRARYCOMMISSION) WDF_LIBRARY_COMMISSION, (PFNLIBRARYDECOMMISSION) WDF_LIBRARY_DECOMMISSION, (PFNLIBRARYREGISTERCLIENT) WDF_LIBRARY_REGISTER_CLIENT, (PFNLIBRARYUNREGISTERCLIENT) WDF_LIBRARY_UNREGISTER_CLIENT, { __WDF_MAJOR_VERSION, __WDF_MINOR_VERSION, __WDF_BUILD_NUMBER } };这个结构体变量初始化看着有点怪怪的,各个成员更像是一段宏,而不是某个函数地址。那就根据这些宏的名字,按图索骥,找到定义他们的地方;
#define WDF_LIBRARY_COMMISSION LibraryCommission #define WDF_LIBRARY_DECOMMISSION LibraryDecommission #define WDF_LIBRARY_REGISTER_CLIENT LibraryRegisterClient #define WDF_LIBRARY_UNREGISTER_CLIENT LibraryUnregisterClient恩,我们顺利找到了宏WDF_LIBRARY_REGISTER_CLIENT对应的函数名:LibraryRegisterClient,而这个函数名就是前面windbg lsa命令显示的源码,由它调用了FxLibraryCommonRegisterClient去分配和初始化WdfDriverGlobals对象,供以后其他DDI使用:
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 ) { NTSTATUS status = STATUS_INVALID_PARAMETER; PFX_DRIVER_GLOBALS pFxDriverGlobals; WCHAR insertString[EVTLOG_MESSAGE_SIZE]; ULONG rawData[RAW_DATA_SIZE]; PCLIENT_INFO clientInfo = NULL; ... status = FxLibraryCommonRegisterClient(Info, WdfDriverGlobals, clientInfo);
相关文章推荐
- 框架与Window对象 学习笔记(一): 创建多个框架
- 框架如何创建App子类的对象(二)? 推荐
- 如何在SpringMVC框架中利用Java反射机制和Javassist实现Java对象、属性、注解的动态创建生成
- 新的 Windows 驱动框架 WDF (Windows Driver Foundation)
- 网络连接之——谷歌提供的通信框架Volley【避免创建多个线程对象】
- spring.net 框架分析(一)对象的创建
- 在YII框架中有2中方法创建对象:
- <框架篇(2)>Spring框架中实例对象(bean)的创建方式(一)
- SSM框架之spring学习1——创建对象,处理依赖关系
- WDF(Windows Driver Frameworks)驱动框架源码!!
- sfilter的DriverEntry例程中创建的控制设备对象之作用
- SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 SignalR 简单示例 通过三个DEMO学会SignalR的三种实现方式 SignalR推送框架两个项目永久连接通讯使用 SignalR 集线器简单实例2 用SignalR创建实时永久长连接异步网络应用程序
- 新的 Windows 驱动框架 WDF (Windows Driver Foundation)
- SSM框架---容器创建注入对象失败
- Spring.NET依赖注入框架学习-- 泛型对象的创建和使用
- spring 框架最基本的功能就是充当创建对象的工厂
- 【框架-MFC】动态创建HICON或HCURSOR对象
- SSH框架之Spring的IOC容器的创建对象、对象依赖关系(1)
- ASP EF框架,数据库操作类(上下文类)的实例创建,线程内唯一对象(HttpContext)
- Wdf框架:FxDriverEntry----驱动程序的入口函数