当前位置:编程学习 > 网站相关 >>

简单驱动编写与windbg调试

来自51cto。

作者: 诚信永安

一.驱动编写

随着对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堆栈的结构:

I/O请求包数据结构

\

MdlAddress(PMDL)域指向一个内存描述符表(MDL),该表描述了一个与该请求关联的用户模式缓冲区。如果顶级设备对象的Flags域为DO_DIRECT_IO,则I/O管理器为IRP_MJ_READ或IRP_MJ_WRITE请求创建这个MDL。如果一个IRP_MJ_DEVICE_CONTROL请求的控制代码指定METHOD_IN_DIRECT或METHOD_OUT_DIRECT操作方式,则I/O管理器为该请求使用的输出缓冲区创建一个MDL。MDL本身用于描述用户模式虚拟缓冲区,但它同时也含有该缓冲区锁定内存页的物理地址。为了访问用户模式缓冲区,驱动程序必须做一点额外工作。

Flags(ULONG)域包含一些对驱动程序只读的标志。但这些标志与WDM驱动程序无关。

AssociatedIrp(union)域是一个三指针联合。其中,与WDM驱动程序相关的指针是AssociatedIrp.SystemBuffer。 SystemBuffer指针指向一个数据缓冲区,该缓冲区位于内核模式的非分页内存中。对于IRP_MJ_READ和IRP_MJ_WRITE操作,如果顶级设备指定DO_BUFFERED_IO标志,则I/O管理器就创建这个数据缓冲区。对于IRP_MJ_DEVICE_CONTROL操作,如果I/O控制功能代码指出需要缓冲区,则I/O管理器就创建这个数据缓冲区。I/O管理器把用户模式程序发送给驱动程序的数据复制到这个缓冲区,这也是创建IRP过程的一部分。这些数据可以是与WriteFile调用有关的数据,或者是DeviceIoControl调用中所谓的输入数据。对于读请求,设备驱动程序把读出的数据填到这个缓冲区,然后I/O管理器再把缓冲区的内容复制到用户模式缓冲区。对于指定了METHOD_BUFFERED的I/O控制操作,驱动程序把所谓的输出数据放到这个缓冲区,然后I/O管理器再把数据复制到用户模式的输出缓冲区。
oStatus(IO_STATUS_BLOCK)是一个仅包含两个域的结构,驱动程序在最终完成请求时设置这个结构。IoStatus.Status域将收到一个NTSTATUS代码,而IoStatus.Information的类型为ULONG_PTR,它将收到一个信息值,该信息值的确切含义要取决于具体的IRP类型和请求完成的状态。Information域的一个公认用法是用于保存数据传输操作,如IRP_MJ_READ,的流量总计。某些PnP请求把这个域作为指向另外一个结构的指针,这个结构通常包含查询请求的结果。

RequestorMode将等于一个枚举常量UserMode或KernelMode,指定原始I/O请求的来源。驱动程序有时需要查看这个值来决定是否要信任某些参数。

PendingReturned(BOOLEAN)如果为TRUE,则表明处理该IRP的最低级派遣例程返回了STATUS_PENDING。完成例程通过参考该域来避免自己与派遣例程间的潜在竞争。

Cancel(BOOLEAN)如果为TRUE,则表明IoCancelIrp已被调用,该函数用于取消这个请求。如果为FALSE,则表明没有调用IoCancelIrp函数。CancelIrql(KIRQL)是一个IQL值,表明那个专用的取消自旋锁是在这个IRQL上获取的。当你在取消例程中释放自旋锁时应参考这个域。

CancelRoutine(PDRIVER_CANCEL)是驱动程序取消例程的地址。你应该使用IoSetCancelRoutine函数设置这个域而不是直接修改该域。

UserBuffer(PVOID) 对于METHOD_NEITHER方式的IRP_MJ_DEVICE_CONTROL请求,该域包含输出缓冲区的用户模式虚拟地址。该域还用于保存读写请求缓冲区的用户模式虚拟地址,但指定了DO_BUFFERED_IO或DO_DIRECT_IO标志的驱动程序,其读写例程通常不需要访问这个域。当处理一个METHOD_NEITHER控制操作时,驱动程序能用这个地址创建自己的MDL。

I/O堆栈

任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用(见图)。堆栈单元中包含该IRP的类型代码和参数信息以及完成函数的地址。图中显示了堆栈单元的结构。

\

\

MajorFunction(UCHAR)是该IRP的主功能码。这个代码应该为类似IRP_MJ_READ一样的值,并与驱动程序对象中MajorFunction表的某个派遣函数指针相对应。如果该代码存在于某个特殊驱动程序的I/O堆栈单元中,它有可能一开始是,例如IRP_MJ_READ,而后被驱动程序转换成其它代码,并沿着驱动程序堆栈发送到低层驱动程序。

MinorFunction(UCHAR)是该IRP的副功能码。它进一步指出该IRP属于哪个

补充:综合编程 , 安全编程 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,