内核中读写内存的方式有很多,典型的读写方式有CR3读写,MDL读写,以及今天要给大家分享的内存拷贝实现读写,拷贝读写的核心是使用MmCopyVirtualMemory
这个内核API函数实现,通过调用该函数即可很容易的实现内存的拷贝读写。
MmCopyVirtualMemory是Windows内核中一个非常有用的函数,它可以在用户空间和内核空间之间实现内存数据的拷贝。这个函数通过复制内存页表并更新它们来实现拷贝,从而实现了高效的内存拷贝操作。使用MmCopyVirtualMemory可以省去手动复制内存所需的许多繁琐工作,提高代码效率和稳定性。
封装KeReadProcessMemory()
内存读取。KeReadProcessMemory 是 Windows 内核中的一个函数,可用于读取其他进程的内存。其原型如下:
NTSTATUS KeReadProcessMemory(
PEPROCESS Process,
PVOID SourceAddress,
PVOID TargetAddress,
SIZE_T Size,
PSIZE_T NumberOfBytesRead
);
参数说明:
- Process:指定要读取内存的目标进程
- SourceAddress:源内存地址,要从该地址所在进程中读取数据
- TargetAddress:目标内存地址,用于存放读取操作得到的数据
- Size:要读取的数据大小
- NumberOfBytesRead:实际读取的数据大小,如果读取失败则为 0
使用 KeReadProcessMemory
函数可以使内核模式下的驱动程序读取其他进程的内存数据,例如可以用于获取其他进程的数据结构信息以进行分析和加固等操作。
#include <ntifs.h>
#include <windef.h>
#include <stdlib.h>
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
NTSTATUS NTAPI MmCopyVirtualMemory(PEPROCESS SourceProcess, PVOID SourceAddress, PEPROCESS TargetProcess, PVOID TargetAddress, SIZE_T BufferSize, KPROCESSOR_MODE PreviousMode, PSIZE_T ReturnSize);
// 定义全局EProcess结构
PEPROCESS Global_Peprocess = NULL;
// 普通Ke内存读取
NTSTATUS KeReadProcessMemory(PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
__try
{
PEPROCESS TargetProcess = PsGetCurrentProcess();
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(Global_Peprocess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_ACCESS_DENIED;
}
return STATUS_ACCESS_DENIED;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("Uninstall Driver Is OK \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");
// 根据PID打开进程
DWORD PID = 6672;
NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Global_Peprocess);
DWORD ref_value = 0;
// 将地址处读取4字节到ref_value中
NTSTATUS read_nt = KeReadProcessMemory((PVOID)0x0009EDC8, &ref_value, 4);
DbgPrint("读出数据: %d \n", ref_value);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
读取效果如下:
封装KeWriteProcessMemory()
内存写入。KeWriteProcessMemory() 是Windows内核函数之一,是用于从一个进程向另一个进程写入数据的 API。它主要用于在内核级别上修改另一个进程的内存数据。
常规情况下,为了保障系统的安全和稳定性,Windows操作系统禁止任意进程访问其他进程的内存空间。但是在一些情况下,比如安全软件的监控和维护,或者是一些高级工具的特定功能,需要访问其他进程的内存空间,这时就可以使用KeWriteProcessMemory()等内核API来实现。
#include <ntifs.h>
#include <windef.h>
#include <stdlib.h>
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
NTSTATUS NTAPI MmCopyVirtualMemory(PEPROCESS SourceProcess, PVOID SourceAddress, PEPROCESS TargetProcess, PVOID TargetAddress, SIZE_T BufferSize, KPROCESSOR_MODE PreviousMode, PSIZE_T ReturnSize);
// 定义全局EProcess结构
PEPROCESS Global_Peprocess = NULL;
// 普通Ke内存写入
NTSTATUS KeWriteProcessMemory(PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
PEPROCESS SourceProcess = PsGetCurrentProcess();
PEPROCESS TargetProcess = Global_Peprocess;
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("Uninstall Driver Is OK \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");
// 根据PID打开进程
DWORD PID = 6672;
NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Global_Peprocess);
DWORD ref_value = 10;
// 将地址处写出4字节
NTSTATUS read_nt = KeWriteProcessMemory((PVOID)0x0009EDC8, &ref_value, 4);
DbgPrint("写入数据: %d \n", ref_value);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
写出内存效果: