MDL进行内存读写
1. 什么是MDL
MDL(Memory Descriptor List,内存描述符列表),用于描述物理内存页的一个结构体,用于处理非连续的物理内存块,对非连续的物理内存进行读写
2. 我们为什么需要使用MDL
如果一块内存只拥有读权限,那么用memcopy()是无法写入的(由于memcopy是访问虚拟内存),因此需要用MDL来直接管理物理内存,我们把物理内存映射到MDL结构体中,通过改变MDL结构体来进行修改,则可以完成访问
3. 如何实现
我们需要一个结构体来储存MDL上下文信息和映射后的虚拟地址
调用
IoAllocateMdl函数为给定的虚拟地址Va和长度Length分配一个MDL,注:IoAllocateMdl只是保留了地址,并没有给出映射后的虚拟地址1 2 3 4 5 6 7 8 9 10 11 12NTSTATUS status; status = STATUS_SUCCESS; ReprotectContext->Mdl = 0; ReprotectContext->lockedVa = 0; //Va是要用mdl描述的物理地址的虚拟地址 //IRP 是用于三环和零环通信的,这边并没有申请内存给Va,在下面申请,这边可以理解为是一个reserve操作,这边保留了一块地址。但没有给出对应的虚拟地址 ReprotectContext->Mdl = IoAllocateMdl(Va, Length,FALSE,FALSE,NULL); if (!ReprotectContext->Mdl) { DbgPrintEx(102, 0, "申请内存失败"); return STATUS_INSUFFICIENT_RESOURCES; }使用
MmProbeAndLockPages来探测并锁定虚拟地址对应的物理页,防止这些页被分页出内存。锁定的内存不会被操作系统换出到硬盘使用
MmMapLockedPagesSpecifyCache将锁定的物理页映射到系统虚拟地址空间1 2 3 4 5 6 7 8 9 10 11// 将分配好的地址给出 commit ReprotectContext->lockedVa =(PUCHAR)MmMapLockedPagesSpecifyCache(ReprotectContext->Mdl,KernelMode, MmCached,NULL,FALSE,NormalPagePriority ); if (!ReprotectContext->lockedVa) { IoFreeMdl(ReprotectContext->Mdl); ReprotectContext->Mdl = 0; DbgPrintEx(102, 0, "映射失败"); return STATUS_UNSUCCESSFUL; }使用
MmProtectMdlSystemAddress将映射的内存设置为可执行和可读写1 2 3 4 5 6 7 8 9 10 11 12status = MmProtectMdlSystemAddress(ReprotectContext->Mdl, PAGE_EXECUTE_READWRITE); if(!NT_SUCCESS(status)) { DbgPrintEx(102, 0, "保护失败"); MmUnmapLockedPages(ReprotectContext->lockedVa, ReprotectContext->Mdl); MmUnlockPages(ReprotectContext->Mdl); IoFreeMdl(ReprotectContext->Mdl); ReprotectContext->Mdl = 0; ReprotectContext->lockedVa = 0; return status; }释放资源
1 2 3 4 5 6 7 8 9 10 11NTSTATUS MmUnlockVaForWrite(PREPROTECT_CONTEXT ReprotectContext) { NTSTATUS status; status = STATUS_SUCCESS; MmUnmapLockedPages(ReprotectContext->lockedVa, ReprotectContext->Mdl); MmUnlockPages(ReprotectContext->Mdl); IoFreeMdl(ReprotectContext->Mdl); ReprotectContext->Mdl = 0; ReprotectContext->lockedVa = 0; return status; }
4. 完整代码
已经在x64HOOK中使用,就不单独添加工程项目了,文件名:MDL.cpp
| |