实战练习
1.创建设备对象并使用
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\MyDevice"
#define DEVICE_SYMBOL_NAME L"\\DosDevices\\MyDeviceSym"
UNICODE_STRING deviceName = RTL_CONSTANT_STRING(DEVICE_NAME);
UNICODE_STRING symName = RTL_CONSTANT_STRING(DEVICE_SYMBOL_NAME);
NTSTATUS OnDeviceCreate(DEVICE_OBJECT *pDevice, IRP *pIrp);
NTSTATUS OnDeviceRead(DEVICE_OBJECT *pDevice, IRP *pIrp);
NTSTATUS OnDeviceWrite(DEVICE_OBJECT *pDevice, IRP *pIrp);
NTSTATUS OnDeviceClose(DEVICE_OBJECT *pDevice, IRP *pIrp);
VOID OnDriverUnload(PDRIVER_OBJECT pDriver)
{
IoDeleteSymbolicLink(&symName);
pDriver->DeviceObject;
IoDeleteDevice(pDriver->DeviceObject);
KdPrint(("项目被卸载\n"));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
reg_path;
NTSTATUS status = STATUS_SUCCESS;
pDriver->DriverUnload = OnDriverUnload;
PDEVICE_OBJECT pDevice = NULL;
status = IoCreateDevice(
pDriver,
0,
&deviceName,
FILE_DEVICE_UNKNOWN,
0,
0,
&pDevice);
if (!NT_SUCCESS(status))
{
KdPrint(("创建新设备失败,错误码:%08x\n", status));
return status;
}
pDevice->Flags |= DO_DIRECT_IO;
IoCreateSymbolicLink(
&symName,
&deviceName
);
pDriver->MajorFunction[IRP_MJ_CREATE] = OnDeviceCreate;
pDriver->MajorFunction[IRP_MJ_READ] = OnDeviceRead;
pDriver->MajorFunction[IRP_MJ_WRITE] = OnDeviceWrite;
pDriver->MajorFunction[IRP_MJ_CLOSE] = OnDeviceClose;
return status;
}
NTSTATUS OnDeviceCreate(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
pDevice;
KdPrint(("设备对象被创建了\n"));
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceRead(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
pDevice;
KdPrint(("设备被读取了\n"));
PCHAR pBuff = NULL;
pIrp->AssociatedIrp.SystemBuffer;
pIrp->MdlAddress;
pIrp->UserBuffer;
if (pIrp->MdlAddress!=NULL)
{
pBuff = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, 0);
}
else if (pIrp->AssociatedIrp.SystemBuffer!=NULL)
{
pBuff = pIrp->AssociatedIrp.SystemBuffer;
}
else if (pIrp->UserBuffer!=NULL)
{
pBuff = NULL;
}
if (pBuff!=NULL)
{
RtlCopyMemory(pBuff, "来自内核的一段字符串", 21);
pIrp->IoStatus.Information = 21;
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceWrite(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
pDevice;
KdPrint(("设备被写入了\n"));
char* pBuffer = NULL;
if (pIrp->MdlAddress!=NULL)
{
pBuffer = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, 0);
}
else if (pIrp->AssociatedIrp.SystemBuffer!=NULL)
{
pBuffer = pIrp->AssociatedIrp.SystemBuffer;
}
else
{
pBuffer = NULL;
}
if (pBuffer!=NULL)
{
KdPrint(("[内核]:从用户层传入的数据--[%s]\n", pBuffer));
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceClose(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
pDevice;
KdPrint(("设备对象被释放了\n"));
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
int main()
{
HANDLE hDevice = CreateFile(
L"\\\\.\\MyDeviceSym",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hDevice==INVALID_HANDLE_VALUE)
{
printf("[3环]:设备打开失败,%d\n", GetLastError());
system("pause");
return 0;
}
char buff[] = "这是一个来自用户层的字符串";
DWORD dwRelSize = 0;
WriteFile(hDevice, buff, sizeof(buff), &dwRelSize, 0);
char str[0x10] = {};
ReadFile(hDevice, str, 0x10, &dwRelSize, 0);
printf("[3环]:获取到的字符串--[%s]\n", str);
CloseHandle(hDevice);
system("pause");
return 0;
}
2.使用DeviceIoContral进行内核通讯
- 使用
ReadFile
和WriteFile
进行内核通讯时有个缺点就是只能读/写,不能传递额外的命令。 - 这种情况下我们可以通过
DeviceIoContral
来实现,在用户层调用这个函数后,驱动对象的派遣函数IRP_MJ_DEVICE_CONTROL
会被调用,在内核层的派遣函数中,通过IO_STACK_COMPLATE.Parameters.DeviceIoControl.IoControlCode
来得到用户层传入进来的控制码。
R3代码
#pragma once
#include <Windows.h>
#define MYCTRLCODE(code) CTL_CODE(FILE_DEVICE_UNKNOWN,0x800+(code),METHOD_BUFFERED,FILE_ANY_ACCESS)
typedef enum _MyCtrlCode
{
readProcessMemory = MYCTRLCODE(0),
writeProcessMemory= MYCTRLCODE(1),
}MyCtrlCode;
typedef struct _ProcessInfo {
ULONG dwPid;
void* address;
char buff[1000];
int buffSize;
}ProcessInfo, *PProcessInfo;
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include "Data.h"
int main()
{
HANDLE hDevice = CreateFile(L"\\\\.\\MyDeviceSymCtrl", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hDevice==INVALID_HANDLE_VALUE)
{
printf("[3环程序]打开设备失败: %d\n", GetLastError());
system("pause");
return 0;
}
DWORD dwPid = 1234;
char buff[0x50];
DWORD dwRelSize = 0;
DeviceIoControl(
hDevice,
readProcessMemory,
&dwPid,
sizeof(DWORD),
buff,
sizeof(buff),
&dwRelSize,
NULL);
printf("发送[writeProcessMemory]类型数据完毕,实际完成字节数:%d,得到数据:%s\n", dwRelSize, buff);
ProcessInfo proInfo = { 1234,(void*)0x400000,"123456",7 };
DeviceIoControl(
hDevice,
writeProcessMemory,
&proInfo,
sizeof(proInfo),
buff,
sizeof(buff),
&dwRelSize,
NULL);
printf("发送[readProcessMemory]类型数据完毕,实际完成字节数:%d,得到数据:%s\n", dwRelSize, buff);
CloseHandle(hDevice);
system("pause");
return 0;
}
R0代码
- Data.h,和3环的应用程序区别在于宏
MYCTRL_CODE
的定义,这里为了避免重定义我直接使用了简单的数据进行了替换
#pragma once
#include <ntddk.h>
#define MYCTRLCODE(code) CTL_CODE(FILE_DEVICE_UNKNOWN,0x800+(code),METHOD_BUFFERED,FILE_ANY_ACCESS)
typedef enum _MyCtrlCode
{
readProcessMemory = MYCTRLCODE(0),
writeProcessMemory = MYCTRLCODE(1),
}MyCtrlCode;
typedef struct _ProcessInfo {
ULONG dwPid;
void* address;
char buff[1000];
int buffSize;
}ProcessInfo, *PProcessInfo;
#include <ntddk.h>
#include "Data.h"
#define DEVICE_NAME L"\\Device\\MyDeviceCtrl"
#define DEVICE_SYMBOL_NAME L"\\DosDevices\\MyDeviceSymCtrl"
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(DEVICE_NAME);
UNICODE_STRING DeviceSymName = RTL_CONSTANT_STRING(DEVICE_SYMBOL_NAME);
NTSTATUS OnDeviceClose(DEVICE_OBJECT *pDevice, IRP *pIrp);
NTSTATUS OnDeviceControl(DEVICE_OBJECT *pDevice, IRP *pIrp);
NTSTATUS OnDeviceCreate(DEVICE_OBJECT *pDevice, IRP *pIrp);
NTSTATUS OnDeviceIoCtrlReadProcessMemory(PDEVICE_OBJECT pDevice, PIRP pIrp);
NTSTATUS OnDeviceIoCtrlWriteProcessMemory(PDEVICE_OBJECT pDevice, PIRP pIrp);
typedef struct _DeviceIoCtrlHandler {
ULONG ctrlCode;
NTSTATUS(*callback)(PDEVICE_OBJECT pDevice, PIRP pIrp);
}DeviceIoCtrlHandler,*PDeviceIoCtrlHandler;
DeviceIoCtrlHandler g_handler[] =
{
{readProcessMemory,OnDeviceIoCtrlReadProcessMemory},
{writeProcessMemory,OnDeviceIoCtrlWriteProcessMemory},
};
PCHAR g_buff = NULL;
VOID OnDriverUnload(PDRIVER_OBJECT pDriver)
{
DbgBreakPoint();
pDriver;
IoDeleteSymbolicLink(&DeviceSymName);
pDriver->DeviceObject;
IoDeleteDevice(pDriver->DeviceObject);
KdPrint(("驱动已被卸载\n"));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath)
{
pPath;
NTSTATUS status = STATUS_SUCCESS;
pDriver->DriverUnload = OnDriverUnload;
PDEVICE_OBJECT pDevice = NULL;
status = IoCreateDevice(
pDriver,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
0,
&pDevice);
if (!NT_SUCCESS(status))
{
KdPrint(("创建设备失败,错误码:%08x\n", status));
return status;
}
pDevice->Flags |= DO_BUFFERED_IO;
IoCreateSymbolicLink(&DeviceSymName,&DeviceName);
pDriver->MajorFunction[IRP_MJ_CREATE] = OnDeviceCreate;
pDriver->MajorFunction[IRP_MJ_CLOSE] = OnDeviceClose;
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = OnDeviceControl;
return status;
}
NTSTATUS OnDeviceCreate(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
pDevice;
KdPrint(("设备对象已创建\n"));
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceClose(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
pDevice;
KdPrint(("设备对象已关闭\n"));
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceControl(DEVICE_OBJECT *pDevice, IRP *pIrp)
{
DbgBreakPoint();
pDevice;
if (pIrp->MdlAddress!=NULL)
{
g_buff =(PCHAR) MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, 0);
}
else if (pIrp->AssociatedIrp.SystemBuffer!=NULL)
{
g_buff = (PCHAR)pIrp->AssociatedIrp.SystemBuffer;
}
else
{
g_buff = NULL;
}
IO_STACK_LOCATION* pIoStack = IoGetCurrentIrpStackLocation(pIrp);
ULONG uInputLen = pIoStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG uOutputLen = pIoStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG uCtrlCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;
KdPrint(("控制码:%08x 输入长度:%d 输出长度:%d\n", uCtrlCode, uInputLen, uOutputLen));
int i = 0;
while (g_handler[i].callback!=NULL)
{
if (g_handler[i].ctrlCode == uCtrlCode)
{
g_handler[i].callback(pDevice, pIrp);
break;
}
++i;
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceIoCtrlReadProcessMemory(PDEVICE_OBJECT pDevice, PIRP pIrp)
{
pDevice;
DbgBreakPoint();
PULONG pPid = (PULONG)g_buff;
KdPrint(("[内核层]:读取进程内存的请求\n"));
KdPrint(("读取到的PID=%d\n", pPid));
RtlCopyMemory(g_buff, "hello World", 12);
pIrp->IoStatus.Information = 12;
return STATUS_SUCCESS;
}
NTSTATUS OnDeviceIoCtrlWriteProcessMemory(PDEVICE_OBJECT pDevice, PIRP pIrp)
{
pDevice;
DbgBreakPoint();
PProcessInfo pProInfo = (PProcessInfo)g_buff;
KdPrint(("[内核]写进程内存的请求\n"));
KdPrint(("pid=%d address=%p buff=%s buffSize=%d\n",
pProInfo->dwPid,
pProInfo->address,
pProInfo->buff,
pProInfo->buffSize));
RtlCopyMemory(g_buff, "已经接收到", 11);
pIrp->IoStatus.Information = 11;
return STATUS_SUCCESS;
}