系统关闭时,会向注册SHUTDOWN事件的设备驱动发送IRP_MJ_SHUTDOWN事件。
NTSTATUS STDCALL
NtShutdownSystem(IN SHUTDOWN_ACTION Action)
{
if (Action > ShutdownPowerOff)
return STATUS_INVALID_PARAMETER;
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
ShutdownThreadMain,
(PVOID)Action);
}
VOID STDCALL
ShutdownThreadMain(PVOID Context)
{
IoShutdownRegisteredDevices();
}
VOID
NTAPI
IoShutdownRegisteredDevices(VOID)
{
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
&ShutdownListLock);
while (ListEntry)
{
/* Get the shutdown entry */
ShutdownEntry = CONTAINING_RECORD(ListEntry,
SHUTDOWN_ENTRY,
ShutdownList);
/* Get the attached device */
DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
/* Build the shutdown IRP and call the driver */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
DeviceObject,
NULL,
0,
NULL,
&Event,
&StatusBlock);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on the driver */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
/* Free the shutdown entry and reset the event */
ExFreePool(ShutdownEntry);
KeClearEvent(&Event);
/* Go to the next entry */
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
&ShutdownListLock);
}
}
调用Native API NtShutdownSystem时会遍历ShutdownListHead队列,取出每个元素,这个元素的结构中包含设备对象:
typedef struct _SHUTDOWN_ENTRY
{
LIST_ENTRY ShutdownList;
PDEVICE_OBJECT DeviceObject;
} SHUTDOWN_ENTRY, *PSHUTDOWN_ENTRY;
之后获得这个设备的设备栈深度并以此建立一个类型为IRP_MJ_SHUTDOWN的IRP请求包,以同步的方式发向设备栈的最上层设备。 设备栈中的设备驱动如果注册了IRP_MJ_SHUTDOWN事件那就调用相应的回调,如果没有注册就按默认的方式完成请求或者下发请求。
联系驱动程序注册IRP_MJ_SHUTDOWN事件和IoShutdownRegisteredDevices函数的是IoRegisterShutdownNotification---注册关机通知函数。这个函数新建SHUTDOWN_ENTRY结构,并填入设备对象,然后把SHUTDOWN_ENTRY结构挂入ShutdownListHead队列。
/*
* @implemented
*/
NTSTATUS
NTAPI
IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
{
PSHUTDOWN_ENTRY Entry;
/* Allocate the shutdown entry */
Entry = ExAllocatePoolWithTag(NonPagedPool,
sizeof(SHUTDOWN_ENTRY),
TAG_SHUTDOWN_ENTRY);
if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
Entry->DeviceObject = DeviceObject;
/* Insert it into the list */
ExInterlockedInsertHeadList(&ShutdownListHead,
&Entry->ShutdownList,
&ShutdownListLock);
DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
return STATUS_SUCCESS;
}
驱动入口以如下的方式注册关闭通知:
DriverEntry(pDriverObject,pRegistryPath)
{
pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = Shutdown;
IoRegisterShutdownNotification(pDriverObject);
}