⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myport.c

📁 Device IO Control MyPort.zip
💻 C
字号:

#include <ntddk.h>
#include "MyPort.h"

// IOPM是65536个端口的位屏蔽矩阵,包含8192字节(8192 x 8 = 65536)
// 0 bit: 允许应用程序访问对应端口
// 1 bit: 禁止应用程序访问对应端口

#define IOPM_SIZE	8192

typedef UCHAR IOPM[IOPM_SIZE];

IOPM *pIOPM = NULL;

// 设备名(要求以UNICODE表示)
const WCHAR NameBuffer[] = L"\\Device\\MyPort";
const WCHAR DOSNameBuffer[] = L"\\DosDevices\\MyPort";

// 这是两个在ntoskrnl.exe中的未见文档的服务例程
// 没有现成的已经说明它们原型的头文件,我们自己声明
void Ke386SetIoAccessMap(int, IOPM *);
void Ke386IoSetAccessProcess(PEPROCESS, int);

// 函数原型预先说明
NTSTATUS MyPortDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
void MyPortUnload(IN PDRIVER_OBJECT DriverObject);


// 驱动程序入口,由系统自动调用,就像WIN32应用程序的WinMain
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	PDEVICE_OBJECT deviceObject;
	NTSTATUS status;
	UNICODE_STRING uniNameString, uniDOSString;

	// 为IOPM分配内存
	pIOPM = MmAllocateNonCachedMemory(sizeof(IOPM));
	if(pIOPM == 0)
	{
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	// IOPM全部初始化为0(允许访问所有端口)
	RtlZeroMemory(pIOPM, sizeof(IOPM));
    
	// 将IOPM加载到当前进程
	Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1);
    Ke386SetIoAccessMap(1, pIOPM);

	// 指定驱动名字
	RtlInitUnicodeString(&uniNameString, NameBuffer);
	RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);

	// 创建设备
	status = IoCreateDevice(DriverObject, 0,
					&uniNameString,
					FILE_DEVICE_MYPORT,
					0, FALSE, &deviceObject);

	if(!NT_SUCCESS(status))
	{
		return status;
	}

	// 创建WIN32应用程序需要的符号连接
	status = IoCreateSymbolicLink (&uniDOSString, &uniNameString);

	if (!NT_SUCCESS(status))
	{
		return status;
	}

	// 指定驱动程序有关操作的模块入口(函数指针)
	// 涉及以下两个模块:MyPortDispatch和MyPortUnload
    DriverObject->MajorFunction[IRP_MJ_CREATE]         =
    DriverObject->MajorFunction[IRP_MJ_CLOSE]          =
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyPortDispatch;
	DriverObject->DriverUnload = MyPortUnload;

    return STATUS_SUCCESS;
}


// IRP处理模块
NTSTATUS MyPortDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
  PIO_STACK_LOCATION IrpStack;
  ULONG              dwInputBufferLength;
  ULONG              dwOutputBufferLength;
  ULONG              dwIoControlCode;
  PULONG               pvIOBuffer;
  NTSTATUS           ntStatus;

  // 填充几个默认值
  Irp->IoStatus.Status = STATUS_SUCCESS;	// 返回状态
  Irp->IoStatus.Information = 0;			// 输出长度
  
  IrpStack = IoGetCurrentIrpStackLocation(Irp);

  // Get the pointer to the input/output buffer and it's length

  // 输入输出共用的缓冲区
  // 因为我们在IOCTL中指定了METHOD_BUFFERED,
  pvIOBuffer = Irp->AssociatedIrp.SystemBuffer;

	switch (IrpStack->MajorFunction)
	{
		case IRP_MJ_CREATE:		// 与WIN32应用程序中的CreateFile对应
			break;
    
		case IRP_MJ_CLOSE:		// 与WIN32应用程序中的CloseHandle对应
			break;
		
		case IRP_MJ_DEVICE_CONTROL:		// 与WIN32应用程序中的DeviceIoControl对应
			dwIoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
			switch (dwIoControlCode)
			{
				// 我们约定,缓冲区共两个DWORD,第一个DWORD为端口,第二个DWORD为数据
				// 一般做法是专门定义一个结构,此处简单化处理了
				case IOCTL_MYPORT_READ_BYTE:		// 从端口读字节
					pvIOBuffer[1] = _inp(pvIOBuffer[0]);
					Irp->IoStatus.Information = 8;		// 输出长度为8
					break;
				case IOCTL_MYPORT_WRITE_BYTE:		// 写字节到端口
					_outp(pvIOBuffer[0], pvIOBuffer[1]);
					break;
				default:		// 不支持的IOCTL
					Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
			}
	}

	ntStatus = Irp->IoStatus.Status;

	IoCompleteRequest (Irp, IO_NO_INCREMENT);

	return ntStatus;
}

// 删除驱动
void MyPortUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING uniDOSString;

	if(pIOPM)
	{
		// 释放IOPM占用的空间
		MmFreeNonCachedMemory(pIOPM, sizeof(IOPM));
	}

	RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);

	// 删除符号连接和设备
	IoDeleteSymbolicLink (&uniDOSString);
	IoDeleteDevice(DriverObject->DeviceObject);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -