文章目錄
Windows驅動之Reinitialize
Windows驅動下面提供了兩個Reinitialize:
IoRegisterBootDriverReinitialization
.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);
}
}
這個流程比較明顯了:
IopInitializeBootDrivers
加載完成Boot驅動。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驅動加載之後會設置。