天天看點

Wdf架構之WdfObject狀态機(2)

    前一篇博文<​​Wdf架構之WdfObject狀态機(1)​​>提到調用WdfObjectCreate使架構對象被納入對象狀态機的管理之下。本篇我們看下架構對象的銷毀過程,即如何結束它的生命周期,進而退出狀态機。由于對象的銷毀往往會引發着子對象的銷毀,整個過程跟迷宮一樣複雜,是以我們先在迷宮外了解一下穿越迷宮的捷徑,暫時不深入探索----即假設程式中隻建立一個Wdf驅動對象(空驅動,沒有子對象),不提供其他任何功能,然後停用驅動。

#include <ntddk.h>
#include <wdf.h>

void Unload(WDFDRIVER drvObj)
{
  UNREFERENCED_PARAMETER(drvObj);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT drvObj, PUNICODE_STRING regPath)
{
  WDF_DRIVER_CONFIG config;
  WDFDRIVER drvHnd;
  UNREFERENCED_PARAMETER(regPath);

  WDF_DRIVER_CONFIG_INIT(&config, NULL);
  config.DriverInitFlags = WdfDriverInitNonPnpDriver;

  config.EvtDriverUnload = Unload;
  return WdfDriverCreate(drvObj,regPath,NULL,&config,&drvHnd);
}      

如前所述,這是個簡單的空的驅動程式,不建立任何裝置對象,可以說這是一個非PNP驅動。對于非PNP驅動需要為WDF_DRIVER_CONFIG!DriverInitFlags域指定WdfDriverInitNonPnpDriver;同時,為

WDF_DRIVER_CONFIG!EvtDriverUnload域指定Unload函數。該驅動通過sc create/sc delete建立/删除服務,通過sc start/sc stop加載/停用驅動。

    大家已經知道,調用WdfDriverCreate後會建立FxDriver對象,并傳回代表FxDriver的句柄 。我們的目标是觀察FxDriver!m_ObjectState在驅動解除安裝過程中的狀态變化。雖然,我們有WDF的源碼,卻無法單步跟蹤源碼和确切的狀态值。不過,這是無法阻止我觀察對象的狀态變化的,變通之策就是從WdfDriverCreate傳回的句柄獲得FxDriver對象,然後通過設定通路斷點來追蹤狀态變遷。下列輸出是Wdf01000!FxDriver::m_ObjectState域在結構中的偏移:

kd> dt Wdf01000!FxDriver -y m_ObjectState 
   +0x012 m_ObjectState : Uint2B      

    現在,我們開始着手于從WDF句柄獲得WDF對象。雖然WDF源碼中給出了兩者之間的計算方法

VOID 
FxObjectHandleGetPtr(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
    __in WDFOBJECT Handle,
    __in WDFTYPE Type,
    __out PVOID* PPObject
    ); //從WDF句柄獲得WDF對象的内聯函數      

但是誰能保證它會一成不變的保持下去,是以還是得依靠windbg的擴充指令----!wdfhandle,在執行個體代碼的return語句之後下斷點,當命中斷點後,運作下列指令:

kd> .load wdfkd ;加載調試wdf驅動的DLL,以支援windbg擴充指令
kd> ?? drvHnd ;檢視WdfDriverCreate傳回的句柄值
struct WDFDRIVER__ *  0x73bf71e8;<-----句柄值
   +0x000 unused           : ??
kd> !wdfhandle 0x73bf71e8 ;!wdfhandle用以根據句柄值獲得對象資訊
Treating handle as a KMDF handle!
Dumping WDFHANDLE 0x73bf71e8
=============================
Handle type is WDFDRIVER
Refcount: 1
...
!wdfobject 0x8c408e10 ;提示運作!wdfobject, 0x8c408e10應該就是FxObject對象的位址  
kd> !wdfobject 0x8c408e10 ;
The type for object  is FxDriver
State: FxObjectStateCreated (0x1) ;<-----!wdfobject已經分析出目前FxObject對象的狀态值
!wdfhandle 0x73bf71e8      

上面的一系列指令,我們成功獲得FxDriver對象的位址(記得記下這個位址,後面調試過程中會反複使用上訴指令),接着,準備下通路斷點:

kd> dt FxDriver 0x8c408e10 -y m_Refcnt -y m_ObjectState
Wdf01000!FxDriver
   +0x008 m_Refcnt      : 0n1
   +0x012 m_ObjectState : 1
