Windows驅動之Reinitialize

Windows驅動之Reinitialize

Windows驅動下面提供了兩個Reinitialize:

  1. IoRegisterBootDriverReinitialization.
  2. IoRegisterDriverReinitialization.

按照MSDN的描述,這兩個函數可以提供驅動重新初始化的機會;但是重新初始化是什麼呢?這兩個函數又有什麼區別呢?本文來探討一下這些問題。

1. IoRegisterBootDriverReinitialization

1.1 函數聲明

VOID IoRegisterBootDriverReinitialization(
  _In_     PDRIVER_OBJECT       DriverObject,
  _In_     PDRIVER_REINITIALIZE DriverReinitializationRoutine,
  _In_opt_ PVOID                Context
);

DRIVER_REINITIALIZE Reinitialize;

VOID Reinitialize(
  _In_     struct _DRIVER_OBJECT *DriverObject,
  _In_opt_ PVOID                 Context,
  _In_     ULONG                 Count
)
{ ... }

這個函數想系統註冊一個DRIVER_REINITIALIZE,並在合適的時間調用這個函數。

1.2 原理

我們看一下這個函數的實現過程:

VOID
NTAPI
IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
                                     IN PDRIVER_REINITIALIZE ReinitRoutine,
                                     IN PVOID Context)
{
    PDRIVER_REINIT_ITEM ReinitItem;

    /* Allocate the entry */
    ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
                                       sizeof(DRIVER_REINIT_ITEM),
                                       TAG_REINIT);
    if (!ReinitItem) return;

    /* Fill it out */
    ReinitItem->DriverObject = DriverObject;
    ReinitItem->ReinitRoutine = ReinitRoutine;
    ReinitItem->Context = Context;

    /* Set the Driver Object flag and insert the entry into the list */
    DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
    ExInterlockedInsertTailList(&DriverBootReinitListHead,
                                &ReinitItem->ItemEntry,
                                &DriverBootReinitListLock);
}

其實這個函數很簡單,就是分配一個PDRIVER_REINIT_ITEM結構,保存到全局的鏈表DriverBootReinitListHead中,合適的時機再調用。

因此這裏有一個很重要的問題需要注意:IoRegisterDriverReinitialization的調用確保驅動正常被加載,也就是說DriverEntry必須返回STATUS_SUCCESS;否則運行PDRIVER_REINITIALIZE將會崩潰

那麼驅動PDRIVER_REINITIALIZE回調函數是什麼時候被執行的呢?答案就是當所有的Boot類型驅動加載完成之後,例如:

BOOLEAN
INIT_FUNCTION
NTAPI
IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
    //...
    /* Load boot start drivers */
    IopInitializeBootDrivers();

    /* Call back drivers that asked for */
    IopReinitializeBootDrivers();
    //...
}

VOID
NTAPI
IopReinitializeBootDrivers(VOID)
{
    PDRIVER_REINIT_ITEM ReinitItem;
    PLIST_ENTRY Entry;

    /* Get the first entry and start looping */
    Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
                                        &DriverBootReinitListLock);
    while (Entry)
    {
        /* Get the item */
        ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);

        /* Increment reinitialization counter */
        ReinitItem->DriverObject->DriverExtension->Count++;

        /* Remove the device object flag */
        ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;

        /* Call the routine */
        ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
                                  ReinitItem->Context,
                                  ReinitItem->DriverObject->
                                  DriverExtension->Count);

        /* Free the entry */
        ExFreePool(Entry);

        /* Move to the next one */
        Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
                                            &DriverBootReinitListLock);
    }
}

這個流程比較明顯了:

  1. IopInitializeBootDrivers加載完成Boot驅動。
  2. IopReinitializeBootDrivers調用DriverBootReinitListHead註冊的函數。

1.3 作用

這個函數有什麼作用呢?有一種情況好處是比較明顯的。例如我們要做相關的初始化,但是這個初始化依賴其他的Boot型驅動,那麼我們可以利用IoRegisterBootDriverReinitialization註冊一個重新初始化的函數,等待其他BOOT驅動加載完成之後再初始化。

2. IoRegisterDriverReinitialization

有了上面的分析經驗之後,分析這個函數就簡單多了,下面我們看下這個函數的流程。

2.1 聲明

VOID IoRegisterDriverReinitialization(
  _In_      PDRIVER_OBJECT DriverObject,
  _In_      PDRIVER_REINITIALIZE DriverReinitializationRoutine,
  _In_opt_  PVOID Context
);

DRIVER_REINITIALIZE Reinitialize;

VOID Reinitialize(
  _In_     struct _DRIVER_OBJECT *DriverObject,
  _In_opt_ PVOID                 Context,
  _In_     ULONG                 Count
)
{ ... }

2.2 原理

這個函數的註冊和Boot初始化的函數註冊流程基本一致,只是這個結構放到了另外一個鏈表DriverReinitListHead中了。

IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
                                 IN PDRIVER_REINITIALIZE ReinitRoutine,
                                 IN PVOID Context)
{
    PDRIVER_REINIT_ITEM ReinitItem;

    /* Allocate the entry */
    ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
                                       sizeof(DRIVER_REINIT_ITEM),
                                       TAG_REINIT);
    if (!ReinitItem) return;

    /* Fill it out */
    ReinitItem->DriverObject = DriverObject;
    ReinitItem->ReinitRoutine = ReinitRoutine;
    ReinitItem->Context = Context;

    /* Set the Driver Object flag and insert the entry into the list */
    DriverObject->Flags |= DRVO_REINIT_REGISTERED;
    ExInterlockedInsertTailList(&DriverReinitListHead,
                                &ReinitItem->ItemEntry,
                                &DriverReinitListLock);
}

那麼,這個函數應該是怎麼調用的呢?答案就是在System Start類型驅動初始化完成,例如:

BOOLEAN
INIT_FUNCTION
NTAPI
IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
    //...
    /* Load boot start drivers */
    IopInitializeBootDrivers();

    /* Call back drivers that asked for */
    IopReinitializeBootDrivers();
    //..
     /* Initialize PnP root relations */
    IopEnumerateDevice(IopRootDeviceNode->PhysicalDeviceObject);
    //..
     /* Load services for devices found by PnP manager */
    IopInitializePnpServices(IopRootDeviceNode);

    /* Load system start drivers */
    IopInitializeSystemDrivers();
    PnpSystemInit = TRUE;

    /* Reinitialize drivers that requested it */
    IopReinitializeDrivers();
    //..
}

VOID
NTAPI
IopReinitializeDrivers(VOID)
{
    PDRIVER_REINIT_ITEM ReinitItem;
    PLIST_ENTRY Entry;

    /* Get the first entry and start looping */
    Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
                                        &DriverReinitListLock);
    while (Entry)
    {
        /* Get the item */
        ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);

        /* Increment reinitialization counter */
        ReinitItem->DriverObject->DriverExtension->Count++;

        /* Remove the device object flag */
        ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;

        /* Call the routine */
        ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
                                  ReinitItem->Context,
                                  ReinitItem->DriverObject->
                                  DriverExtension->Count);

        /* Free the entry */
        ExFreePool(Entry);

        /* Move to the next one */
        Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
                                            &DriverReinitListLock);
    }
}

這些回調函數都是在System Start類型驅動啓動之後再去調用的。

2.3 作用

這個函數的作用相比上面之前用途就稍大一些了,如果我們有啓動早的驅動,可能要去訪問WDM設備信息,例如讀取文件等等這些,那麼這個時候PNP設備管理器還沒有準備好,也就是說設備棧信息並沒有,那麼就可以用IoRegisterDriverReinitialization註冊回調函數,當PNP驅動加載完成之後再初始化。

3. 總結

如果我們的IoRegisterBootDriverReinitialization並不是在Boot型驅動中設置的呢?從目前的分析來看,那麼註冊的函數將無法調用。

如果我們IoRegisterDriverReinitialization在System Start驅動啓動之後呢?答案是DriverEntry調用完成之後就會調用初始化完成的函數:

NTSTATUS
FASTCALL
IopInitializeDriverModule(
    IN PDEVICE_NODE DeviceNode,
    IN PLDR_DATA_TABLE_ENTRY ModuleObject,
    IN PUNICODE_STRING ServiceName,
    IN BOOLEAN FileSystemDriver,
    OUT PDRIVER_OBJECT *DriverObject)
{
    //...
    Status = IopCreateDriver(DriverName.Length > 0 ? &DriverName : NULL,
                             DriverEntry,
                             &RegistryKey,
                             ServiceName,
                             ModuleObject,
                             &Driver);
    //...
    if (PnpSystemInit) IopReinitializeDrivers();
    //...
}

其中PnpSystemInit = TRUE;這個是在System Start驅動加載之後會設置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章