我是靠谱客的博主 文静航空,最近开发中收集的这篇文章主要介绍驱动与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

驱动程序处理使用以下部分或全部主要功能代码设置的 IRPIRP_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 通信方式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部