MDL解析
使用MDL映射非分页内存
PMDL MdlForFunc;PVOID Msct;KIRQL f_oldirql;MdlForFunc = MmCreateMdl(NULL, HookData.HookAddress, HookData.HookLenth);if (MdlForFunc){MmBuildMdlForNonPagedPool(MdlForFunc);MdlForFunc->MdlFlags = MdlForFunc->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;__try{MmProbeAndLockPages(MdlForFunc, KernelMode, IoWriteAccess);}__except (EXCEPTION_EXECUTE_HANDLER){IoFreeMdl(MdlForFunc);ExFreePool(HookData.OldData);return;}Msct = MmMapLockedPagesSpecifyCache(MdlForFunc, KernelMode, MmWriteCombined, NULL, FALSE, 0);KIRQL Irql = KeRaiseIrqlToDpcLevel();//do somethingKeLowerIrql(Irql);MmUnmapLockedPages(Msct, MdlForFunc);MmUnlockPages(MdlForFunc);IoFreeMdl(MdlForFunc);}
映射分页内存
PMDL mdl;
// 驱动卸载的回调函数,会在卸载的时候被调用
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{//释放MDLIoFreeMdl(mdl);UNREFERENCED_PARAMETER(DriverObject);
}// 2. 提供驱动程序的入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, // 驱动对象,类似实例句柄PUNICODE_STRING RegistryPath) // 字符串指针,保存驱动在注册表的路径
{//设置回调函数DriverObject->DriverUnload = DriverUnload;// 创建一个指针指向常量字符串char source[0x4096] = { 0 };//创建一个souce的MDL 只映射0x1000字节mdl = IoAllocateMdl(source, 0x1000, FALSE, FALSE, NULL);// 对于分页内存,需要使用下面的函数锁定内存不会被换出// 对于非分页内存,需要调用 MmBuildMdlForNonPagedPool 建立描述符// 锁定MDLMmProbeAndLockPages(mdl, KernelMode, IoModifyAccess);// 1. 需要进行重新映射的 MDL 结构,必须是绑定好了的// 2. 重新映射的虚拟地址位于什么空间// 3. 表示缓存的级别,允许 CPU 进行缓存// 4. 想要映射到哪个地址,NULL 表示不指定// 5. 如果映射失败,是否蓝屏// 6. 当前映射的级别,通常使用普通级别//调用MmMapLockedPagesSpecifyCache后,标志位mdl->MdlFlags = mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA.;//有此标志位后,MmGetSystemAddressForMdlSafe就是直接取mdl->MappedSystemVa,如果没有该标志那么就会调用MmMapLockedPagesSpecifyCache.char* dest = MmMapLockedPagesSpecifyCache(mdl,KernelMode,MmCached,NULL,FALSE,NormalPagePriority);dest[0] = 'C';DbgBreakPoint();/*1: kd> ??mdlstruct _MDL * 0xffffc789`c4a98100+0x000 Next : (null)+0x008 Size : 0n64 v9 = (((unsigned __int16)VirtualAddress & 0xFFF) + (unsigned __int64)Length + 4095) >> 12;Size = 8 * (v9 + 6); Size值有什么用?+0x00a MdlFlags : 0n139+0x010 Process : (null)+0x018 MappedSystemVa : 0xffff8f81`dbb40830 Void 用于保存映射后的虚拟地址指针,映射时会分配一个虚拟内存,这个虚拟内存会和被映射内存使用同一物理页。--------------------------- 以下字段记录被映射内存的相关信息 --------------+0x020 StartVa : 0xfffffc08`58af7000 Void 被映射的虚拟地址的开始页+0x028 ByteCount : 0x1000 总共映射的字节数 后面使用的内存不能超过这个值+被映射地址 +0x02c ByteOffset : 0x830 被映射的虚拟地址的页内偏移 StartVa+ByteOffset就是被映射地址 1: kd> ??dest
char * 0xffff8f81`dbb40830"C"
1: kd> ??source
char [16534] 0xfffffc08`58af7830
67 'C'*/KdPrint(("%S\n", dest));//取消映射-取消锁定MmUnmapLockedPages(dest, mdl);MmUnlockPages(mdl);// 3. 必须需要提供一个返回值,如果返回成功// 那么就会加载成功,其他值都是加载失败return STATUS_SUCCESS;
}
运行结果得出: mdl的 StartVa + ByteOffset =buffer 映射的buffer地址.
调用函数MmMapLockedPagesSpecifyCache取得映射的地址buffer2 等于MappedSystemVa.
总结:
实际上MDL映射是系统申请了一块我们要映射大小的内存,我们操作的是映射后的内存.
这块内存跟被映射的内存使用的是同一个物理页
建立映射后的mdl
1: kd> ??mdl
struct _MDL * 0xffffbe8f`e412c940+0x000 Next : (null) +0x008 Size : 0n88+0x00a MdlFlags : 0n139+0x010 Process : (null) +0x018 MappedSystemVa : 0xffffd181`c6bf5810 Void //映射后的虚拟地址 +0x020 StartVa : 0xffffa883`8f349000 Void //被映射的虚拟地址+0x028 ByteCount : 0x4096 //映射的大小 +0x02c ByteOffset : 0x810
1: kd> dq 0xffffbe8f`e412c940 l 20
ffffbe8f`e412c940 00000000`00000000 00000000`008b0058
ffffbe8f`e412c950 00000000`00000000 ffffd181`c6bf5810
ffffbe8f`e412c960 ffffa883`8f349000 00000810`00004096
ffffbe8f`e412c970 00000000`000028ff 00000000`000028fe //大小是0x4096 需要5个物理页,MDL结构的后面就记录了这5个物理页
ffffbe8f`e412c980 00000000`000013fd 00000000`000028fc
ffffbe8f`e412c990 00000000`000028fb 00000000`00000000 //物理页结束
ffffbe8f`e412c9a0 00000000`00000000 00000000`00000000
ffffbe8f`e412c9b0 00000000`00000000 00000000`00000000
ffffbe8f`e412c9c0 00000000`00000000 00000000`00000000

那就可以得出真正的MDL结构其实是这样的
typedef struct _MDL {struct _MDL *Next;CSHORT Size;CSHORT MdlFlags;struct _EPROCESS *Process;PVOID MappedSystemVa; /* see creators for field size annotations. */PVOID StartVa; /* see creators for validity; could be address 0. */ULONG ByteCount;ULONG ByteOffset;PPFN_NUMBER pfnNumber[1]; //该数组大小=ByteCount/0x1000+1
} MDL, *PMDL;
映射3环地址
BOOLEAN MapSection()
{OBJECT_ATTRIBUTES ob = { 0 };ob.Length = 0x30;ob.Attributes = OBJ_KERNEL_HANDLE;LARGE_INTEGER MaxSize;MaxSize.QuadPart = 0x1000;HANDLE SectionHandle = NULL;if (!ZwCreateSection(&SectionHandle, SECTION_MAP_READ | SECTION_QUERY, &ob, &MaxSize, PAGE_READONLY, 0x8000000, 0)){ULONG_PTR ViewSize;PVOID BaseAddress;BaseAddress = 0;ViewSize = 0x1000;if (!ZwMapViewOfSection(SectionHandle,(HANDLE)0xFFFFFFFFFFFFFFFF,&BaseAddress, //三环地址0,0x1000,0,&ViewSize,ViewUnmap,0,PAGE_READONLY)){//pMdl在新分配的内存里面MDL Mdl = {0};Mdl.Next = NULL;Mdl.Size = 8 * ((((ULONG64)BaseAddress & 0xfff + 4095) >> 12) + 7);Mdl.MdlFlags = 0;Mdl.MappedSystemVa = NULL;Mdl.StartVa = (ULONG64)BaseAddress & 0xFFFFFFFFFFFFF000; Mdl.ByteCount = 0x1000;Mdl.ByteOffset = (ULONG64)BaseAddress & 0xfff;__try{MmProbeAndLockPages(&Mdl, UserMode, IoReadAccess);}__except (1){//锁定内存失败ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFF, BaseAddress);ZwClose(SectionHandle);return FALSE;}PVOID MapBuf = MmMapLockedPagesSpecifyCache(&Mdl, 0, MmCached, 0, 0, NormalPagePriority);if (MapBuf){//把应用层内存映射到内核中 MappedSystemVa字段就是MapBuf}MmUnlockPages(&Mdl);ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFF, BaseAddress);}}if (SectionHandle){ZwClose(SectionHandle);SectionHandle = NULL;}return TRUE;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
