一般windows下驱动加载一是通过inf文件或者命令行sc命令动态加载驱动,二是通过系统启动的时候加载。那么windows内核是如何加载驱动呢?通过简要分析 ReactOS 系统源码可以看到大体的驱动加载过程。分析加载过程,可以加深对驱动程序的理解,我们也可以通过windbg下载系统函数断点 或者 hook驱动加载函数,监控我们的系统安装了哪些驱动程序,分析哪些驱动程序可能存在风险等。
我自己以系统启动session管理驱动为例子。
函数 BOOL InitSessionManager (HANDLE Children[])中有如下片段:
/* Load the kernel mode driver win32k.sys */
RtlInitUnicodeString (&CmdLineW,
L"\\SystemRoot\\system32\\drivers\\win32k.sys");
Status = NtLoadDriver (&CmdLineW);
如上,启动的系统驱动image文件路径是入口参数。调用NtLoadDriver函数(在device.c中)。
NTSTATUS
STDCALL
NtLoadDriver (
PUNICODE_STRING DriverServiceName
)
{
/* FIXME: this should lookup the filename from the registry and then call LdrLoadDriver */
return LdrLoadDriver (DriverServiceName);
}
NtLoadDrver调用LdrLoadDriver函数,LdrLoadDriver需要先加载模块文件,通过imgae路径,然后通过IO管理器,调用驱动程序的EntryPoint函数,即
通常情况下的DriverEntry函数。
NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename)
{
PMODULE_OBJECT ModuleObject;
ModuleObject = LdrLoadModule(Filename);
if (ModuleObject == 0)
{
return STATUS_UNSUCCESSFUL;
}
/* FIXME: should we dereference the ModuleObject here? */
return IoInitializeDriver(ModuleObject->EntryPoint);
}
如下IoInitializeDriver 函数,首先为PDRIVER_OBJECT 分配内存同时初始化,包括驱动类型和默认的派遣函数等。最后通过 Status = DriverEntry(DriverObject, NULL); 调用到驱动程序的入口,执行驱动程序的初始化操作或者注册PNP事件等。
NTSTATUS
IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry)
/*
* FUNCTION: Called to initalize a loaded driver
* ARGUMENTS:
*/
{
NTSTATUS Status;
PDRIVER_OBJECT DriverObject;
ULONG i;
DriverObject = ExAllocatePool(NonPagedPool,sizeof(DRIVER_OBJECT));
if (DriverObject == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
memset(DriverObject, 0, sizeof(DRIVER_OBJECT));
DriverObject->Type = InternalDriverType;
for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = IopDefaultDispatchFunction;
}
DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
Status = DriverEntry(DriverObject, NULL);
if (!NT_SUCCESS(Status))
{
ExFreePool(DriverObject);
return(Status);
}
return(Status);
}
至此,驱动程序基本初始化完成。