驱动开发

环境搭建

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请求处理操作,并且不增加优先级
}

results matching ""

    No results matching ""