kd> ba w 4 0x8c408e10+0x08 ;FxDriver!m_Refcnt的通路斷點
kd> ba w 4 0x8c408e10+0x10 ;FxDriver!m_ObjectState的通路斷點,考慮到記憶體對齊,是以偏移設定為0x10      

    另外,為了驗證在調用wdf01000!FxDriver::Unload前,FxDriver!m_ObjectState的狀态未發生改變,還需要在wdf01000!FxDriver::Unload處下斷點:

kd> x wdf01000!FxDriver::Unload
86a16672          Wdf01000!FxDriver::Unload (struct _DRIVER_OBJECT *)
kd> bp Wdf01000!FxDriver::Unload      

    現在萬事俱備,準備觀察狀态的變化。驅動停止過程中,在Wdf01000!FxDriver::Unload處遇到斷點,正如所料,此時FxObject狀态沒有改變,為FxObjectStateCreated:

kd> g
Breakpoint 4 hit
Wdf01000!FxDriver::Unload:
86a16672 8bff            mov     edi,edi
kd> bl
 0 e a4d510d8     0001 (0001) KMDFdrv!FxDriverEntry
 1 e a4d51036     0001 (0001) KMDFdrv!DriverEntry+0x36
 2 e 8c408e18 w 4 0001 (0001) 
 3 e 8c408e20 w 4 0001 (0001) 
 4 e 86a16672     0001 (0001) Wdf01000!FxDriver::Unload

kd> kb
 # ChildEBP RetAddr  Args to Child              
00 b2c03bb8 a4d511de afc5b890 b2c03be0 81bc5013 Wdf01000!FxDriver::Unload ;斷點發生在FxDriver::Unload[fxdriver.cpp @ 143]
01 b2c03bc4 81bc5013 afc5b890 8c234910 afc257c0 KMDFdrv!FxStubDriverUnload+0x1a [stub.cpp @ 159]
02 b2c03be0 8191b8c5 8c234910 00000000 afc257c0 nt!IopLoadUnloadDriver+0x77
kd> !wdfobject 0x8c408e10 ;檢視FxDriver::m_ObjectState狀态

The type for object 0x8c408e10 is FxDriver
State: FxObjectStateCreated (0x1) ;從驅動啟動到停用,m_ObjectState狀态一直沒有改變
!wdfhandle 0x73bf71e8

kd> !wdfhandle 0x73bf71e8 
Treating handle as a KMDF handle!

Dumping WDFHANDLE 0x73bf71e8
=============================
Handle type is WDFDRIVER
Refcount: 1 <-引用計數也沒有發生改變

!wdfobject 0x8c408e10      

繼續放調試器運作,由于FxDriver會頻繁修改m_Refcnt和m_ObjectState的值,是以調試器會陸陸續續的中斷若幹次(附注,根據我觀察,每次發生通路斷點時esi寄存器存放FxDriver對象的位址):

kd> g
Breakpoint 3 hit
Wdf01000!FxObject::IsForceDisposeThreadLocked+0xd [inlined in Wdf01000!FxObject::DeleteObject+0xbe]:
86a0589e 0f859db90200    jne     Wdf01000!FxObject::DeleteObject+0x2ba61 (86a31241)
kd> ub . L2
Wdf01000!FxObject::SetObjectStateLocked+0xf [fxobjectstatemachine.cpp @ 124] [inlined in Wdf01000!FxObject::DeleteObject+0xb5 [fxobjectstatemachine.cpp @ 124]]:
86a05895 b809000000      mov     eax,9
86a0589a 66894612        mov     word ptr [esi+12h],ax ;彙編代碼顯示,架構正在修改m_ObjectState的值
kd> kb
 # ChildEBP RetAddr  Args to Child              
00 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::IsForceDisposeThreadLocked+0xd [fxobject.hpp @ 1379]
01 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::DisposeChildrenWorker+0xd [fxobjectstatemachine.cpp @ 1094]
02 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::DeleteWorkerAndUnlock+0x30 [d:\th\minkernel\wdf\framework\shared\object\fxobjectstatemachine.cpp @ 937]
03 b2c03ba4 86a166b2 8c234910 81a8f220 afc257c0 Wdf01000!FxObject::DeleteObject+0xbe [fxobjectstatemachine.cpp @ 124]
04 b2c03bb8 a4d511de afc5b890 b2c03be0 81bc5013 Wdf01000!FxDriver::Unload+0x40 [fxdriver.cpp @ 176]
05 b2c03bc4 81bc5013 afc5b890 8c234910 afc257c0 KMDFdrv!FxStubDriverUnload+0x1a [stub.cpp @ 159]      

