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 類型定義的截圖。

原文鏈接:請訪問看雪論壇


分享到:


相關文章: