MDL突破 SSDT的只读访问限制(二)

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 类型定义的截图。

原文链接:请访问看雪论坛


分享到:


相關文章: