驱动程序中读取与写入内存数据的几种方式 1.读取与写入系统虚拟内存地址数据
使用指针直接读取与写入。
使用C语言内存复制函数读取与写入,例如memcpy()函数。
使用windows驱动函数,例如,RtllCopyMemory。
使用MDL映射的方式写入系统虚拟地址
2.读取与写入物理地址的方式 操作系统与驱动程序都运行在系统虚拟地址高位空间中,要想读取与写入物理地址需要将物理地址映射到系统虚拟地址中。才能在驱动程序中读取与写入数据。
映射物理地址到系统虚拟地址的方法
方法一:使用函数
方法二:使用MDL的方式使用函数
3.读取与写入应用程序虚拟内存地址的方式 高位系统虚拟地址运行的是内核与驱动的指令,低位系统虚拟地址运行的是应用程序的指令。每个应用程序进程的地址空间都会通过四级页表映射到系统虚拟地址空间中。
读取与写入应用程序内存数据的方法
方法一:使用windows驱动函数MmCopyVirtualMemory.
方法二: 根据应用pid获得eprocess后挂靠就可以通过指针或者内存复制函数来读取或写入。
方法三:找到应用程序进程中虚拟地址对应的物理地址后->将物理地址映射到系统虚拟地址中->就可以在驱动中读取或者修改内存地址数据。
方法三:通过切换CR0来读取与写入应用程序进程内存地址数据。
MDL映射的方式写入系统虚拟内存地址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <ntifs.h> VOID TestMadAddrMdl () ; NTSTATUS DriverUnload (PDRIVER_OBJECT pdriver) { DbgPrint("unload...\n" ); return STATUS_SUCCESS; } NTSTATUS DriverEntry (PDRIVER_OBJECT pdriver, PUNICODE_STRING path) { pdriver->DriverUnload = DriverUnload; DbgPrint("loading...\n" ); TestMadAddrMdl(); return STATUS_SUCCESS; } VOID TestMadAddrMdl () { PVOID addr = 0xFFFFF8030DF578D0 ; ULONG size = 10 ; PMDL mdl = IoAllocateMdl(addr, size, FALSE, FALSE, NULL ); if (!mdl)return ; MmProbeAndLockPages(mdl, KernelMode, IoReadAccess); PVOID map = MmMapLockedPagesSpecifyCache(mdl, KernelMode, MmCached, NULL , FALSE, HighPagePriority); if (!map ) { MmUnlockPages(mdl); IoFreeMdl(mdl); return ; } DbgPrint("map:%p,addr:%p\n" , mdl, addr); *(PCHAR)addr = 0xc3 ; MmUnmapLockedPages(map , mdl); MmUnlockPages(mdl); IoFreeMdl(mdl); return ; }
⚙️驱动程序修改应用程序数据的原理一 驱动程序中需要挂靠进程后读取与写入内存数据,挂靠需要获取EPROCESS,EPROCESS可以通过pid与windows函数获得。
3环代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> #include <cstring> char p[] = "Hello world" ;int main () { printf ("%s,%llx" , p, p); getchar (); printf ("%s,%llx" , p, p); getchar (); char str[] = "123456789444444" ; memcpy (p, str, sizeof (str)); printf ("%s,%llx" , p, p); getchar (); p[5 ] = 'h' ; p[6 ] = 'a' ; p[7 ] = 'h' ; p[8 ] = 'a' ; p[9 ] = '\0' ; printf ("%s,%llx" , p, p); getchar (); return 0 ; }
0环代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <ntifs.h> VOID DriverUnload (PDRIVER_OBJECT pDriver) ; PEPROCESS LookupProcess (HANDLE hPid) { PEPROCESS pEProcess = NULL ; if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &pEProcess))) return pEProcess; return NULL ; } VOID ChangeData (ULONG uId) { KAPC_STATE ks; PEPROCESS pEprocess = LookupProcess((HANDLE)uId); KeStackAttachProcess(pEprocess, &ks); char * p = (char *)0x7ff7b2ae5000 ; p[5 ] = 'h' ; p[6 ] = 'a' ; p[7 ] = 'h' ; p[8 ] = 'a' ; p[9 ] = '\0' ; KeUnstackDetachProcess(&ks); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath) { UNREFERENCED_PARAMETER(pPath); ChangeData(0x1AAC ); pDriver->DriverUnload = DriverUnload; return STATUS_SUCCESS; } VOID DriverUnload (PDRIVER_OBJECT pDriver) { UNREFERENCED_PARAMETER(pDriver); }
结果会修改几个字符
issue: char p 定义失败,const char *p定义成功,char *p位静态地址不能直接修改内容,数组char []可以直接修改,或者用alloc 开辟动态内存。
⚙️封装根据pid读取虚拟内存地址数据的功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 NTSTATUS ReadUserMemoryByPid (HANDLE pid, PVOID targetAddress, PVOID buffer, SIZE_T size) { PEPROCESS pProcess; NTSTATUS status = PsLookupProcessByProcessId(pid, &pProcess); if (!NT_SUCCESS(status)) return status; KAPC_STATE apc; KeStackAttachProcess(pProcess, &apc); __try { RtlCopyMemory(buffer, targetAddress, size); status = STATUS_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { status = STATUS_ACCESS_VIOLATION; } KeUnstackDetachProcess(&apc); ObDereferenceObject(pProcess); return status; }
⚙️使用MmCopyVirtualMemory写入应用进程虚拟内存地址 对比之前的读取应用进程虚拟内存地址文章只需要将目标进程和目标地址对比源进程与源地址的位置交换。
sysmain.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #pragma warning (disable: 4100 4047 4024) #pragma once #include <ntifs.h> #include <ntddk.h> NTKERNELAPI NTSTATUS MmCopyVirtualMemory ( _In_ PEPROCESS srcProcess, _In_ PVOID srcAddr, _In_ PEPROCESS dstProcess, _In_ PVOID dstAddr, _In_ SIZE_T DataSize, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PSIZE_T RetureSize ) ; NTSTATUS kReadProcessMemory (PEPROCESS Process, PVOID lpBaseAddress, PVOID lpBuffer, size_t nSize) { PSIZE_T rSize; return MmCopyVirtualMemory(Process, lpBaseAddress, PsGetCurrentProcess(), lpBuffer, nSize, KernelMode, &rSize); } NTSTATUS kWriteProcessMemory (PEPROCESS Process, PVOID lpBaseAddress, PVOID lpBuffer, size_t nSize) { PSIZE_T rSize; return MmCopyVirtualMemory(PsGetCurrentProcess(), lpBuffer, Process, lpBaseAddress, nSize, KernelMode, &rSize); } NTSTATUS DriverUnload (PDRIVER_OBJECT pDriverObject) { DbgPrintEx(0 , 0 , "stop hsys.\n" ); return STATUS_SUCCESS; } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegister) { pDriverObject->DriverUnload = DriverUnload; PEPROCESS Process; size_t pid = 2572 ; PsLookupProcessByProcessId((HANDLE)pid, &Process); PVOID addr = 0x00007FF72BB8C178 ; int newValue = 100 ; kWriteProcessMemory(Process, addr, &newValue, sizeof (int )); int readValue = 0 ; kReadProcessMemory(Process, addr, &readValue, sizeof (int )); DbgPrintEx(0 , 0 , "change value: %d\n" , readValue); return STATUS_SUCCESS; }
参考资料:
windows 内核模式读写内存
⚙️使用MmCopyVirtualMemory读取进程数据复制到另一个进程中 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <ntifs.h> #include <ntddk.h> void CopyMemoryBetweenProcesses () { NTSTATUS status; PEPROCESS sourceProcess = NULL ; PEPROCESS targetProcess = NULL ; HANDLE sourcePid = (HANDLE)0x8EC ; HANDLE targetPid = (HANDLE)0xEC8 ; PVOID sourceAddress = (PVOID)0x7FFF67678 ; PVOID targetAddress = (PVOID)0x7676766AD ; SIZE_T size = 0x1000 ; SIZE_T bytesCopied = 0 ; status = PsLookupProcessByProcessId(sourcePid, &sourceProcess); if (!NT_SUCCESS(status)) { DbgPrint("Failed to get source process\r\n" ); return ; } status = PsLookupProcessByProcessId(targetPid, &targetProcess); if (!NT_SUCCESS(status)) { DbgPrint("Failed to get target process\r\n" ); ObDereferenceObject(sourceProcess); return ; } status = MmCopyVirtualMemory( sourceProcess, sourceAddress, targetProcess, targetAddress, size, KernelMode, &bytesCopied ); if (NT_SUCCESS(status)) { DbgPrint("Successfully copied %llu bytes from source to target process\r\n" , bytesCopied); } else { DbgPrint("Failed to copy memory\r\n" ); } ObDereferenceObject(sourceProcess); ObDereferenceObject(targetProcess); }
找到应用程序进程中虚拟地址对应的物理地址后->将物理地址映射到系统虚拟地址中->在驱动中读取或者修改内存地址数据。 ⚙️方式一:获取虚拟地址对应的物理地址 + MmMapIoSpace ✅ 优点:
可以查看 虚拟地址对应的物理地址 (使用 MmGetPhysicalAddress)。
可以将 物理地址映射到内核空间 后直接读取。
对于调试页表映射、驱动开发中分析地址转换非常有用。
❌ 缺点与风险:
问题
解释
只对 物理内存常驻页 有效
不能映射分页内存(pagefile)或尚未分配的虚拟页
无法写入(理论上可以写,但极其危险)
写物理内存可能会破坏系统稳定性、导致蓝屏
需要手动判断物理地址有效性
某些地址可能映射不到设备可访问区域
仅支持内存线性映射区域
有些页可能不是线性物理映射的(尤其是 NUMA/SMEP 机器)
⚙️ 方式二:使用 MDL 构造映射用户虚拟地址* + 映射用户页表
通过 MmProbeAndLockPages 获取用户内存页的物理页
然后用 MmMapLockedPagesSpecifyCache 映射到内核
这种方法适用于绕过 PatchGuard 的某些内核注入行为
🚀 完整代码(读取 + 写入)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 NTSTATUS ReadWriteProcessMemoryViaMDL ( HANDLE TargetPid, PVOID TargetAddress, PVOID Buffer, SIZE_T Size, BOOLEAN bWrite ) { PEPROCESS targetProcess = NULL ; NTSTATUS status = PsLookupProcessByProcessId(TargetPid, &targetProcess); if (!NT_SUCCESS(status)) return status; KAPC_STATE apc; KeStackAttachProcess(targetProcess, &apc); __try { if (!MmIsAddressValid(TargetAddress)) { status = STATUS_ACCESS_VIOLATION; __leave; } PMDL pMdl = IoAllocateMdl( TargetAddress, (ULONG)Size, FALSE, FALSE, NULL ); if (!pMdl) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } __try { MmProbeAndLockPages(pMdl, UserMode, bWrite ? IoReadAccess : IoWriteAccess); PVOID mappedAddress = MmMapLockedPagesSpecifyCache( pMdl, KernelMode, MmCached, NULL , FALSE, NormalPagePriority ); if (!mappedAddress) { status = STATUS_INSUFFICIENT_RESOURCES; MmUnlockPages(pMdl); IoFreeMdl(pMdl); __leave; } if (bWrite) { RtlCopyMemory(mappedAddress, Buffer, Size); } else { RtlCopyMemory(Buffer, mappedAddress, Size); } MmUnmapLockedPages(mappedAddress, pMdl); MmUnlockPages(pMdl); } __except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } IoFreeMdl(pMdl); } __except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } KeUnstackDetachProcess(&apc); return status; }
🔧 用法示例:
✅ 读取目标用户进程内存:
1 2 3 4 5 6 7 8 cCopyEditUCHAR buffer[64 ] = { 0 }; NTSTATUS st = ReadWriteProcessMemoryViaMDL( pid, (PVOID)0x7FF620003000 , buffer, sizeof (buffer), FALSE );
✅ 写入数据到目标进程:
1 2 3 4 5 6 7 8 cCopyEditUCHAR writeData[8 ] = { 0x90 , 0x90 , 0x90 , 0x90 , 0xC3 , 0x00 , 0x00 , 0x00 }; NTSTATUS st = ReadWriteProcessMemoryViaMDL( pid, (PVOID)0x7FF620003000 , writeData, sizeof (writeData), TRUE );
✅ 优点:
优势
解释
支持对用户虚拟地址的直接读写
不关心物理地址,只要地址有效就能读写
自动处理页表映射
MmProbeAndLockPages + MmMapLockedPages 自动完成物理映射
比物理地址更安全
因为系统已经帮你处理页边界、锁页等操作
兼容分页内存
能读取未常驻物理内存的数据,系统会自动调页进来
❌ 缺点:
如果地址无效或权限不足,会异常,需要 __try/__except 包裹。
稍微复杂一些。
⚙️手动模拟上下文切换,切换CR3读取与写入(不推荐) 1.通过切换读取内存数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 #include <ntifs.h> #include <windef.h> #include <intrin.h> #define DIRECTORY_TABLE_BASE 0x028 #pragma intrinsic(_disable) #pragma intrinsic(_enable) NTKERNELAPI NTSTATUS PsLookupProcessByProcessId (HANDLE ProcessId, PEPROCESS *Process) ; NTKERNELAPI CHAR* PsGetProcessImageFileName (PEPROCESS Process) ; KIRQL Open () { KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff ; __writecr0(cr0); _disable(); return irql; } void Close (KIRQL irql) { UINT64 cr0 = __readcr0(); cr0 |= 0x10000 ; _enable(); __writecr0(cr0); KeLowerIrql(irql); } ULONG64 CheckAddressVal (PVOID p) { if (MmIsAddressValid(p) == FALSE) return 0 ; return *(PULONG64)p; } BOOLEAN CR3_ReadProcessMemory (IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, OUT PVOID Buffer) { ULONG64 pDTB = 0 , OldCr3 = 0 , vAddr = 0 ; pDTB = CheckAddressVal((UCHAR*)Process + DIRECTORY_TABLE_BASE); if (pDTB == 0 ) { return FALSE; } _disable(); OldCr3 = __readcr3(); __writecr3(pDTB); _enable(); if (MmIsAddressValid(Address)) { RtlCopyMemory(Buffer, Address, Length); DbgPrint("读入数据: %ld" , *(PDWORD)Buffer); return TRUE; } _disable(); __writecr3(OldCr3); _enable(); return FALSE; } VOID UnDriver (PDRIVER_OBJECT driver) { DbgPrint(("Uninstall Driver Is OK \n" )); } NTSTATUS DriverEntry (IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { DbgPrint("hello Driver \n" ); PEPROCESS Peprocess = NULL ; DWORD PID = 6672 ; NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess); DWORD buffer = 0 ; BOOLEAN bl = CR3_ReadProcessMemory(Peprocess, (PVOID)0x0009EDC8 , 4 , &buffer); DbgPrint("readbuf = %x \n" , buffer); DbgPrint("readbuf = %d \n" , buffer); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
2.通过切换CR3写入内存数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #include <ntifs.h> #include <windef.h> #include <intrin.h> #define DIRECTORY_TABLE_BASE 0x028 #pragma intrinsic(_disable) #pragma intrinsic(_enable) NTKERNELAPI NTSTATUS PsLookupProcessByProcessId (HANDLE ProcessId, PEPROCESS *Process) ; NTKERNELAPI CHAR* PsGetProcessImageFileName (PEPROCESS Process) ; KIRQL Open () { KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff ; __writecr0(cr0); _disable(); return irql; } void Close (KIRQL irql) { UINT64 cr0 = __readcr0(); cr0 |= 0x10000 ; _enable(); __writecr0(cr0); KeLowerIrql(irql); } ULONG64 CheckAddressVal (PVOID p) { if (MmIsAddressValid(p) == FALSE) return 0 ; return *(PULONG64)p; } BOOLEAN CR3_WriteProcessMemory (IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, IN PVOID Buffer) { ULONG64 pDTB = 0 , OldCr3 = 0 , vAddr = 0 ; pDTB = CheckAddressVal((UCHAR*)Process + DIRECTORY_TABLE_BASE); if (pDTB == 0 ) { return FALSE; } _disable(); OldCr3 = __readcr3(); __writecr3(pDTB); _enable(); if (MmIsAddressValid(Address)) { RtlCopyMemory(Address, Buffer, Length); return TRUE; } _disable(); __writecr3(OldCr3); _enable(); return FALSE; } VOID UnDriver (PDRIVER_OBJECT driver) { DbgPrint(("Uninstall Driver Is OK \n" )); } NTSTATUS DriverEntry (IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { DbgPrint("hello Driver \n" ); PEPROCESS Peprocess = NULL ; DWORD PID = 6672 ; NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess); DWORD buffer = 999 ; BOOLEAN bl = CR3_WriteProcessMemory(Peprocess, (PVOID)0x0009EDC8 , 4 , &buffer); DbgPrint("写出状态: %d \n" , bl); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
3.通过切换cr3读写内存数据
ConverPidProcess.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #pragma once #include <ntifs.h> #define Log(X) DbgPrint("qi:" X##) typedef NTSTATUS (*PfnZwQueryInformationProcess) ( __in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __out_bcount(ProcessInformationLength) PVOID ProcessInformation, __in ULONG ProcessInformationLength, __out_opt PULONG ReturnLength ) ;PfnZwQueryInformationProcess ZwQueryInformationProcess; NTKERNELAPI CHAR* PsGetProcessImageFileName (PEPROCESS Process) ; HANDLE PidToHandle (ULONG PID) ; ULONG HandleToPid (HANDLE handle) ; PEPROCESS PidToObject (ULONG Pid) ; PEPROCESS HandleToEprocess (HANDLE handle) ; HANDLE EprocessToHandle (PEPROCESS eprocess) ; ULONG GetProcessIdByName (char * name) ; PEPROCESS GetProcessObjectByName (char * name) ;
entry.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #include <ntifs.h> #include <wdm.h> #include <intrin.h> #include <windef.h> #include "ConverPidProcess.h" #define Log(X) DbgPrintEx(0, 0,"qi:" X##) NTSTATUS ReadProcessMemory (HANDLE pid, PVOID addr, PVOID buf, SIZE_T size) ; VOID TestRead () ; NTSTATUS WriteProcessMemory (HANDLE pid, PVOID addr, PVOID buf, SIZE_T size) ; VOID TestWrite () ; NTSTATUS DriverUnload (PDRIVER_OBJECT pdriver) { DbgPrint("unload...\n" ); return STATUS_SUCCESS; } NTSTATUS DriverEntry (PDRIVER_OBJECT pdriver, PUNICODE_STRING path) { pdriver->DriverUnload = DriverUnload; DbgPrint("loading...\n" ); TestRead(); TestWrite(); return STATUS_SUCCESS; } NTSTATUS ReadProcessMemory (HANDLE pid, PVOID addr, PVOID buf, SIZE_T size) { PEPROCESS pe = NULL ; NTSTATUS status = PsLookupProcessByProcessId(pid, &pe); if (!NT_SUCCESS(status))return STATUS_UNSUCCESSFUL; ObReferenceObject(pe); KAPC_STATE kapc = { 0 }; KeStackAttachProcess(pe, &kapc); __try { RtlCopyMemory(buf, addr, size); } __except (1 ) { DbgPrint("Read Error\n" ); KeUnstackDetachProcess(&kapc); return STATUS_UNSUCCESSFUL; } KeUnstackDetachProcess(&kapc); return STATUS_SUCCESS; } VOID TestRead () { HANDLE pid = NULL ; CHAR pname[] = "Taskmgr.exe" ; pid = GetProcessIdByName(pname); if (!pid) { DbgPrint("error1 pid get false\n" ); return ; } PVOID addr = 0x400000 ; ULONG buf = 0 ; ReadProcessMemory((HANDLE)pid, addr, &buf, 4 ); Log("%p value %d\n" , addr, buf); return ; } NTSTATUS WriteProcessMemory (HANDLE pid, PVOID addr, PVOID buf, SIZE_T size) { PEPROCESS pe = NULL ; NTSTATUS status = PsLookupProcessByProcessId(pid, &pe); if (!NT_SUCCESS(status))return STATUS_UNSUCCESSFUL; ObReferenceObject(pe); KAPC_STATE kapc = { 0 }; unsigned __int64 cr0 = 0 ; KeStackAttachProcess(pe, &kapc); __try { _disable(); cr0 = __readcr0(); cr0 &= 0xfffeffff ; __writecr0(cr0); _enable(); RtlCopyMemory(addr, buf, size); _disable(); cr0 = __readcr0(); cr0 &= 0x10000 ; __writecr0(cr0); _enable(); } __except (1 ) { DbgPrint("Write Error\n" ); _disable(); cr0 = __readcr0(); cr0 &= 0x10000 ; __writecr0(cr0); _enable(); KeUnstackDetachProcess(&kapc); return STATUS_UNSUCCESSFUL; } KeUnstackDetachProcess(&kapc); return STATUS_SUCCESS; } VOID TestWrite () { HANDLE pid = NULL ; CHAR pname[] = "Taskmgr.exe" ; pid = GetProcessIdByName(pname); if (!pid) { DbgPrint("error1 pid get false\n" ); return ; } PVOID addr = 0x400000 ; ULONG buf = 666666 ; WriteProcessMemory((HANDLE)pid, addr, &buf, 4 ); ReadProcessMemory((HANDLE)pid, addr, &buf, 4 ); Log("%p value %d\n" , addr, buf); return ; }
ConverPidProcess.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 #include "ConverPidProcess.h" HANDLE PidToHandle (ULONG PID) { if (!PID)return NULL ; HANDLE hProcessHandle; OBJECT_ATTRIBUTES obj; CLIENT_ID clientid; clientid.UniqueProcess = PID; clientid.UniqueThread = 0 ; InitializeObjectAttributes(&obj, 0 , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0 , 0 ); NTSTATUS status = ZwOpenProcess(&hProcessHandle, PROCESS_ALL_ACCESS, &obj, &clientid); if (status == STATUS_SUCCESS) { ZwClose(&hProcessHandle); return hProcessHandle; } return 0 ; } ULONG HandleToPid (HANDLE handle) { if (!handle)return 0 ; PROCESS_BASIC_INFORMATION ProcessBasicInfor; UNICODE_STRING UtrZwQueryInformationProcessName = RTL_CONSTANT_STRING(L"ZwQueryInformationProcess" ); ZwQueryInformationProcess = (PfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&UtrZwQueryInformationProcessName); ZwQueryInformationProcess( handle, ProcessBasicInformation, (PVOID)&ProcessBasicInfor, sizeof (ProcessBasicInfor), NULL ); return ProcessBasicInfor.UniqueProcessId; } PEPROCESS PidToObject (ULONG Pid) { if (!Pid)return NULL ; PEPROCESS pEprocess; NTSTATUS status = PsLookupProcessByProcessId((HANDLE)Pid, &pEprocess); if (status == STATUS_SUCCESS) { ObDereferenceObject(pEprocess); return pEprocess; } return NULL ; } PEPROCESS HandleToEprocess (HANDLE handle) { if (!handle)return NULL ; PEPROCESS pEprocess; NTSTATUS status = ObReferenceObjectByHandle(handle, GENERIC_ALL, *PsProcessType, KernelMode, &pEprocess, NULL ); if (status == STATUS_SUCCESS) { return pEprocess; } return 0 ; } HANDLE EprocessToHandle (PEPROCESS eprocess) { if (!eprocess)return NULL ; HANDLE hProcessHandle = (HANDLE)-1 ; NTSTATUS status = ObOpenObjectByPointer( eprocess, OBJ_KERNEL_HANDLE, 0 , 0 , *PsProcessType, KernelMode, &hProcessHandle ); if (status == STATUS_SUCCESS) { return hProcessHandle; } return NULL ; } PEPROCESS GetProcessObjectByName (char * name) { if (!name)return NULL ; SIZE_T temp; for (temp = 100 ; temp < 10000 ; temp += 4 ) { NTSTATUS status; PEPROCESS ep; status = PsLookupProcessByProcessId((HANDLE)temp, &ep); if (NT_SUCCESS(status)) { char * pn = PsGetProcessImageFileName(ep); if (_stricmp(pn, name) == 0 ) return ep; } } return NULL ; } ULONG GetProcessIdByName (char * name) { if (!name)return 0 ; PEPROCESS eprocess = GetProcessObjectByName(name); if (!eprocess) return 0 ; HANDLE handle = EprocessToHandle(eprocess); if (handle == 0 )return 0 ; ULONG pid = HandleToPid(handle); return pid; }