64位驱动开发之读写驱动程序IRP_MJ_READ和IRP_MJ_WRITE的IO
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 64位驱动开发之读写驱动程序IRP_MJ_READ和IRP_MJ_WRITE的IO
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
64位驱动开发之读写驱动程序IRP_MJ_READ和IRP_MJ_WRITE的IO
文章目录
一、64位驱动开发之读写驱动程序IRP_MJ_READ和IRP_MJ_WRITE的IO
MFC读写代码
这边用了两个按钮
具体实现步骤如下:
第一步:在用户层(MFC工程项目里)选“资源视图”,在对话框里双击“IRP_MJ_READ”按钮和IRP_MJ_WRITE按钮,在里面添加如下代码:
void CD00910MFCDlg::OnBnClickedButton1IrpMjWrite()
{
// TODO: 在此添加控件通知处理程序代码
char 输入缓冲区[] = "yjx:R3 WriteFile写测试";
DWORD len = 0;//返回实际写如字节集数量
BOOL ret = WriteFile(DeviceHandle, 输入缓冲区, sizeof(输入缓冲区), &len, 0);
}
void CD00910MFCDlg::OnBnClickedButton1IrpMjRead()
{
// TODO: 在此添加控件通知处理程序代码
char 输出缓冲区[512] = { 0 };
DWORD len = 0;//返回实际写如字节集数量
BOOL ret = ReadFile(DeviceHandle, 输出缓冲区, sizeof(输出缓冲区), &len/*返回实际读取大小*/, 0);
char buf[256];
sprintf_s(buf, "ret=%d 输入缓冲区=%s,len=%d yjx", ret, 输出缓冲区,len);
OutputDebugStringA(buf);
}
二、驱动读写代码
第二步:在驱动层写相应的操作代码,这里我们可以把读写取数据的代码单独写到一个函数里,代码如下:
//READ WRITE
DriverObject->MajorFunction[IRP_MJ_READ] = IRP_CALL; //ReadFile ReadFileEx
DriverObject->MajorFunction[IRP_MJ_WRITE] = IRP_CALL; //WriteFile NtWriteFile ZwWriteFile
完整代码
//加载驱动时被调用
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
RegistryPath;
DriverObject->DriverUnload = DriverUnload;//注册卸载例程-回调函数
DriverObject->MajorFunction[IRP_MJ_CREATE] = IRP_CALL;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = IRP_CALL;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_CALL;
//READ WRITE
DriverObject->MajorFunction[IRP_MJ_READ] = IRP_CALL; //ReadFile ReadFileEx
DriverObject->MajorFunction[IRP_MJ_WRITE] = IRP_CALL; //WriteFile NtWriteFile ZwWriteFile
CreateDevice(DriverObject);//创建驱动设备
KdPrint(("yjx:进入DriverEntry入口点 DriverObject=%p 行号=%d\n", DriverObject, __LINE__));//Debug
//KdPrint(("yjx:RegistryPath=%s\n, RegistryPath->Buffer"));//多字节字符集
KdPrint(("yjx:RegistryPath=%ws\n", RegistryPath->Buffer));//Unicode 宽字符
return 0;//返回成功
}ZwWriteFile
2.然后在 IRP_CALL函数里直接调用,这里为了不影响上一节课的写入功能,加了case IRP_MJ_READ: case IRP_MJ_WRITE: 。代码如下:
代码如下(示例):
case IRP_MJ_READ:
{
char* 指针1 = (char*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
char* 指针2 = (char*)pirp->MdlAddress;//和IRP有关的系统缓冲区
char* 指针3 = (char*)pirp->UserBuffer;//和IRP有关的系统缓冲区
KdPrint(("yjx:SYS IRP_MJ_READ (%p,%p,%p)", 指针1, 指针2, 指针3));
char 返回字符串[] = "SYS IRP_MJ_READ返回的字符串";
ULONG 长度 = sizeof(返回字符串);
if (指针3 && irpStackL->Parameters.Read.Length >= 长度)
{
//irpStackL->Parameters.Read.Length;
irpStackL->Parameters.Read.Length;
RtlCopyMemory(指针3, 返回字符串, 长度);
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 长度;//strlen//对应ReadFile 第4个参数 len
IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并且不增加优先级
KdPrint(("yjx:IRP_MJ_READ 离开派遣函数"));
return STATUS_SUCCESS;//返回0,表示成功
break;
}
case IRP_MJ_WRITE://DevieIoControl 输入数据
{
char* 指针1 = (char*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
char* 指针2 = (char*)pirp->MdlAddress;//和IRP有关的系统缓冲区
char* 指针3 = (char*)pirp->UserBuffer;//和IRP有关的系统缓冲区
KdPrint(("yjx:SYS IRP_MJ_WRITE (%p,%p,%p)", 指针1, 指针2, 指针3));
KdPrint(("yjx:SYS IRP_MJ_WRITE (%s,%s,%s)", 指针1, 指针2, 指针3));
break;
}
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturned
IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并且不增加优先级
KdPrint(("yjx:离开派遣函数"));
return STATUS_SUCCESS;//返回0,表示成功
完整代码
NTSTATUS IRP_CALL(PDEVICE_OBJECT device, PIRP pirp)
{
device;
KdPrint(("yjx:进入派遣函数"));
PIO_STACK_LOCATION irpStackL;
irpStackL = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的参数
switch (irpStackL->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL://DeviceIoControl
{
UINT32 控制码 = irpStackL->Parameters.DeviceIoControl.IoControlCode;
if (控制码 == 读测试)
{
IRP_IO_读测试(pirp);
return STATUS_SUCCESS;
}
else if (控制码 == 写测试)
{
char* 缓冲区 = (char*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
KdPrint(("R0 yjx:用户层调用了DeviceIoControl 控制码=%X", 控制码));
KdPrint(("R0 yjx:用户层调用了DeviceIoControl 控制码=%X 缓冲区=%s", 控制码, 缓冲区));
}
else if (控制码 == 读写测试)
{
IRP_IO_读写测试(pirp);
return STATUS_SUCCESS;
}
break;
}
case IRP_MJ_CREATE://CreateFile
{
KdPrint(("yjx:用户层调用了CreateFile"));
break;
}
case IRP_MJ_CLOSE://CloseHandle
{
KdPrint(("yjx:用户层调用了CloseHandle"));
break;
}
case IRP_MJ_READ:
{
char* 指针1 = (char*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
char* 指针2 = (char*)pirp->MdlAddress;//和IRP有关的系统缓冲区
char* 指针3 = (char*)pirp->UserBuffer;//和IRP有关的系统缓冲区
KdPrint(("yjx:SYS IRP_MJ_READ (%p,%p,%p)", 指针1, 指针2, 指针3));
char 返回字符串[] = "SYS IRP_MJ_READ返回的字符串";
ULONG 长度 = sizeof(返回字符串);
if (指针3 && irpStackL->Parameters.Read.Length >= 长度)
{
//irpStackL->Parameters.Read.Length;
irpStackL->Parameters.Read.Length;
RtlCopyMemory(指针3, 返回字符串, 长度);
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 长度;//strlen//对应ReadFile 第4个参数 len
IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并且不增加优先级
KdPrint(("yjx:IRP_MJ_READ 离开派遣函数"));
return STATUS_SUCCESS;//返回0,表示成功
break;
}
case IRP_MJ_WRITE://DevieIoControl 输入数据
{
char* 指针1 = (char*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
char* 指针2 = (char*)pirp->MdlAddress;//和IRP有关的系统缓冲区
char* 指针3 = (char*)pirp->UserBuffer;//和IRP有关的系统缓冲区
KdPrint(("yjx:SYS IRP_MJ_WRITE (%p,%p,%p)", 指针1, 指针2, 指针3));
KdPrint(("yjx:SYS IRP_MJ_WRITE (%s,%s,%s)", 指针1, 指针2, 指针3));
break;
}
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturned
IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并且不增加优先级
KdPrint(("yjx:离开派遣函数"));
return STATUS_SUCCESS;//返回0,表示成功
}
##3.虚拟机调试结果
总结
提示:这里对文章进行总结:
以上就是今天要讲的内容。