自己跟着教程写的驱动,觉得重要的地方都标了注释
#include <ntddk.h>
#define device_name L"\\device\\myfirstdrv"
#define link_name L"\\dosdevices\\myfirstdrv"
#define ioctrl_base 0x8000
#define myioctrl_code(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN,ioctrl_base+i,METHOD_BUFFERED,FILE_ANY_ACCESS) //定义控制码,其中CTL_CODE是库里的宏
#define ctl_hello myioctrl_code(0)
#define ctl_print myioctrl_code(1)
#define ctl_bye myioctrl_code(2)
NTSTATUS dispathcommon(PDEVICE_OBJECT pobject, PIRP pirp)
{
pirp->IoStatus.Status = STATUS_SUCCESS;//告诉r3成功
pirp->IoStatus.Information = 0;//通讯的有效字节数
IoCompleteRequest(pirp, IO_NO_INCREMENT);//结束掉这个irp
return STATUS_SUCCESS;//告诉内核驱动对象io管理器成功
}
NTSTATUS dispathcreat(PDEVICE_OBJECT pobject, PIRP pirp)
{
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS dispathread(PDEVICE_OBJECT pobject, PIRP pirp)
{
PVOID preadbuffer = NULL; //参数初始化(buff地址,buff长度,irp栈地址)
ULONG ureadlength = 0;
PIO_STACK_LOCATION pstack = NULL;
ULONG umin = 0;
ULONG uhellostr = 0;
uhellostr = (wcslen(L"hello world") + 1)*sizeof(WCHAR);//计算字符串的长度sizeof保证可移植性
preadbuffer = pirp->AssociatedIrp.SystemBuffer; //从irp头部拿需要拷入的buff地址,因为是buff_io所以是systembuffer
pstack = IoGetCurrentIrpStackLocation(pirp); //从irp下部拿栈地址,read,write,iocontrol都在栈上的一个union中
ureadlength = pstack->Parameters.Read.Length; //从栈中拿buff的长度
umin = ureadlength > uhellostr ? uhellostr : ureadlength;//确定buff的实际长度,保证数据不会溢出
RtlCopyMemory(preadbuffer, L"hellow world", umin);//内核内存拷贝函数
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = umin;
IoCompleteRequest(pirp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS dispathwrite(PDEVICE_OBJECT pobject, PIRP pirp)
{
PVOID pwritebuffer = NULL; //参数初始化(irp中buff地址、长度、irp栈地址)
ULONG uwritelengh = 0;
PIO_STACK_LOCATION pstack = NULL;
PVOID pbuffer = NULL; //参数初始化(内核中buff地址)
pwritebuffer = pirp->AssociatedIrp.SystemBuffer;
pstack = IoGetCurrentIrpStackLocation(pirp);
uwritelengh = pstack->Parameters.Write.Length;
pbuffer = ExAllocatePoolWithTag(PagedPool, uwritelengh, 'tset');//在堆上往内核中分配内存:分页池(首选),源地址,源地址长度,标记(便于以后的测试,大小为4字节)
if (pbuffer == NULL) //内存分配失败的处理(空间不够)
{
pirp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
memset(pbuffer, 0, uwritelengh);//对新分配的内存全部填0初始化处理
RtlCopyMemory(pbuffer, pwritebuffer, uwritelengh);//r3的内容写入r0
ExFreePool(pbuffer);//因为实际什么都没做,所以释放内存
pbuffer = NULL;//防止野指针(因为函数快结束所以意义不大)
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information =uwritelengh;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS dispathioctrl(PDEVICE_OBJECT pobject, PIRP pirp)
{
ULONG uioctrlcode = 0; //通过查阅r3的deviceiocontrol函数,得知须用到5个参数:控制码、写入缓存地址、写入缓存长度、读取缓存地址、读取缓存长度
PVOID pinputbuff = NULL; //分别对它们进行初始化
PVOID poutputbuff = NULL;
ULONG uinputlength = 0;
ULONG uoutputlength = 0;
PIO_STACK_LOCATION pstack = NULL;
pinputbuff = poutputbuff = pirp->AssociatedIrp.SystemBuffer;
pstack = IoGetCurrentIrpStackLocation(pirp);
uinputlength = pstack->Parameters.DeviceIoControl.InputBufferLength; //控制码、地址长度都在irp栈里
uoutputlength = pstack->Parameters.DeviceIoControl.OutputBufferLength;
uioctrlcode = pstack->Parameters.DeviceIoControl.IoControlCode;
switch (uioctrlcode)
{
case ctl_hello:
DbgPrint("hellow iocontrol\n");
break;
case ctl_print:
DbgPrint("%ws\n",pinputbuff);
break;
case ctl_bye:
break;
DbgPrint("goodbye iocontrol\n");
default:
DbgPrint("unknow iocontrol\n");
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS dispathclose(PDEVICE_OBJECT pobject, PIRP pirp)
{
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS dispathclean(PDEVICE_OBJECT pobject, PIRP pirp)
{
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
void driverunload(PDRIVER_OBJECT pdriverobject)
{
UNICODE_STRING ulinkname = { 0 };
RtlInitUnicodeString(&ulinkname, link_name);
IoDeleteSymbolicLink(&ulinkname);
IoDeleteDevice(pdriverobject->DeviceObject);
DbgPrint("driver unload!");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pdriverobject,PUNICODE_STRING pregpath)
{
UNICODE_STRING udevicename = { 0 };//定义一个设备名
UNICODE_STRING ulinkname = { 0 };//定义一个符号链接名
NTSTATUS ntstatus = 0;//驱动里NTSTATUS返回0才为成功
PDEVICE_OBJECT pdeviceobject = NULL;
ULONG i = 0;
DbgPrint("driver load begin\n");//驱动中的打印函数
RtlInitUnicodeString(&udevicename,device_name);//设备名初始化
RtlInitUnicodeString(&ulinkname,link_name);//符号链接名初始化
ntstatus = IoCreateDevice(pdriverobject,
0, &udevicename,FILE_DEVICE_UNKNOWN,0,FALSE,&pdeviceobject);//创建设备对象,用来接收irp
//(驱动对象,设备扩展长度,设备类型,设备属性,驱动是否被独占,设备对象指针)
if (!NT_SUCCESS(ntstatus))//ntstatus<0的处理
{
DbgPrint("iocreatdevice faild:%x", ntstatus);
return ntstatus;
}
pdeviceobject->Flags |= DO_BUFFERED_IO;//最安全
ntstatus = IoCreateSymbolicLink(&ulinkname, &udevicename);//创建符号链接,为了驱动能被看到
if (!NT_SUCCESS(ntstatus))
{
IoDeleteDevice(pdeviceobject);//如果出错应把分配的资源删除,要删掉设备对象
DbgPrint("IoCreateSymbolicLink failed:%x",ntstatus);
return ntstatus;
}
for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION+1; i++)//将分发函数初始化
{
pdriverobject->MajorFunction[i] = dispathcommon;
}
pdriverobject->MajorFunction[IRP_MJ_CREATE] = dispathcreat;//分发函数的注册
pdriverobject->MajorFunction[IRP_MJ_READ] = dispathread;
pdriverobject->MajorFunction[IRP_MJ_WRITE] = dispathwrite;
pdriverobject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = dispathioctrl;
pdriverobject->MajorFunction[IRP_MJ_CLEANUP] = dispathclean;
pdriverobject->MajorFunction[IRP_MJ_CLOSE] = dispathclose;
pdriverobject->DriverUnload = driverunload;
DbgPrint("driver load ok!\n");
return STATUS_SUCCESS;
}