通过cr3读写进程内存
通过cr3读写进程内存本文总结于lyshark的《Windows内核安全编程技术实践》。技术原理cr3保存着当前进程的最高级页目录地址(物理地址修改cr3为目标进程的最高级页目录地址即可读写目标进程的内存空间。目标进程的最高级页目录地址存放于KPEOCESS结构体偏移0x28处同时也是EPROCESS结构体0x28处。我们通过PsLookupProcessByProcessId和PsGetProcessImageFileName函数获取获取目标进程的EPROCESS地址。之后加上0x28便得到最高级页目录地址。获取目标进程EPROCESS我们希望通过目标进程的可执行文件名称获取EPROCESS结构体staticPEPROCESS sg_pEprocessnullptr;EXTERN_C NTKERNELAPI NTSTATUSPsLookupProcessByProcessId(HANDLE ProcessId,PEPROCESS*Process);EXTERN_C NTKERNELAPI CHAR*PsGetProcessImageFileName(PEPROCESS Process);// 通过进程名获取EPROCESS结构NTSTATUSGetProcessObjectByName(char*name){NTSTATUS statusSTATUS_UNSUCCESSFUL;SIZE_T i;__try{for(i0;i20000;i){PEPROCESS ep;NTSTATUS stPsLookupProcessByProcessId((HANDLE)i,ep);if(NT_SUCCESS(st)){char*pnPsGetProcessImageFileName(ep);// 带下划线版本的是微软的标准扩展实现应该优先使用if(_stricmp(pn,name)0){DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,Found %s\n,name);sg_pEprocessep;__leave;}}}DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,Not Found %s\n,name);}__except(EXCEPTION_EXECUTE_HANDLER){returnstatus;}returnSTATUS_SUCCESS;}读写目标进程的内存现在有了EPROCESS我们开着手修改cr3寄存器的内容也就是开始切换页表// 切换页表_disable();UINT64 cr3__readcr3();__writecr3(pDTB);_enable();这里使用_disable()来关闭中断CR3寄存器控制当前进程的页表基址切换CR3会立即改变地址空间映射。如果在切换过程中被中断打断中断处理程序可能在不正确的地址空间中执行导致数据访问错误或系统崩溃。示例代码#includentddk.h#includewindef.h#includeintrin.h// 页表偏移#defineDIRECTORY_TABLE_BASE0x028// _disable直接生成cli指令需要在内核模式中使用#pragmaintrinsic(_disable)// 将_disable声明为内联函数#pragmaintrinsic(_enable)EXTERN_C NTKERNELAPI NTSTATUSPsLookupProcessByProcessId(HANDLE ProcessId,PEPROCESS*Process);EXTERN_C NTKERNELAPI CHAR*PsGetProcessImageFileName(PEPROCESS Process);staticPEPROCESS sg_pEprocessnullptr;// 通过进程名获取EPROCESS结构NTSTATUSGetProcessObjectByName(char*name){NTSTATUS statusSTATUS_UNSUCCESSFUL;SIZE_T i;__try{for(i0;i20000;i){PEPROCESS ep;NTSTATUS stPsLookupProcessByProcessId((HANDLE)i,ep);if(NT_SUCCESS(st)){char*pnPsGetProcessImageFileName(ep);// 带下划线版本的是微软的标准扩展实现应该优先使用if(_stricmp(pn,name)0){DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,Found %s\n,name);sg_pEprocessep;__leave;}}}DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,Not Found %s\n,name);}__except(EXCEPTION_EXECUTE_HANDLER){returnstatus;}returnSTATUS_SUCCESS;}VOIDDriverUnload(PDRIVER_OBJECT pDriverObj){UNREFERENCED_PARAMETER(pDriverObj);DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,Uninstall Driver Successfully\n);}ULONG64CheckAddressVal(PVOID p){if(MmIsAddressValid(p)FALSE){return0;}// 返回p指向的地址所存的内存return*(PULONG64)p;}BOOLEANCR3_ReadProcessMemory(PEPROCESS ep,PVOID addr,UINT32 length,PVOID buf){ULONG64 pDTBCheckAddressVal((UCHAR*)epDIRECTORY_TABLE_BASE);if(pDTB0){returnfalse;}// 切换页表_disable();UINT64 cr3__readcr3();__writecr3(pDTB);_enable();if(MmIsAddressValid(addr)){RtlCopyMemory(buf,addr,length);DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,read data: %ld\n,*(PDWORD)buf);returntrue;}_disable();__writecr3(cr3);_enable();returnFALSE;}EXTERN_C NTSTATUSDriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING pRegPath){UNREFERENCED_PARAMETER(pRegPath);DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,AccessMem Hello\n);pDriverObj-DriverUnloadDriverUnload;NTSTATUS statusGetProcessObjectByName(x64dbg.exe);if(NT_SUCCESS(status)){DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,[] eprocess %p\n,sg_pEprocess);}DWORD buf0;PVOID addr(PVOID)0x0000000009edc800;BOOLEAN blCR3_ReadProcessMemory(sg_pEprocess,addr,4,buf);UNREFERENCED_PARAMETER(bl);DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,read process x64 address %p: %x, %d\n,addr,buf,buf);returnSTATUS_SUCCESS;}