Windows驱动之Reinitialize

文章目录

  • Windows驱动之Reinitialize
    • 1. IoRegisterBootDriverReinitialization
      • 1.1 函数声明
      • 1.2 原理
      • 1.3 作用
    • 2. IoRegisterDriverReinitialization
      • 2.1 声明
      • 2.2 原理
      • 2.3 作用
    • 3. 总结

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驱动加载之后会设置。

你可能感兴趣的:(Windows驱动开发)