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 類型定義的截圖。
原文鏈接:請訪問看雪論壇
閱讀更多 看雪學院 的文章