MDL(Memory Descriptor List),指記憶體描述符表,它包含了該記憶體地區的起始地址、擁有者進程、位元組數量以及標誌。MDL結構定義在ntddk.h中,具體結構如下:
Typedef struct _MDL{
Struct _MDL *Next;
CSHORT Size;
CSHORT MdlFlags;
Struct _EPROCESS *Process;
PVOID MappedSystemVa;
PVOID StartVa;
ULONG ByteCount;
ULONG ByteOffset;
} MDL, *PMDL;
為了修改記憶體標誌,需要聲明一個結構,該結構用於強制轉換由Windows核心匯出的KeServiceDescriptorTable變數的類型。該結構如下:
typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //Used only in checked build unsigned int NumberOfServices; unsigned char *ParamTableBase; } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; |
《Rootkits》書中給的源碼如下所示,儘管去能夠在windows XP下編譯過,並且能夠執行,但其中的有些函數已經過時,已有新的函數替代了。下面分別描述:
g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4); if(!g_pmdlSystemCall) return STATUS_UNSUCCESSFUL; MmBuildMdlForNonPagedPool(g_pmdlSystemCall); // Change the flags of the MDL g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode); |
MmCreateMdl函數的定義如下
PMDL MmCreateMdl( IN PMDL MemoryDescriptorList OPTIONAL, IN PVOID Base, IN SIZE_T Length ); |
新的函數為
PMDL IoAllocateMdl( __in_opt PVOID VirtualAddress, __in ULONG Length, __in BOOLEAN SecondaryBuffer, __in BOOLEAN ChargeQuota, __inout_opt PIRP Irp OPTIONAL ); |
IoAllocateMdl的作用是分配一個MDL結構,也就是將系統的一段記憶體空間映射到另外一個地方,然後修改這部分記憶體的保護屬性,並修改其內容,以達到修改受保護記憶體的目的。第一參數為MDL記憶體的起始地址,第二個參數為MDL的長度。
由於IoAllocateMdl建立的MDL都是指向非分頁的虛擬記憶體的buffer中的,所以需要MmBuildMdlForNonPagedPool函數來在實體記憶體上更新這個MDL。
MmMapLocakedPages函數的定義如下
PVOID MmMapLockedPages( IN PMDL MemoryDescriptorList, IN KPROCESSOR_MODE AccessMode ); |
新的函數為MmMapLockedPagesSpecifyCache,它的定義為
PVOID MmMapLockedPagesSpecifyCache( __in PMDLX MemoryDescriptorList, __in KPROCESSOR_MODE AccessMode, __in MEMORY_CACHING_TYPE CacheType, __in_opt PVOID BaseAddress, __in ULONG BugCheckOnFailure, __in MM_PAGE_PRIORITY Priority ); |
它的作用是用來鎖定記憶體中的MDL頁,允許使用者修改其屬性。
所以使用新函數後修改的代碼如下:
//g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, //KeServiceDescriptorTable.NumberOfServices*4); g_pmdlSystemCall = IoAllocateMdl(KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4,FALSE, FALSE, NULL ); if(!g_pmdlSystemCall) return STATUS_UNSUCCESSFUL; MmBuildMdlForNonPagedPool(g_pmdlSystemCall); // Change the flags of the MDL // MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode); MappedSystemCallTable = MmMapLockedPagesSpecifyCache(g_pmdlSystemCall, KernelMode, MmWriteCombined, NULL, FALSE, 0); MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode); |