天天看點

Wdf架構:FxDriverEntry----驅動程式的入口函數

    在前面的文章<Wdf架構中WdfDriverGlobals對象的建立>中簡單的提到過WdfVersionBind函數的作用,但是沒有來得及分析這個函數的調用處。今天得空,借這篇文章寫下WdfVersionBind函數的調用者:FxDriverEntry。

    在寫這篇文章前,我被WdfLdr.sys的名字誤導,以為這個sys檔案是核心的加載器,用于加載整個核心啟動(Ldr是Loader的縮寫)。是以,當時我很粗淺的認為這個驅動隻在系統引導階段才被調用,之後就靠邊站了。然而事實卻是,當系統啟動後,隻要加載基于WDF架構的驅動,就會中斷在WdfVersionBind函數上。以登入到系統後,加載WinDDK中WdfSimple.sys驅動(toast驅動的WDF版本)為例:

kd> bp WDFLDR!WdfVersionBind
kd> g
Breakpoint 1 hit
WDFLDR!WdfVersionBind:
fffff802`9598d2d0 488bc4          mov     rax,rsp
kd> kb
RetAddr           : Args to Child                                                           : Call Site
fffff802`98a414a3 : ffff8881`fc86f000 ffff8881`fbf2c750 00000000`00000000 ffff327f`24cdc304 : WDFLDR!WdfVersionBind 
fffff802`5ab053e9 : 00000000`00000000 ffffd381`a819d460 ffff8881`fbf2c750 ffffffff`00000000 : wdfsimple!FxDriverEntryWorker+0x7f
fffff802`5abab13e : 00000000`00000000 00000000`00000000 00000000`00000004 ffffc285`00000004 : nt!IopLoadDriver+0x521
fffff802`5ab04495 : ffffd381`a819da01 ffffd381`a819d6c8 00000000`c0000000 ffffd381`a819d6a4 : nt!PipCallDriverAddDeviceQueryRoutine+0x1b6
fffff802`5ab03e93 : 00000000`00000000 00000000`00000014 00000000`c0000034 ffff8881`fbd6cd30 : nt!PnpCallDriverQueryServiceHelper+0xbd
fffff802`5ab0323d : ffff8881`fbd6cd30 ffffd381`a819d8e0 ffff8881`fbd6cd30 00000000`00000000 : nt!PipCallDriverAddDevice+0x317
fffff802`5acd5eda : ffff8881`fbd6cd30 00000000`00000001 ffffd381`a819db19 fffff802`5ab0397b : nt!PipProcessDevNodeTree+0x1cd
fffff802`5a824d9e : 00000001`00000003 00000000`00000000 ffffd381`a819daf0 00000000`00000000 : nt!PiRestartDevice+0xba
fffff802`5a6e0d79 : ffff8881`f97af040 fffff802`5a9a5320 fffff802`5aa46280 fffff802`5aa46280 : nt! ?? ::FNODOBFM::`string'+0x42bde
fffff802`5a7254bd : fffff802`5a9cb180 00000000`00000080 ffff8881`f88af6c0 ffff8881`f97af040 : nt!ExpWorkerThread+0xe9
fffff802`5a7d8456 : fffff802`5a9cb180 ffff8881`f97af040 fffff802`5a72547c 43ffff41`04080003 : nt!PspSystemThreadStartup+0x41
00000000`00000000 : ffffd381`a819e000 ffffd381`a8198000 00000000`00000000 00000000`00000000 : nt!KxStartSystemThread+0x16      

圖1:

Wdf架構:FxDriverEntry----驅動程式的入口函數

圖1結合調試輸出顯示,在登入系統後,加載驅動也會中斷到WdfVersionBind。由此可見,OS會為每個Wdf驅動設定WDF架構的版本号等資訊。這些内容屬于上一篇文章的延伸,我要借助它引出這篇文章的主題:FxDriverEntry。

    上面的函數調用棧中隻有frame 1與我們的驅動子產品有關,但名字卻是FxDriverEntryWorker。整份Sample源碼中沒有調用這個函數,可見,它是由編譯器插入的。這就又引出2個疑問:

1.驅動入口DriverEntry在FxDriverEntryWorker函數執行完後調用;

2.反之,驅動入口DriverEntry在FxDriverEntryWorker函數之前執行。

如果屬于情況2,可能我要重新開機或者重新加載驅動。怕麻煩的我最終選擇用IDA加載wdfsimple.sys分析了函數流程。下圖是在IDA中對DriverEntry函數執行"XRefs graph to"後生成的調用圖,調用次序依次為FxDriverEntry->FxDriverEntryWorker->DriverEntry:

Wdf架構:FxDriverEntry----驅動程式的入口函數
int __fastcall FxDriverEntryWorker(_DRIVER_OBJECT *DriverObject, _UNICODE_STRING *RegistryPath)
{
  _UNICODE_STRING *v2; // rsi@1
  _DRIVER_OBJECT *v3; // rdi@1
  int result; // eax@2
  int v5; // ebx@4
  void (__cdecl *v6)(_DRIVER_OBJECT *); // rax@7

  v2 = RegistryPath;
  v3 = DriverObject;
  if ( DriverObject )
  {
    result = WdfVersionBind_0(v3, &WdfDriverStubRegistryPath, &WdfBindInfo, &WdfDriverGlobals);
    if ( result >= 0 )
    {
      v5 = FxStubBindClasses(&WdfBindInfo);
      if ( v5 < 0 || (FxStubInitTypes(), v5 = DriverEntry(v3, v2), v5 < 0) )  //WdfVersionBind執行成功後,調用DrvierEntry
      {
      }