這次中斷是因為架構企圖修改FxDriver::m_ObjectState的狀态值:

kd> !wdfobject 0x8c408e10
The type for object 0x8c408e10 is FxDriver
State: FxObjectStateDeletedDisposing (0x9) <--m_ObjectState由1變為9
!wdfhandle 0x73bf71e8
dt FxDriver 0x8c408e10

kd> !wdfhandle 0x73bf71e8
Treating handle as a KMDF handle!
Dumping WDFHANDLE 0x73bf71e8
=============================
Handle type is WDFDRIVER
Refcount: 1 <--引用計數暫無改變

!wdfobject 0x8c408e10      

繼續讓windbg運作,之後馬上會觸發通路斷點,這次還是因為修改m_ObjectState的狀态:

kd> g
Breakpoint 3 hit
Wdf01000!FxObject::DeleteObject+0x11e:
86a058fe 8bff            mov     edi,edi
kd> ub . L3
Wdf01000!FxObject::SetObjectStateLocked+0x9 [fxobjectstatemachine.cpp @ 124] [inlined in Wdf01000!FxObject::DeleteObject+0x10f [fxobjectstatemachine.cpp @ 124]]:
86a058ef 0f85b1b90200    jne     Wdf01000!FxObject::DeleteObject+0x2bac6 (86a312a6)
86a058f5 b80a000000      mov     eax,0Ah
86a058fa 66894612        mov     word ptr [esi+12h],ax
kd> !wdfhandle 0x73bf71e8
Treating handle as a KMDF handle!

Dumping WDFHANDLE 0x73bf71e8
=============================
Handle type is WDFDRIVER
Refcount: 1 ;引用計數沒有發生改變
!wdfobject 0x8c408e10
kd> !wdfobject 0x8c408e10

The type for object 0x8c408e10 is FxDriver
State: FxObjectStateDeletedAndDisposed (0xa) ;m_ObjectState狀态值由9變為0xa
!wdfhandle 0x73bf71e8

dt FxDriver 0x8c408e10
kd> kb
 # ChildEBP RetAddr  Args to Child              
00 b2c03ba4 86a166b2 8c234910 81a8f220 afc257c0 Wdf01000!FxObject::DeleteObject+0x11e [fxobjectstatemachine.cpp @ 124]
01 b2c03bb8 a4d511de afc5b890 b2c03be0 81bc5013 Wdf01000!FxDriver::Unload+0x40 [fxdriver.cpp @ 176]
02 b2c03bc4 81bc5013 afc5b890 8c234910 afc257c0 KMDFdrv!FxStubDriverUnload+0x1a [stub.cpp @ 159]
03 b2c03be0 8191b8c5 8c234910 00000000 afc257c0 nt!IopLoadUnloadDriver+0x77      

再次F5,下一次觸發通路中斷是因為Unload中調用Release減少FxDriver的引用計數

kd> g
Breakpoint 2 hit
Wdf01000!FxObject::Release+0x12 [inlined in Wdf01000!FxObject::DeleteObject+0x14a]:
86a0592a 48              dec     eax
kd> kb
 # ChildEBP RetAddr  Args to Child              
00 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::Release+0x12 [fxobject.hpp @ 867] ;<-Unload引起Release減少引用
01 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::DeletedAndDisposedWorkerLocked+0x44 [fxobjectstatemachine.cpp @ 1215]
02 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::DeleteWorkerAndUnlock+0xbc [fxobjectstatemachine.cpp @ 941]
03 b2c03ba4 86a166b2 8c234910 81a8f220 afc257c0 Wdf01000!FxObject::DeleteObject+0x14a [fxobjectstatemachine.cpp @ 124]
04 b2c03bb8 a4d511de afc5b890 b2c03be0 81bc5013 Wdf01000!FxDriver::Unload+0x40 [fxdriver.cpp @ 176]
05 b2c03bc4 81bc5013 afc5b890 8c234910 afc257c0 KMDFdrv!FxStubDriverUnload+0x1a [stub.cpp @ 159]
kd> ub . L4
Wdf01000!FxObject::IsDebug [fxobjectstatemachine.cpp @ 124] [inlined in Wdf01000!FxObject::DeleteObject+0x138 [fxobjectstatemachine.cpp @ 124]]:
86a05918 f6461080        test    byte ptr [esi+10h],80h ;<-修改引用計數的指令
86a0591c 0f85deb90200    jne     Wdf01000!FxObject::DeleteObject+0x2bb20 (86a31300)
86a05922 83c8ff          or      eax,0FFFFFFFFh
86a05925 f00fc14608      lock xadd dword ptr [esi+8],eax
kd> !wdfobject 0x8c408e10

