DbgPrint(" KiServiceTable 地址,与上面一致: %X\r\n", os_ki_service_table);
DBG_TRACE("MapMdl", ".......表中的系统服务地址可以通过 dps 转储 os_ki_service_table 查看!..........r\n");
try {
mdl_pointer = IoAllocateMdl(VirtualAddress, 0x191 * 4, FALSE, FALSE, NULL);
if (mdl_pointer == NULL) {
DBG_TRACE("MapMdl", ".........无法分配一个 MDL 来描述原始的 KiServiceTable !..........\r\n");
return NULL;
}
DbgPrint("分配的 MDL 指针自身的地址: %p ,可用 dd 转储它持有的地址\r\n", &mdl_pointer);
DbgPrint("分配的 MDL 指针指向一个 _MDL 的地址: %p,与 dd %p 的输出一致,它用来描述原始的 KiServiceTable\r\n", mdl_pointer, &mdl_pointer);
backup_mdl_ptr = mdl_pointer;
// 这里设置的两个断点是为了观察调用前后的 _MDL.MdlFlags 如何变化 __asm {
int 3;
}
if (mdl_pointer->MdlFlags & MDL_ALLOCATED_FIXED_SIZE)
{
DBG_TRACE("MapMdl", ".....IoAllocateMdl() 分配的 MDL 结构有固定大小(MDL_ALLOCATED_FIXED_SIZE)........\r\n");
}
MmProbeAndLockPages(mdl_pointer, KernelMode, IoWriteAccess);
__asm {
int 3;
}
if ((mdl_pointer->MdlFlags & MDL_ALLOCATED_FIXED_SIZE) &&
(mdl_pointer->MdlFlags & MDL_WRITE_OPERATION) &&
(mdl_pointer->MdlFlags & MDL_PAGES_LOCKED))
{
DBG_TRACE("MapMdl", " MmProbeAndLockPages() 以写权限(MDL_WRITE_OPERATION)把 MDL 描述的原始 KiServiceTable 所在页面锁定到物理内存中(MDL_PAGES_LOCKED)\r\n");
}
mapped_addr = MmGetSystemAddressForMdlSafe(mdl_pointer, NormalPagePriority);
// 此处顺便观察 _MDL.MdlFlags 的变化 __asm {
int 3;
}
if (
(mdl_pointer->MdlFlags & MDL_ALLOCATED_FIXED_SIZE) &&
(mdl_pointer->MdlFlags & MDL_WRITE_OPERATION) &&
(mdl_pointer->MdlFlags & MDL_PAGES_LOCKED) &&
(mdl_pointer->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
)
{
DBG_TRACE("MapMdl", " MmGetSystemAddressForMdlSafe() 把 MDL 结构描述的原始 KiServiceTable 映射到另一个内核虚拟地址(MDL_MAPPED_TO_SYSTEM_VA)\r\n");
}
DbgPrint("MmGetSystemAddressForMdlSafe() 调用依然可以通过原始的 MDL 指针访问 _MDL 的地址: %p\r\n", mdl_pointer);
DbgPrint("也可以通过备份的 MDL 指针访问 _MDL 的地址: %p,这都说明 MDL 结构尚未被释放,\r\n", backup_mdl_ptr);
pfn_array_follow_mdl = (PPFN_NUMBER)(mdl_pointer + 1);
DbgPrint(" MDL 结构后偏移 %2x 地址处是一个 PFN 数组,用来存储该 MDL 描述的虚拟缓冲区映射到的物理页框号\r\n", mdl_header_length);
DbgPrint(" 该 PFN 数组的起始地址为:%p\r\n", pfn_array_follow_mdl);
DbgPrint(" 第一个物理页框号为:%p\r\n", *pfn_array_follow_mdl);
return mapped_addr;
}
except (STATUS_ACCESS_VIOLATION) {
IoFreeMdl(mdl_pointer);
return NULL;
}
}
void UnMapMdl(PMDL mdl_pointer, PVOID baseaddr)
{
if (mdl_pointer != backup_mdl_ptr) {
DBG_TRACE("UnMapMdl", ".......先解锁备份 MDL 映射的页面,然后释放备份的 MDL........");
MmUnlockPages(backup_mdl_ptr); // 此例程的效果是,无法通过映射的系统地址来访问 KiServiceTable,且 _MDL 结构中各字段已发生变化, IoFreeMdl(backup_mdl_ptr); // 此例程的效果是,MDL 指针不再持有 _MDL 结构的地址 if (backup_mdl_ptr == NULL) {
DBG_TRACE("UnMapMdl", ".............解锁页面,释放备份 MDL 完成!................");
}
return;
}
DBG_TRACE("UnMapMdl", ".........原始 MDL 未被修改,解锁它映射的页面后释放它...........");
// 如果前面使用 MmBuildMdlForNonPagedPool() ,就不能执行下面前2个操作 //MmUnmapLockedPages(baseaddr, mdl); MmUnlockPages(mdl_pointer);
IoFreeMdl(mdl_pointer);
if (mdl_pointer == NULL) {
DBG_TRACE("UnMapMdl", ".............解锁页面,释放原始 MDL 完成!................");
}
return;
}
头文件 dbgmsg.h 内容如下,它仅仅是在预处理阶段替换为 DbgPrint() 的一些可变参数罢了,没啥黑科技可言:
#ifdef LOG_OFF
#define DBG_TRACE(src,msg)
#define DBG_PRINT1(arg1)
#define DBG_PRINT2(fmt,arg1)
#define DBG_PRINT3(fmt,arg1,arg2)
#define DBG_PRINT4(fmt,arg1,arg2,arg3)
#else
#define DBG_TRACE(src,msg) DbgPrint("[%s]:%s\n",src,msg)
#define DBG_PRINT1(arg1) DbgPrint("%s",arg1)
#define DBG_PRINT2(fmt,arg1) DbgPrint(fmt,arg1)
#define DBG_PRINT3(fmt,arg1,arg2) DbgPrint(fmt,arg1,arg2)
#define DBG_PRINT4(fmt,arg1,arg2,arg3) DbgPrint(fmt,arg1,arg2,arg3)
另一个包含文件 datatype.h 的所有内容, 请参考第一部分:就是那张 DWORD、WORD、BYTE 类型定义的截图。
原文链接:请访问看雪论坛
閱讀更多 看雪學院 的文章