Windows驱动下面提供了两个Reinitialize:
IoRegisterBootDriverReinitialization
.IoRegisterDriverReinitialization
.按照MSDN的描述,这两个函数可以提供驱动重新初始化的机会;但是重新初始化是什么呢?这两个函数又有什么区别呢?本文来探讨一下这些问题。
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
,并在合适的时间调用这个函数。
我们看一下这个函数的实现过程:
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
注册的函数。这个函数有什么作用呢?有一种情况好处是比较明显的。例如我们要做相关的初始化,但是这个初始化依赖其他的Boot型驱动,那么我们可以利用IoRegisterBootDriverReinitialization
注册一个重新初始化的函数,等待其他BOOT驱动加载完成之后再初始化。
有了上面的分析经验之后,分析这个函数就简单多了,下面我们看下这个函数的流程。
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
)
{ ... }
这个函数的注册和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类型驱动启动之后再去调用的。
这个函数的作用相比上面之前用途就稍大一些了,如果我们有启动早的驱动,可能要去访问WDM设备信息,例如读取文件等等这些,那么这个时候PNP设备管理器还没有准备好,也就是说设备栈信息并没有,那么就可以用IoRegisterDriverReinitialization
注册回调函数,当PNP驱动加载完成之后再初始化。
如果我们的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驱动加载之后会设置。