The type for object 0x8c408e10 is FxDriver
State: FxObjectStateDeletedAndDisposed (0xa) ;m_ObjectState狀态從上次觸發中斷以來,沒有發生改變
!wdfhandle 0x73bf71e8

dt FxDriver 0x8c408e10

kd> !wdfhandle 0x73bf71e8
Treating handle as a KMDF handle!

Dumping WDFHANDLE 0x73bf71e8
=============================
Handle type is WDFDRIVER
Refcount: 0 ;<-引用計數減少為零

!wdfobject 0x8c408e10      

由于引用計數m_Refcnt歸零,會引起Wdf架構調用對象的析構函數FxDriver::~FxDriver。期間又會引起FxDriver狀态變化:

kd> g
Breakpoint 3 hit
Wdf01000!FxObject::~FxObject+0x51: ;<--架構目前進入了FxObject析構函數
86a0c1b1 5e              pop     esi
kd> kb
 # ChildEBP RetAddr  Args to Child              
00 b2c03b78 86a210b5 8c408e10 b2c03ba4 86a05acb Wdf01000!FxObject::~FxObject+0x51 [fxobject.cpp @ 155]
01 b2c03b84 86a05acb 00000001 afdb0118 8c408e10 Wdf01000!FxDriver::`scalar deleting destructor'+0xd
02 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::SelfDestruct+0xe7 [fxobject.hpp @ 441]
03 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::ProcessDestroy+0x17c [fxobjectstatemachine.cpp @ 371]
04 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::FinalRelease+0x19a [fxobject.cpp @ 249]
05 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::Release+0x1b3 [fxobject.hpp @ 870]
06 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::DeletedAndDisposedWorkerLocked+0x1e5 [fxobjectstatemachine.cpp @ 1215]
07 (Inline) -------- -------- -------- -------- Wdf01000!FxObject::DeleteWorkerAndUnlock+0x25d [fxobjectstatemachine.cpp @ 941]
08 b2c03ba4 86a166b2 8c234910 81a8f220 afc257c0 Wdf01000!FxObject::DeleteObject+0x2eb [fxobjectstatemachine.cpp @ 124]
09 b2c03bb8 a4d511de afc5b890 b2c03be0 81bc5013 Wdf01000!FxDriver::Unload+0x40 [fxdriver.cpp @ 176]
0a b2c03bc4 81bc5013 afc5b890 8c234910 afc257c0 KMDFdrv!FxStubDriverUnload+0x1a [stub.cpp @ 159]
0b b2c03be0 8191b8c5 8c234910 00000000 afc257c0 nt!IopLoadUnloadDriver+0x77
kd> ub . L4
Wdf01000!FxObject::SetObjectStateLocked+0x9 [fxobject.cpp @ 155] [inlined in Wdf01000!FxObject::~FxObject+0x3e [fxobject.cpp @ 155]]:
86a0c19e 0f853e5d0200    jne     Wdf01000!FxObject::~FxObject+0x25d82 (86a31ee2)
86a0c1a4 b80c000000      mov     eax,0Ch
86a0c1a9 c6461c00        mov     byte ptr [esi+1Ch],0
86a0c1ad 66894612        mov     word ptr [esi+12h],ax ;<-Wdf架構修改m_ObjectState狀态值
kd> !wdfhandle 0x73bf71e8
Treating handle as a KMDF handle!
Dumping WDFHANDLE 0x73bf71e8
=============================
Handle type is WDFDRIVER
Refcount: 0
!wdfobject 0x8c408e10
kd> !wdfobject 0x8c408e10
The type for object 0x8c408e10 is FxDriver
State: FxObjectStateDestroyed (0xc) ;狀态值由前面的0x0a變為0x0c
!wdfhandle 0x73bf71e8