一、获取被保护数据,驱动块源码(第二种方法)
BOOLEAN KReadProcessMemory2(IN PEPROCESS 目标进程, IN PVOID 目标地址, IN UINT32 目标长度, IN PVOID 返回数据) { KAPC_STATE apc_state; RtlZeroMemory(&apc_state, sizeof(KAPC_STATE)); //创建MDL来读取内存 PMDL 映射内存结构 = IoAllocateMdl(返回数据, 目标长度, 0, 0, NULL); if (!映射内存结构) { return FALSE; } //将映射内存变成可读 MmBuildMdlForNonPagedPool(映射内存结构); //获取可读的地址 unsigned char* 可读内存 = (unsigned char*)MmMapLockedPages(映射内存结构, KernelMode); if (!可读内存) { IoFreeMdl(映射内存结构); return FALSE; } //切换到目标进程进行操作 KeStackAttachProcess((PVOID)目标进程, &apc_state); //判断该地址是否可读 BOOLEAN 是否可读 = MmIsAddressValid(目标地址); if (是否可读) { RtlCopyMemory(可读内存, 目标地址, 目标长度); } else { KdPrint(("nxyn2不可读")); } //恢复环境 KeUnstackDetachProcess(&apc_state); MmUnmapLockedPages((PVOID)可读内存, 映射内存结构); IoFreeMdl(映射内存结构); return 是否可读; } int ReadProcessMemoryForPid2(UINT32 dwPid, PVOID 读取地址, PVOID 读取内容, UINT32 读取大小) { //根据pid获取PEPROCESS PEPROCESS Seleted_pEPROCESS = NULL; if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(dwPid), &Seleted_pEPROCESS) == STATUS_SUCCESS) { BOOLEAN br = KReadProcessMemory2(Seleted_pEPROCESS, (PVOID)读取地址, 读取大小, 读取内容); ObDereferenceObject(Seleted_pEPROCESS); if (br) { return 读取大小; } } else { KdPrint(("nxyn 2读取失败")); } return 0; } NTSTATUS IRP_ReadProcessMemory2(PIRP pirp) { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION irpStack = NULL; irpStack = IoGetCurrentIrpStackLocation(pirp); #pragma pack(push) #pragma pack(8) typedef struct TINPUT_BUF { UINT64 dwPid;//目标进程PID PVOID pBase; //目标进程地址 UINT64 nSize;//要读取的长度 }TINPUT_BUF; #pragma pack(pop) TINPUT_BUF* 输入数据 = (TINPUT_BUF*)(pirp->AssociatedIrp.SystemBuffer); ReadProcessMemoryForPid2(输入数据->dwPid, 输入数据->pBase, 输入数据/*保存读取的数据*/, 输入数据->nSize); if (irpStack) // { if (ntStatus == STATUS_SUCCESS) { //成功则返回 缓冲区大小 pirp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;//DeviceIoControl } else { //失败则不返回 pirp->IoStatus.Information = 0; } //完成请求 IoCompleteRequest(pirp, IO_NO_INCREMENT); } pirp->IoStatus.Status = ntStatus; return ntStatus; }
二、在头文件添加函数声明
NTSTATUS IRP_ReadProcessMemory2(PIRP pirp);
三、控制码实现代码
#define irp读被保护数据2 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED,FILE_ANY_ACCESS) else if(控制码== irp读被保护数据2) { return IRP_ReadProcessMemory2(IRP指针); }
四、MFC实现
1、界面添加一个按钮
2、代码实现
#define irp读被保护数据2 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED,FILE_ANY_ACCESS) void CtestDlg::OnBnClickedButtonDqbbhsj2() { #pragma pack(push) #pragma pack(8) typedef struct TINPUT_BUF { UINT64 dwPid;//目标进程PID PVOID pBase; //目标进程地址 UINT64 nSize;//要读取的长度 }TINPUT_BUF; #pragma pack(pop) UpdateData(true); DWORD 返回字节数 = 0; DWORD 临时数据 = 0; UINT_PTR 地址 = 0x7FF7F8F20000; TINPUT_BUF 输入缓存区 = { mbpid,(PVOID)地址,4 }; DeviceIoControl( 设备句柄, irp读被保护数据2, &输入缓存区, sizeof(TINPUT_BUF), &临时数据, sizeof(临时数据), &返回字节数, NULL ); char 缓存[256]; sprintf_s(缓存, "2读取被保护值%X", 临时数据); ::MessageBoxA(0, 缓存, "2读被保护测试", MB_OK); }
五、运行效果,两种方法都可读取