驱动开发
环境搭建
vs 2019
sdk
wdk
创建项目
①带框架的(初学者不合适)
新建项目>Visual C++>Windows Drivers>Kernel Mode Driver
②不带框架的
新建项目>Visual C++>Windows Drivers>Kernel Mode Driver Empty
删除inf文件
禁用inf 配置属性>Inf2Cat>Run Inf2Cat 否
删除Driver files下的文件,KMDFDriver.inf
编译生成驱动的目标平台和操作系统版本 配置属性>Driver settings
项目新建cpp文件,名称为.c
调试信息 DebugVIew软件
capture勾选
capture kernel、enable verbose kernel output、capture events
可以设置过滤
安装、加载、卸载驱动
使用cmd
#安装驱动
sc create sample type=kernel binPath=c:\sample.sys
#加载驱动
sc start sample
#卸载驱动
sc stop sample
#删除驱动
sc delete sample
使用DriverMonitor软件
安装驱动
加载驱动
卸载驱动
删除驱动
打开测试签名模式(方便测试)
bcdedit /set nointegritychecks on
bcdedit /set testsigning on
重启生效
启动调式模式(windbg双机调式需要开启)
bcdedit /copy {current} /d "win7 x64 debug for windbg"
如果是win10就把win7改为win10
运行之后查看msconfig引导多出win7 x64 debug for windbg,
可以修改超时时间
对应的高级选项中选中调式
可以设为默认
驱动入口函数和卸载驱动函数
#include <ntddk.h>
//没有卸载例程,加载驱动后是没法卸载驱动的
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) {
KdPrint(("Driver Unloaded driverobj=%p, line=%d\n", DriverObject, __LINE__));
}
//驱动入口函数——DriverEntry
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
KdPrint(("my first driver load driverobj=%p, line=%d\n", DriverObject, __LINE__));
//unicode宽字符
KdPrint(("RegistryPath=%ws\n", RegistryPath->Buffer));
DriverObject->DriverUnload = DriverUnload;
return 0;
}
IRP例程注册
IRP(I/O Request Package)是输入输出请求包的简称
操作系统会将上层应用程序的文件相关的I/O函数转为IRP类型,这些IRP再被传送到驱动程序的派遣函数中。
常用IRP
| 名称 (IRP类型) | 描述 | 调用者 |
|---|---|---|
| IRP_MJ_CREATE | 请求一个句柄 | CreateFile |
| IRP_MJ_CLOSE | 关闭句柄 | CloseHandle |
| IRP_MJ_READ | 从设备得到数据 | ReadFile |
| IRP_MJ_WRITE | 传送数据到设备 | WriteFile |
| IRP_MJ_DEVICE_CONTROL | 控制操作(利用IOCTL宏) | DeviceIoControl |
使用
派遣函数
DriverObject->MajorFunction是指针数组,为不同类型的IRP注册回调,实际可以用用一个函数处理不同类型的IRP
//驱动入口函数——DriverEntry
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = IRP_CALL; //CreateFile
DriverObject->MajorFunction[IRP_MJ_CLOSE] = IRP_CALL; //卸载驱动CloseHandle
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_CALL; //DeviceControl
KdPrint(("my first driver load driverobj=%p, line=%d\n", DriverObject, __LINE__));
//unicode宽字符
KdPrint(("RegistryPath=%ws\n", RegistryPath->Buffer));
return 0;
}
//参数设备对象指针
NTSTATUS IRP_CALL(IN PDEVICE_OBJECT device, PIRP pirp) {
KdPrint(("%p: enter paiqian fun\n", device));
PIO_STACK_LOCATION irpStackL;
irpStackL = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的参数
switch (irpStackL->MajorFunction)
{
case IRP_MJ_CREATE:
KdPrint(("user call CreateFile\n"));
break;
case IRP_MJ_CLOSE:
KdPrint(("user call CloseHandle\n"));
break;
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturened
IoCompleteRequest(pirp, IO_NO_INCREMENT);//条用房已完成所有I/O请求处理操作,并且不增加优先级
KdPrint(("leave paiqian fun\n"));
return STATUS_SUCCESS;
}
驱动设备和符号链接
符号链接是给用户层r3层 CreateFile等接口使用用的
//创建驱动设备
NTSTATUS
IoCreateDevice(
_In_ PDRIVER_OBJECT DriverObject,
_In_ ULONG DeviceExtensionSize,
_In_opt_ PUNICODE_STRING DeviceName,
_In_ DEVICE_TYPE DeviceType,
_In_ ULONG DeviceCharacteristics,
_In_ BOOLEAN Exclusive,
_Outptr_result_nullonfailure_
_At_(*DeviceObject,
__drv_allocatesMem(Mem)
_When_((((_In_function_class_(DRIVER_INITIALIZE))
||(_In_function_class_(DRIVER_DISPATCH)))),
__drv_aliasesMem))
PDEVICE_OBJECT *DeviceObject
);
//删除驱动设备
VOID
IoDeleteDevice(
_In_ __drv_freesMem(Mem) PDEVICE_OBJECT DeviceObject
);
//创建符号链接
NTSTATUS
IoCreateSymbolicLink(
_In_ PUNICODE_STRING SymbolicLinkName,
_In_ PUNICODE_STRING DeviceName
);
//删除符号链接
NTSTATUS
IoDeleteSymbolicLink(
_In_ PUNICODE_STRING SymbolicLinkName
);
//创建设备对象函数
status = IoCreateDevice(pdriver, sizeof(pdriver->DriverExtension), &MyDriver, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device);
//删除驱动设备
IoDeleteDevice(pdriver->DeviceObject);
//创建符号链接
UNICODE_STRING uzSymbolName; //符号链接名字
RtlInitUnicodeString(&uzSymbolName, SymbolicLink); //CreateFile
status = IoCreateSymbolicLink(&uzSymbolName, &MyDriver);
//删除符号链接
IoDeleteSymbolicLink(&uzSymbolName);
创建(放在DriverEntry中)
CreateDevice(DriverObject);//创建驱动设备
#define DriverName L"\\DEVICE\\CHYDriver"
#define SymbolicLink L"\\??\\CHYDriver"
NTSTATUS CreateDevice(PDRIVER_OBJECT pdriver)
{
NTSTATUS status;
UNICODE_STRING MyDriver;
PDEVICE_OBJECT device; //用于存放设备对象
RtlInitUnicodeString(&MyDriver, DriverName); //驱动设备名字
status = IoCreateDevice(pdriver, sizeof(pdriver->DriverExtension), &MyDriver, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device);
if (status == STATUS_SUCCESS)
{
KdPrint(("chy: 驱动设备对象创建成功\n"));
//创建符号链接
UNICODE_STRING uzSymbolName; //符号链接名字
RtlInitUnicodeString(&uzSymbolName, SymbolicLink); //CreateFile
status = IoCreateSymbolicLink(&uzSymbolName, &MyDriver);
if (status == STATUS_SUCCESS)
{
KdPrint(("chy: 创建符号链接%wZ成功\n", &uzSymbolName));
}
else
{
KdPrint(("chy: 创建符号链接%wZ失败 status=%X\n", &uzSymbolName, status));
}
}
else
{
KdPrint(("chy: 驱动设备对象创建失败,删除设备\n"));
if(device)
{
IoDeleteDevice(device);
}
}
}
删除(放在DriverUnload中)
DeleteDevice(DriverObject);//删除驱动设备
void DeleteDevice(PDRIVER_OBJECT pdriver)
{
KdPrint(("chy: 进入DeleteDevice\n"));
if (pdriver->DeviceObject)
{
//删除符号链接
UNICODE_STRING uzSymbolName; //符号链接名字
RtlInitUnicodeString(&uzSymbolName, SymbolicLink);
KdPrint(("chy: 删除符号链接\n"));
IoDeleteSymbolicLink(&uzSymbolName);
KdPrint(("chy: 删除驱动设备\n"));
IoDeleteDevice(pdriver->DeviceObject);
//删除设备对象
}
KdPrint(("chy: 退出DeleteDevice\n"));
}
IRP_MJ_DEVICE_CONTROL通信
用户层调用DeviceIoControl函数触发
通过ctlType判断当前用户层调用的是读还是写、读写。然后进行处理。
int ctlType = irpStackL->Parameters.DeviceIoControl.IoControlCode;
数据存储:pirp->AssociatedIrp.SystemBuffer,可根据需求强制转换
#define WriteData CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define ReadData CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define ReadWriteData CTL_CODE(FILE_DEVICE_UNKNOWN,0x805,METHOD_BUFFERED,FILE_ANY_ACCESS)
void IRP_IO_READ(PIRP pirp)
{
char* data = (char*)pirp->AssociatedIrp.SystemBuffer;
char redata[] = "Hello World Read你好";
unsigned int length = sizeof(redata);
memcpy_s(data, length, redata, length);
KdPrint(("chy: 发送数据%s 长度%d\n", redata, length));
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = length;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturened
IoCompleteRequest(pirp, IO_NO_INCREMENT);//条用房已完成所有I/O请求处理操作,并且不增加优先级
}
void IRP_IO_READWRITE(PIRP pirp)
{
int* data = (int*)pirp->AssociatedIrp.SystemBuffer;
// 读取数据
int param1 = data[0];
int param2 = data[1];
int redata = param1 + param2;
unsigned int length = sizeof(redata);
data[0] = redata;
KdPrint(("chy: 发送数据%d\n", redata));
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = length;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturened
IoCompleteRequest(pirp, IO_NO_INCREMENT);//条用房已完成所有I/O请求处理操作,并且不增加优先级
}
case IRP_MJ_DEVICE_CONTROL:
KdPrint(("chy: user call DeviceIoControl\n"));
int ctlType = irpStackL->Parameters.DeviceIoControl.IoControlCode;
if (ctlType == WriteData)
{
char* data = (char*)pirp->AssociatedIrp.SystemBuffer;
KdPrint(("chy: 收到数据%s\n", data));
}
else if (ctlType == ReadData)
{
IRP_IO_READ(pirp);
return STATUS_SUCCESS;
}
else if (ctlType == ReadWriteData)
{
IRP_IO_READWRITE(pirp);
return STATUS_SUCCESS;
}
break;
IRP_MJ_READ通信
用户层调用ReadFile函数触发
数据存储: pirp->UserBuffer 可根据需求强制转换
case IRP_MJ_READ:
KdPrint(("chy: user call ReadFile\n"));
char* buff = (char*)pirp->UserBuffer;
//rpStackL->Parameters.Read.Length 即为用户层传送得缓冲区长度,如果要发送得超过这个长度就有问题
KdPrint(("chy: r3 缓冲区长度 %d\n", irpStackL->Parameters.Read.Length));
char redata[] = "Hello World Read你好";
unsigned int length = sizeof(redata);
if (buff && irpStackL->Parameters.Read.Length > length)
{
memcpy_s(buff, length, redata, length);
}
KdPrint(("chy: 发送数据%s 长度%d\n", redata, length));
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = length;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturened
IoCompleteRequest(pirp, IO_NO_INCREMENT);//条用房已完成所有I/O请求处理操作,并且不增加优先级
return STATUS_SUCCESS;
break;
IRP_MJ_WRITE通信
用户层调用WriteFile函数触发
数据存储: pirp->UserBuffer 可根据需求强制转换
case IRP_MJ_WRITE:
KdPrint(("chy: user call WriteFile\n"));
char* str = (char*)pirp->UserBuffer;
KdPrint(("chy: 接受数据 %s\n", str));
break;
保护进程(阻止结束进程和读写进程内存等)
阻止用户层调用OpenProcess指定权限阻止结束进程和读写进程内存等
通过 ObRegisterCallbacks 实现
ObRegisterCallbacks在调用在NtOpenProcess调用时进行权限的过滤(应用层调用OpenProcess)
HANDLE OpenProcess(
DWORD dwDesiredAccess, // access flag
BOOL bInheritHandle, // handle inheritance flag
DWORD dwProcessId // process identifier
);
比如
清除(终止进程)PROCESS_TERMINATE,
(对进程内存读写)PROCESS_VM_OPERATION 等操作。
权限定义
#pragma once
#define PROCESS_TERMINATE (0x0001)
#define PROCESS_CREATE_THREAD (0x0002)
#define PROCESS_SET_SESSIONID (0x0004)
#define PROCESS_VM_OPERATION (0x0008)
#define PROCESS_VM_READ (0x0010)
#define PROCESS_VM_WRITE (0x0020)
#define PROCESS_DUP_HANDLE (0x0040)
#define PROCESS_CREATE_PROCESS (0x0080)
#define PROCESS_SET_QUOTA (0x0100)
#define PROCESS_SET_INFORMATION (0x0200)
#define PROCESS_QUERY_INFORMATION (0x0400)
#define PROCESS_SUSPEND_RESUME (0x0800)
#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
回调进行权限的过滤
OB_PREOP_CALLBACK_STATUS my_pre_callback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
UNREFERENCED_PARAMETER(RegistrationContext);
KdPrint(("chy: sys pEPROCESS=%p \n", OperationInformation->Object));
if (OperationInformation->KernelHandle)
{
//内核创建
}
else
{
//用户层
ACCESS_MASK old权限 = OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess;
ACCESS_MASK new = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
//移除进程内存读取权限
old权限 &= ~PROCESS_VM_READ;
//移除进程内存写入权限
old权限 &= ~PROCESS_VM_WRITE;
//移除进程结束权限
old权限 &= ~PROCESS_TERMINATE;
//返回修改的权限
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = old权限;
KdPrint(("chy: old权限=%X, new权限=%X \n", new, old权限));
}
return OB_PREOP_SUCCESS;
}
加载保护
放入DriverEntry中,驱动加载及启动保护
HANDLE gs_HandleCallback = NULL; //存放返回的句柄
void LoadProtect()
{
OB_CALLBACK_REGISTRATION ob_callback_reg = {0};
OB_OPERATION_REGISTRATION ob_operation_reg= {0};
//设置ob_callback_reg
RtlInitUnicodeString(&ob_callback_reg.Altitude, L"321000");
ob_callback_reg.RegistrationContext = NULL;
ob_callback_reg.Version = OB_FLT_REGISTRATION_VERSION;//OBGetFilterVersion()
ob_callback_reg.OperationRegistrationCount = 1; //只注册一个回调
ob_callback_reg.OperationRegistration = &ob_operation_reg;
//设置ob_operation_reg
ob_operation_reg.ObjectType = PsProcessType; // 指定三个值之一PsProcessType,PsThreadType,ExDesktopObjectType 进程句柄被操作时,还是线程句柄被操作时,还是窗口句柄被操作时
ob_operation_reg.Operations = OB_OPERATION_HANDLE_CREATE;
ob_operation_reg.PostOperation = NULL;
ob_operation_reg.PreOperation = my_pre_callback;
ObRegisterCallbacks(&ob_callback_reg, &gs_HandleCallback);// /INTEGRITYCHECK
KdPrint(("chy: 安装内存保护gs_HandleCallback=%p \n", gs_HandleCallback));
}
卸载保护
放入卸载驱动中,驱动卸载及卸载保护
void UnLoadProtect()
{
if(gs_HandleCallback)
ObUnRegisterCallbacks(gs_HandleCallback);
KdPrint(("chy: 卸载内存保护gs_HandleCallback=%p \n", gs_HandleCallback));
}
保护指定PID和特定名字的进程
#include <ntifs.h>
#include <ntddk.h>
void AddProjectPid(unsigned int);
void RemoveProjectPid(unsigned int);
void ClearProjectPid();
BOOLEAN IsProjectpid(unsigned int);
char* PsGetProcessImageFileName(PEPROCESS);
char* GetProcessName(HANDLE ProcessId);
unsigned int pids[256] = { 0 }; //保存被保护PID的数组
char* GetProcessName(HANDLE ProcessId)
{
NTSTATUS st = STATUS_UNSUCCESSFUL;
PEPROCESS ProcessObj = NULL;
const char* imagename = NULL;
st = PsLookupProcessByProcessId(ProcessId, &ProcessObj);
if (NT_SUCCESS(st))
{
imagename = PsGetProcessImageFileName(ProcessObj);
ObfDereferenceObject(ProcessObj);
}
return imagename;
}
void AddProjectPid(unsigned int pid)
{
DbgBreakPoint;
for (unsigned int i = 0; i < 256; i++)
{
if (pids[i] == 0 || pids[i] == pid)
{
pids[i] = pid;
KdPrint(("chy: 添加受保护的进程PID=%d \n", pid));
break;
}
}
}
void RemoveProjectPid(unsigned int pid)
{
for (unsigned int i = 0; i < 256; i++)
{
if (pids[i] == pid)
{
pids[i] = 0;
KdPrint(("chy: 移除受保护的进程PID=%d \n", pid));
}
}
}
void ClearProjectPid()
{
memset(pids, 0 , sizeof(pids));
}
BOOLEAN IsProjectpid(unsigned int pid)
{
if (pid == 0)
return FALSE;
for (unsigned int i = 0; i < 256; i++)
{
if (pids[i] == pid)
{
return TRUE;
}
}
return FALSE;
}
OB_PREOP_CALLBACK_STATUS my_pre_callback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
UNREFERENCED_PARAMETER(RegistrationContext);
if (OperationInformation->KernelHandle)
{
//内核创建
}
else
{
HANDLE curPID = PsGetCurrentProcessId();//获取当前进程PID
char* processName = PsGetProcessImageFileName(PsGetCurrentProcess()); // 15个有效字符包括0
HANDLE targetPID = PsGetProcessId((PEPROCESS)OperationInformation->Object);
char* targetName = GetProcessName(targetPID); // 15个有效字符包括0
if (IsProjectpid(targetPID))
{
//用户层
ACCESS_MASK old权限 = OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess;
ACCESS_MASK new = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
//移除进程内存读取权限
old权限 &= ~PROCESS_VM_READ;
//移除进程内存写入权限
old权限 &= ~PROCESS_VM_WRITE;
//移除进程结束权限
old权限 &= ~PROCESS_TERMINATE;
//返回修改的权限
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = old权限;
KdPrint(("chy: 原权限=%X,修改后权限=%X, 进程名 %s, 进程pid %d, 被保护进程名 %s, 进程pid %d \n", new, old权限, processName, curPID, targetName, targetPID));
}
}
return OB_PREOP_SUCCESS;
}
WinDbg双机调式
本地机器和虚拟机串口连接
虚拟机windows设置
msconfig->引导->高级选项设置选中调式,调式端口根据虚拟机添加的串行端口号选择com
虚拟机软件设置
添加串行端口(注意端口后面的数字),使用命名的管道 \.\pipe\chy
本地机器连接
WinDbg->File->Kernel Debugging->COM->Port 设置为管道名,波特率跟windows一致
常用命令
窗口点击调式指令
命令
g 继续
t 指令单步执行
加断点
bu 驱动名!函数名
代码里加DbgBreakPoint宏
Windbug双机调试 驱动时KDPrint、DbgPrint不能打印的问题解决
注册表HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/中 新建key,名字为Debug Print Filter ,DWORD value ,值8
重启生效
突破保护进程跨进程读内存
1、ExAllocatePool(NonPagedPool, Length); 分配内核空间
2、KeStackAttachProcess((PRKPROCESS)Process, &apc_state); 进入目标进程内存空间
3、RtlCopyMemory(tmpBuf_Kernel, Address, Length); 拷贝进程内存到内核空间
4、KeUnstackDetachProcess(&apc_state); 分离目标进程,恢复环境
5、RtlCopyMemory(Buffer, tmpBuf_Kernel, Length); 拷贝内核空间到r3地址
6、ExFreePool(tmpBuf_Kernel); 释放内核空间
BOOLEAN KReadProcessMemory(PEPROCESS Process, PVOID Address, PVOID Buffer, UINT32 Length);
int ReadProcessMemoryForPid(UINT32 dwPid, PVOID pBase, PVOID ipBuffer, UINT32 nSize);
BOOLEAN KReadProcessMemory(PEPROCESS Process, PVOID Address, PVOID Buffer, UINT32 Length)
{
KAPC_STATE apc_state;
RtlZeroMemory(&apc_state, sizeof(KAPC_STATE));
//在所有进程通用
PVOID tmpBuf_Kernel = ExAllocatePool(NonPagedPool, Length);
//Ke
KdPrint(("chy: 附加到目标进程 Address=%p, Buffer=%p \n", Address, Buffer));;
//进入目标进程内存空间
//进程R3的Buffer 在目标地址里不存在,故不能访问
KeStackAttachProcess((PRKPROCESS)Process, &apc_state);
//判断目标地址是否可以访问
BOOLEAN dwRet = MmIsAddressValid(Address);
KdPrint(("chy: dwRet=%d \n", dwRet));
if (dwRet)
{
KdPrint(("chy: 目标地址合法可访问 Address=%p, Buffer=%p \n", Address, Buffer));;
RtlCopyMemory(tmpBuf_Kernel, Address, Length);
}
else
{
KdPrint(("chy: MmIsAddressValid Error Lines=%d, \n", __LINE__));
}
//分离目标进程,恢复环境
KeUnstackDetachProcess(&apc_state);
KdPrint(("chy: 分离目标进程\n"));;
RtlCopyMemory(Buffer, tmpBuf_Kernel, Length);
ExFreePool(tmpBuf_Kernel);
return dwRet;
}
int ReadProcessMemoryForPid(UINT32 dwPid, PVOID pBase, PVOID ipBuffer, UINT32 nSize)
{
KdPrint(("chy: ReadProcessMemoryForPid pid=%d, address=%p, buffer=%p, length=%d\n", dwPid, pBase, ipBuffer, nSize));
//根据pid获取PEPROCESS
PEPROCESS pEPROCESS = NULL;
if (PsLookupProcessByProcessId(dwPid ,&pEPROCESS) == STATUS_SUCCESS)
{
BOOLEAN br = KReadProcessMemory(pEPROCESS, pBase, ipBuffer, nSize);
ObDereferenceObject(pEPROCESS);
if (br)
{
return nSize;
}
}
else
{
KdPrint(("chy: PsLookupProcessByProcessId Error Lines=%d, \n", __LINE__));
}
return STATUS_SUCCESS;
}
void IRP_IO_ReadProcessMemory(PIRP pirp)
{
typedef struct Info
{
UINT32 pid;
PVOID address;
UINT32 length;
} Info;
Info* data = (Info*)pirp->AssociatedIrp.SystemBuffer;
UINT32 readSize = ReadProcessMemoryForPid(data->pid, data->address, pirp->AssociatedIrp.SystemBuffer, data->length);
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = length;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturened
IoCompleteRequest(pirp, IO_NO_INCREMENT);//条用房已完成所有I/O请求处理操作,并且不增加优先级
}
突破保护进程跨进程写内存(只读内存也可)
主模块基址地址基本都是只读的,在此情况下直接更改地址会造成蓝屏
1、KeStackAttachProcess((PRKPROCESS)Process, &apc_state); 进入目标进程内存空间
2、IoAllocateMdl(Address, Length, 0, 0, NULL); 创建MDL来读取内存
3、MmBuildMdlForNonPagedPool(pmdl);对Mdl进行一个更新. 更新对物理内存的描述
4、pmdl->MdlFlags = MDL_WRITE_OPERATION | MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED; 修改内存的访问属性
5、mapped = (unsigned char*)MmMapLockedPages(pmdl, KernelMode); 映射进程内存在内核内存 映射由给定 MDL 描述的物理页面
6、KeUnstackDetachProcess(&apc_state); 分离目标进程,恢复环境
7、RtlCopyMemory(mapped, R3Buffer, Length); 拷贝r3地址数据到进程内存映射的内核空间
8、MmUnmapLockedPages(mapped, pmdl);释放一个映射,该映射是通过之前对 MmMapLockedPages 或 MmMapLockedPagesSpecifyCache 例程的调用设置的
9、IoFreeMdl(pmdl); 释放mdl
BOOLEAN KWriteProcessMemory(PEPROCESS Process, PVOID Address, PVOID R3Buffer, UINT32 Length)
{
KAPC_STATE apc_state;
unsigned char* mapped = NULL;
PMDL pmdl = NULL;
RtlZeroMemory(&apc_state, sizeof(KAPC_STATE));
//进入目标空间 才能读取进程内存,进入之后无法读取r3地址空间
KdPrint(("chy: 附加到目标进程 \n"));;
KeStackAttachProcess((PRKPROCESS)Process, &apc_state);
BOOLEAN dwRet = MmIsAddressValid(Address);
if (dwRet)
{
KdPrint(("chy: 目标地址合法可访问 Address=%p\n", Address));
//创建MDL来读取内存
pmdl = IoAllocateMdl(Address, Length, 0, 0, NULL);
if (!pmdl)
{
return FALSE;
}
//对Mdl进行一个更新. 更新对物理内存的描述
MmBuildMdlForNonPagedPool(pmdl);
//修改内存的访问属性
pmdl->MdlFlags = MDL_WRITE_OPERATION | MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED;
//映射进程内存在内核内存
mapped = (unsigned char*)MmMapLockedPages(pmdl, KernelMode);
if (!mapped)
{
IoFreeMdl(pmdl);
return FALSE;
}
}
//分离目标进程,恢复环境
KdPrint(("chy: 分离目标进程\n"));
KeUnstackDetachProcess(&apc_state);
KdPrint(("chy: RtlCopyMemory\n"));
if (mapped)
//拷贝r3地址数据到进程内存映射的内核空间
RtlCopyMemory(mapped, R3Buffer, Length);
//释放、清理
//释放MDL相关资源
if (mapped)
MmUnmapLockedPages(mapped, pmdl);
if (pmdl)
IoFreeMdl(pmdl);
return dwRet;
}
int WriteProcessMemoryForPid(UINT32 dwPid, PVOID pBase, PVOID r3Buffer, UINT32 nSize)
{
KdPrint(("chy: WriteProcessMemoryForPid pid=%d, address=%p, r3buffer=%p, length=%d\n", dwPid, pBase, r3Buffer, nSize));
//根据pid获取PEPROCESS
PEPROCESS pEPROCESS = NULL;
if (PsLookupProcessByProcessId(dwPid, &pEPROCESS) == STATUS_SUCCESS)
{
BOOLEAN br = KWriteProcessMemory(pEPROCESS, pBase, r3Buffer, nSize);
ObDereferenceObject(pEPROCESS);
if (br)
{
return nSize;
}
}
else
{
KdPrint(("chy: PsLookupProcessByProcessId Error Lines=%d, \n", __LINE__));
}
return STATUS_SUCCESS;
}
void IRP_IO_WriteProcessMemory(PIRP pirp)
{
typedef struct Info
{
UINT32 pid;
PVOID address;
PVOID r3Address;
UINT32 length;
} Info;
Info* data = (Info*)pirp->AssociatedIrp.SystemBuffer;
UINT32 readSize = WriteProcessMemoryForPid(data->pid, data->address, data->r3Address, data->length);
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = data->length;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturened
IoCompleteRequest(pirp, IO_NO_INCREMENT);//条用房已完成所有I/O请求处理操作,并且不增加优先级
}