我是靠谱客的博主 文静航空,最近开发中收集的这篇文章主要介绍驱动与R3的通信IRP_MJ_READ 通信IRP_MJ_DEVICE_CONTROL 通信方式,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
kd> dt PDRIVER_OBJECT
Wdf01000!PDRIVER_OBJECT
Ptr32 +0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Flags : Uint4B
+0x00c DriverStart : Ptr32 Void
+0x010 DriverSize : Uint4B
+0x014 DriverSection : Ptr32 Void
+0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING
+0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
+0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH
+0x02c DriverInit : Ptr32 long
+0x030 DriverStartIo : Ptr32 void
+0x034 DriverUnload : Ptr32 void
+0x038 MajorFunction : [28] Ptr32 long //由驱动程序的DispatchXxx例程的入口点数组组成的调度表。数组的索引值是IRP_MJ_ XXX代表每个值IRP主功能码。每个驱动必须在此数组中设置的入口点IRP_MJ_ XXX请求驱动程序句柄
kd> dt PIO_STACK_LOCATION
Wdf01000!PIO_STACK_LOCATION
Ptr32 +0x000 MajorFunction : UChar//指示要执行的 I/O 操作类型的IRP 主要功能代码。
+0x001 MinorFunction : UChar//MajorFunction的子函数代码
+0x002 Flags : UChar
+0x003 Control : UChar
+0x004 Parameters : _IO_STACK_LOCATION::<unnamed-type-Parameters>//取决于MajorFunction和MinorFunction 中包含的主要和次要 IRP 函数代码值的联合
+0x014 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x018 FileObject : Ptr32 _FILE_OBJECT
+0x01c CompletionRoutine : Ptr32 long
+0x020 Context : Ptr32 Void
驱动程序处理使用以下部分或全部主要功能代码设置的 IRP:
IRP_MJ_CLEANUP
IRP_MJ_CLOSE
IRP_MJ_CREATE//创造
IRP_MJ_DEVICE_CONTROL//设备控制
IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_INTERNAL_DEVICE_CONTROL//设备控制
IRP_MJ_PNP
IRP_MJ_POWER
IRP_MJ_QUERY_INFORMATION//查询文件
IRP_MJ_READ//读
IRP_MJ_SET_INFORMATION//设置文件
IRP_MJ_SHUTDOWN
IRP_MJ_SYSTEM_CONTROL
IRP_MJ_WRITE//写
kd> dt _IRP
win32k!_IRP
+0x000 Type : Int2B
+0x002 Size : Uint2B
+0x004 MdlAddress : Ptr32 _MDL//指向一个内存描述符表(MDL)
+0x008 Flags : Uint4B//包含一些对驱动程序只读的标志
+0x00c AssociatedIrp : <unnamed-tag>
+0x010 ThreadListEntry : _LIST_ENTRY
+0x018 IoStatus : _IO_STATUS_BLOCK//包含两个域的结构,驱动程序在最终完成请求时设置这个结构,IoStatus.Status域将收到一个NTSTATUS代码,而IoStatus.Information的类型为ULONG_PTR
+0x020 RequestorMode : Char//UserMode或KernelMode,指定原始I/O请求的来源
+0x021 PendingReturned : UChar
+0x022 StackCount : Char
+0x023 CurrentLocation : Char
+0x024 Cancel : UChar
+0x025 CancelIrql : UChar
+0x026 ApcEnvironment : Char
+0x027 AllocationFlags : UChar
+0x028 UserIosb : Ptr32 _IO_STATUS_BLOCK
+0x02c UserEvent : Ptr32 _KEVENT
+0x030 Overlay : <unnamed-tag>
+0x038 CancelRoutine : Ptr32 void
+0x03c UserBuffer : Ptr32 Void
+0x040 Tail : <unnamed-tag>
IRP_MJ_READ 通信
驱动
#include <ntifs.h>
#define DEVICE_NAME L"\Device\wangliang"//设备名
#define SYM_NAME L"\??\wangliang"
NTSTATUS DefDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;//完成请求时设置这个结构
IoCompleteRequest(Irp, 0);//调用方已完成所有I/O请求处理操作,并将给定的 IRP 返回给 I/O 管理器
/*
void IofCompleteRequest(
PIRP Irp,//指向要完成的 IRP 的指针
CCHAR PriorityBoost
);
*/
return STATUS_SUCCESS;
}
NTSTATUS ReadDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
DbgBreakPoint();
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);//返回一个指向IO_STACK_LOCATION结构的指针
LARGE_INTEGER ByteOffset = ioStack->Parameters.Read.ByteOffset;//指定读多少个字节
int Length = ioStack->Parameters.Read.Length;//要读取的数据的长度(以字节为单位)。如果读取操作成功,则在Irp->IoStatus指向的IO_STATUS_BLOCK结构体的Information成员中返回读取的字节数。
int* xxx = Irp->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过程的一部分。对于读请求,设备驱动程序把读出的数据填到这个缓冲区,然后I/O管理器再把缓冲区的内容复制到用户模式缓冲区。
*xxx = 100;
Irp->IoStatus.Information = Length;
Irp->IoStatus.Status = STATUS_SUCCESS;//驱动程序在最终完成请求时设置这个结构,IoStatus.Status域将收到一个NTSTATUS代码,而IoStatus.Information的类型为ULONG_PTR
IoCompleteRequest(Irp, 0);
return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
UNICODE_STRING symName = { 0 };
RtlInitUnicodeString(&symName, SYM_NAME);
IoDeleteSymbolicLink(&symName);//删除符号链接
IoDeleteDevice(pDriver->DeviceObject);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
UNICODE_STRING unName = { 0 };
RtlInitUnicodeString(&unName, DEVICE_NAME);//初始化一个Unicode的字符串,设备名
UNICODE_STRING symName = { 0 };
RtlInitUnicodeString(&symName, SYM_NAME);//函数名
PDEVICE_OBJECT pDevice = NULL;
NTSTATUS status = IoCreateDevice(pDriver, 0, &unName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);//创建一个驱动设备使用的设备对象
/*
NTSTATUS IoCreateDevice(
PDRIVER_OBJECT DriverObject,//指向调用者的驱动程序对象的指针
ULONG DeviceExtensionSize,//指定要为设备对象的设备扩展分配的驱动程序确定的字节数
PUNICODE_STRING DeviceName,//命名设备对象
DEVICE_TYPE DeviceType,//指定设备类型的值
ULONG DeviceCharacteristics,//提供有关驱动程序设备的附加信息 多数驱动程序为此参数指定 FILE_DEVICE_SECURE_OPEN
BOOLEAN Exclusive,//指定设备对象是否代表独占设备。多数驱动程序将此值设置为FALSE
PDEVICE_OBJECT *DeviceObject//指向变量的指针,该变量接收指向新创建的DEVICE_OBJECT结构的指针
);*/
if (!NT_SUCCESS(status))
{
DbgPrint("[db]:%xrn", status);
//DbgPrintEx(77, 0, "");
return status;
}
status = IoCreateSymbolicLink(&symName, &unName);//设备名和用户的可见名之间创建符号链接
/*
NTSTATUS IoCreateSymbolicLink(
PUNICODE_STRING SymbolicLinkName,//用户的可见名
PUNICODE_STRING DeviceName//指向设备对象名称
);*/
if (!NT_SUCCESS(status))
{
IoDeleteDevice(pDevice);
DbgPrint("[db]:%xrn", status);
return status;
}
pDevice->Flags &= ~DO_DEVICE_INITIALIZING;//干掉这个位 符号链接->设备对象->驱动对象->功能函数
pDevice->Flags |= DO_BUFFERED_IO;
pDriver->MajorFunction[IRP_MJ_CREATE] = DefDispatch;//设置回调函数
pDriver->MajorFunction[IRP_MJ_CLOSE] = DefDispatch;
pDriver->MajorFunction[IRP_MJ_READ] = ReadDispatch;
pDriver->DriverUnload = DriverUnload;
return status;
}
R3端的程序
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
#define SYM_NAME "\\.\wangliang"
int main()
{
HANDLE hDevice = CreateFileA(SYM_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
/*
HANDLE CreateFileA(
LPCSTR lpFileName,//要创建或打开的文件或设备的名称
DWORD dwDesiredAccess,//权限
DWORD dwShareMode,//请求的文件或设备的共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes,//指向SECURITY_ATTRIBUTES 结构的指针,该结构包含两个独立但相关的数据成员:一个可选的安全描述符,以及一个确定返回的句柄是否可以被子进程继承的布尔值。此参数可以为NULL。如果此参数为NULL,则CreateFile返回的句柄 不能由应用程序可能创建的任何子进程继承,并且与返回的句柄关联的文件或设备获得默认安全描述符。
DWORD dwCreationDisposition,//对存在或不存在的文件或设备采取的操作。
DWORD dwFlagsAndAttributes,//文件或设备属性和标志,FILE_ATTRIBUTE_NORMAL是文件最常见的默认值。
HANDLE hTemplateFile//具有GENERIC_READ访问权限的模板文件的有效句柄。模板文件为正在创建的文件提供文件属性和扩展属性。此参数可以为NULL。
);*/
int x = 500;
DWORD p = 0;
ReadFile(hDevice, &x, 4, &p, NULL);//从指定的文件或输入/输出 (I/O) 设备读取数据
/*
BOOL ReadFile(
HANDLE hFile,//设备句柄
LPVOID lpBuffer,//指向接收从文件或设备读取的数据的缓冲区的指针。
DWORD nNumberOfBytesToRead,//要读取的最大字节数。
LPDWORD lpNumberOfBytesRead,/一个指向接收使用同步hFile参数时读取的字节数的变量的指针
LPOVERLAPPED lpOverlapped
);*/
CloseHandle(hDevice);
printf("%drn", x);
system("pause");
return 0;
}
这是不开驱动的情况
开了驱动
成功通信
IRP_MJ_DEVICE_CONTROL 通信
驱动
#include <ntifs.h>
#define DEVICE_NAME L"\Device\wangliang"//设备名
#define SYM_NAME L"\??\wangliang"
#define CODE_CTR_INDEX 0x800//为以上设备类型定义一个设备的唯一标识功能号。CODE的唯一标识功能号用十六进制表示,转换为十进制后的有效范围是:0 - 2047是保留给微软; 代码2048 - 4095是为OEM和IHV保留。其它功能代码定义大于4095。
#define TEST CTL_CODE(FILE_DEVICE_UNKNOWN,CODE_CTR_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)//用于创建一个唯一的32位系统I/O控制代码
/*
void CTL_CODE(
DeviceType,//设备类型,高16位(16-31位)
Function,//包含功能函数值
Method,//包含有关如何为 I/O 和 FS 控件传递缓冲区的方法代码
Access//访问限制,14-15位
);
( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
*/
NTSTATUS DefDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;//完成请求时设置这个结构
IoCompleteRequest(Irp, 0);//调用方已完成所有I/O请求处理操作,并将给定的 IRP 返回给 I/O 管理器
/*
void IofCompleteRequest(
PIRP Irp,//指向要完成的 IRP 的指针
CCHAR PriorityBoost
);
*/
return STATUS_SUCCESS;
}
NTSTATUS Dispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);//返回一个指向IO_STACK_LOCATION结构的指针
DbgBreakPoint();
if (ioStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)//判断类型是不是这个
{
int size = ioStack->Parameters.DeviceIoControl.InputBufferLength;
int OutputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG IoControlCode = ioStack->Parameters.DeviceIoControl.IoControlCode;
switch (IoControlCode)//判断控制代码
{
case TEST:
{
int* x = (int*)Irp->AssociatedIrp.SystemBuffer;
DbgPrint("[db]:-------%x----------rn", *x);
}
break;
}
}
Irp->IoStatus.Status = STATUS_SUCCESS;//设置成功
IoCompleteRequest(Irp, 0);
return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
UNICODE_STRING symName = { 0 };
RtlInitUnicodeString(&symName, SYM_NAME);
IoDeleteSymbolicLink(&symName);//删除符号链接
IoDeleteDevice(pDriver->DeviceObject);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
UNICODE_STRING unName = { 0 };
RtlInitUnicodeString(&unName, DEVICE_NAME);//初始化一个Unicode的字符串,设备名
UNICODE_STRING symName = { 0 };
RtlInitUnicodeString(&symName, SYM_NAME);//函数名
PDEVICE_OBJECT pDevice = NULL;
NTSTATUS status = IoCreateDevice(pDriver, 0, &unName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);//创建一个驱动设备使用的设备对象
/*
NTSTATUS IoCreateDevice(
PDRIVER_OBJECT DriverObject,//指向调用者的驱动程序对象的指针
ULONG DeviceExtensionSize,//指定要为设备对象的设备扩展分配的驱动程序确定的字节数
PUNICODE_STRING DeviceName,//命名设备对象
DEVICE_TYPE DeviceType,//指定设备类型的值
ULONG DeviceCharacteristics,//提供有关驱动程序设备的附加信息 多数驱动程序为此参数指定 FILE_DEVICE_SECURE_OPEN
BOOLEAN Exclusive,//指定设备对象是否代表独占设备。多数驱动程序将此值设置为FALSE
PDEVICE_OBJECT *DeviceObject//指向变量的指针,该变量接收指向新创建的DEVICE_OBJECT结构的指针
);*/
if (!NT_SUCCESS(status))
{
DbgPrint("[db]:%xrn", status);
//DbgPrintEx(77, 0, "");
return status;
}
status = IoCreateSymbolicLink(&symName, &unName);//设备名和用户的可见名之间创建符号链接
/*
NTSTATUS IoCreateSymbolicLink(
PUNICODE_STRING SymbolicLinkName,//用户的可见名
PUNICODE_STRING DeviceName//指向设备对象名称
);*/
if (!NT_SUCCESS(status))
{
IoDeleteDevice(pDevice);
DbgPrint("[db]:%xrn", status);
return status;
}
pDevice->Flags &= ~DO_DEVICE_INITIALIZING;//干掉这个位 符号链接->设备对象->驱动对象->功能函数
pDevice->Flags |= DO_BUFFERED_IO;
pDriver->MajorFunction[IRP_MJ_CREATE] = DefDispatch;//设置回调函数
pDriver->MajorFunction[IRP_MJ_CLOSE] = DefDispatch;
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch;
//"\device\null"
//有些游戏 加跳板可以,有些游戏追跳板 BE//jmp 我的函数 E8 E9 mov rax,0x11345678 push 0x123465678
//遍历驱动 找到驱动路径,打开驱动文件,对比代码段
//我之前lock文件, WIN7 走是HOOK WIN10走是WIN10
pDriver->DriverUnload = DriverUnload;
return status;
}
接收
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
#define SYM_NAME "\\.\wangliang"
#define CODE_CTR_INDEX 0x800//为以上设备类型定义一个设备的唯一标识功能号。CODE的唯一标识功能号用十六进制表示,转换为十进制后的有效范围是:0 - 2047是保留给微软; 代码2048 - 4095是为OEM和IHV保留。其它功能代码定义大于4095。
#define TEST CTL_CODE(FILE_DEVICE_UNKNOWN,CODE_CTR_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)//用于创建一个唯一的32位系统I/O控制代码
int main()
{
HANDLE hDevice = CreateFileA(SYM_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
/*
HANDLE CreateFileA(
LPCSTR lpFileName,//要创建或打开的文件或设备的名称
DWORD dwDesiredAccess,//权限
DWORD dwShareMode,//请求的文件或设备的共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes,//指向SECURITY_ATTRIBUTES 结构的指针,该结构包含两个独立但相关的数据成员:一个可选的安全描述符,以及一个确定返回的句柄是否可以被子进程继承的布尔值。此参数可以为NULL。如果此参数为NULL,则CreateFile返回的句柄 不能由应用程序可能创建的任何子进程继承,并且与返回的句柄关联的文件或设备获得默认安全描述符。
DWORD dwCreationDisposition,//对存在或不存在的文件或设备采取的操作。
DWORD dwFlagsAndAttributes,//文件或设备属性和标志,FILE_ATTRIBUTE_NORMAL是文件最常见的默认值。
HANDLE hTemplateFile//具有GENERIC_READ访问权限的模板文件的有效句柄。模板文件为正在创建的文件提供文件属性和扩展属性。此参数可以为NULL。
);*/
int x = 100;
DWORD p = 0;
BOOL b = DeviceIoControl(hDevice, TEST, x, 4, NULL, NULL , &p, NULL);//直接向指定的设备驱动程序发送控制代码,使相应的设备执行相应的操作。
/*
BOOL DeviceIoControl(
HANDLE hDevice,//要在其上执行操作的设备的句柄
DWORD dwIoControlCode,//操作的控制代码。此值标识要执行的特定操作以及执行该操作的设备类型。
LPVOID lpInBuffer,//指向包含执行操作所需数据的输入缓冲区的指针
DWORD nInBufferSize,//输入缓冲区的大小
LPVOID lpOutBuffer,//指向输出缓冲区的指针
DWORD nOutBufferSize,//输出缓冲区的大小
LPDWORD lpBytesReturned,//一个指向变量的指针
LPOVERLAPPED lpOverlapped
);*/
CloseHandle(hDevice);
printf("%drn", b);
system("pause");
return 0;
}
第一个是ReadFile实现的通信,这个是DeviceIoControl实现的通信
方式
METHOD_BUFFERED:直接把值传入内核中去
METHOD_IN_DIRECT/METHOD_OUT_DIRECT:把物理页映射到内核地址中,修改哪一边都一起修改
METHOD_NEITHER:直接操作地址
最后
以上就是文静航空为你收集整理的驱动与R3的通信IRP_MJ_READ 通信IRP_MJ_DEVICE_CONTROL 通信方式的全部内容,希望文章能够帮你解决驱动与R3的通信IRP_MJ_READ 通信IRP_MJ_DEVICE_CONTROL 通信方式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复