作者: 诚信网安--小麒麟 出处:51CTO.com 2008-03-07 14:06
一.驱动编写
随着对windows系统的深入研究,越来越多的内核方面的知识被挖掘出来了,今天我们讨论下如何写一个简单的驱动,并使用现在比较新的windbg调试器进行调试。首先写驱动要对驱动有一个比较全面的认识。
一个简单的驱动一般有以下几个部分组成:
1,一个入口点(DriverEntry):用于创建设备对象及符号连接,以及其它初使化操作,如分配池内存等.
2,一个出口(DriverUnload):删除符号连接与设备对象,并释放已经分配的各种资源,如池内存等
3,几个派遣例程:用于响应Ring3程序的请求及其它驱动事件,并做相关处理。
我用一个挂钩SSDT的简单驱动来详细介绍如何写一个驱动和驱动的结构。
在驱动入口点,我们需要使用RtlInitUnicodeString来初始化一个UnicodeString结构:
例如:
RtlInitUnicodeString(&DeviceName,NT_DEVICE_NAME);
RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
NT_DEVICE_NAME和 DOS_DEVICE_NAME,往往在头文件中用define进行定义。
(这里有一点要注意如:
#define NT_DEVICE_NAME L"//Device//HookSSDT"
这里的L并不是说明”//Device//HookSSDT”是个Unicode字符串,只是表明他是一个宽字符,这里很多人都搞混。)
我们初始化设备名后就可以调用IoCreateDevice创建一个设备对象了,这里我给大家一个小例子:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING theRegistryPath)
{
NTSTATUS ntStatus;
UNICODE_STRING DeviceName;
UNICODE_STRING DeviceLinkString;
PDEVICE_OBJECT pDeviceObject;
RtlInitUnicodeString(&DeviceName,NT_DEVICE_NAME);
RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
ntStatus = IoCreateDevice(DriverObject,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDeviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&DeviceLinkString,&DeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DevCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DispatchDeviceControl;
DriverObject->DriverUnload=OnUnload;
DbgPrint("驱动已经加载");
return STATUS_SUCCESS;
}
这里IoCreateSymbolicLink用来创建一个符号链接以便在应用程序中可以方便的打开驱动对象,与其通讯。
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DevCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
这里是典型的派遣例程,他把IRP的处理过程交给我们的派遣例程去执行,其实我们常常要做的是把IRP交给下一层的驱动处理。
在这里的DispatchDeviceControl中我们处理由应用程序传来的控制码,首先我们要了解IRP和IRP堆栈的结构: