遍歷核心驅動模組
PsLoadedModuleList是Windows載入的所有核心模組構成的連結串列的表頭,利用它可以列舉所有這些模組的資訊,下面是WRK中對PsLoadedModuleList的定義:LIST_ENTRY PsLoadedModuleList;
核心在載入驅動時,會為每一個驅動建立一個驅動物件(DRIVER_OBJECT),下面是驅動物件的資料結構:
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORTSize;
PDEVICE_OBJECT DeviceObject; //指向裝置物件,所有的裝置物件構成一個連結串列
ULONGFlags; //驅動程式標誌
PVOIDDriverStart; //驅動程式映像起始地址
ULONGDriverSize; //驅動程式映像大小
PVOIDDriverSection; //指向驅動程式映像的記憶體區物件
PDRIVER_EXTENSIONDriverExtension; //指向驅動程式物件的擴充套件部分
UNICODE_STRINGDriverName; //驅動程式名稱
PUNICODE_STRINGHardwareDatabase
PFAST_IO_DISPATCHFastIoDispatch; //指向快速I/O的分發結構
PDRIVER_INITIALIZE DriverInit; //驅動程式的初始化例程
PDRIVER_STARTIO DriverStartIo; //驅動程式的啟動I/O例程
PDRIVER_UNLOADDriverUnload; //驅動程式的解除安裝例程
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
typedef
DRIVER_OBJECT物件的DriverExtension成員指向的是驅動程式映像的記憶體區物件,它的結構KLDR_DATA_TABLE_ENTRY的定義是:
typedef struct_KLDR_DATA_TABLE_ENTRY {
LIST_ENTRYInLoadOrderLinks;
PVOIDExceptionTable;
ULONG ExceptionTableSize;
PVOIDGpValue;
PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;
PVOID DllBase; //指明瞭驅動的載入基址
PVOID EntryPoint;
ULONGSizeOfImage;
UNICODE_STRING FullDllName; //指明瞭驅動模組檔案的全路徑
UNICODE_STRING BaseDllName; //指明瞭驅動模組的名稱
ULONGFlags;
USHORTLoadCount;
USHORT__Unused5;
PVOIDSectionPointer;
ULONGCheckSum;
PVOID LoadedImports;
PVOIDPatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
這個結構體中的第一個成員InLoadOrderLinks是一個LIST_ENTRY的結構. 每個驅動模組都被加入到這個雙向連結串列中.我們只要遍歷這個雙向連結串列就能枚舉出所有的驅動模組,下面的DbgObjGetSysModuleInfo函式可以遍歷核心所有的驅動模組:
NTSTATUS DbgObjGetSysModuleInfo(PDRIVER_OBJECTlpDriverObject)
{
PKLDR_DATA_TABLE_ENTRY ModuleEntry =NULL;
PLIST_ENTRY PsLoadedModuleList =NULL;
PLIST_ENTRY ListEntry =NULL;
PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)lpDriverObject->DriverSection;
//系統模組連結串列的連結串列頭
PsLoadedModuleList =ldr->InLoadOrderLinks.Flink;
ListEntry =PsLoadedModuleList->Flink;
while (ListEntry != PsLoadedModuleList)
{
ModuleEntry =CONTAINING_RECORD(ListEntry,KLDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
if (&ModuleEntry->BaseDllName.Buffer != 0){
DbgPrint("Nt Module Fileis %wZ\n",&ModuleEntry->BaseDllName);
}
//指向下一個連結串列
ListEntry =ListEntry->Flink;
}
returnSTATUS_SUCCESS;
}
下面的程式碼是將驅動的記憶體區物件的DllBase或FullDllName.buffer填為0,它可以簡單地繞過一些檢測:
PVOID pDllBase =NULL;
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->DllBase = pDllBase;
KdPrint(("Ddvp-> Call DriverUnload \n"));
return;
}
VOID Reinitialize(PDRIVER_OBJECTDriverObject,PVOID Context,ULONGCount)
{
((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->DllBase = NULL;//將DllBase填0
}
NTSTATUS DriverEntry(INPDRIVER_OBJECTDriverObject,INPUNICODE_STRINGRegPath)
{
NTSTATUSStatus =STATUS_SUCCESS;
pDllBase = ((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->DllBase;
IoRegisterDriverReinitialization(DriverObject,Reinitialize,NULL);
((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->FullDllName.Buffer = NULL; //將FullDllName.Buffer填0
DriverObject->DriverUnload = &DriverUnload;
return STATUS_SUCCESS;
}
注:不能直接修改DllBase的值,否則會藍屏。必須使用函式IoRegisterDriverReinitialization的回撥函式來修改,下面是該函式的宣告:
VOID
IoRegisterDriverReinitialization(
INPDRIVER_OBJECT DriverObject, //指向驅動的驅動物件
INPDRIVER_REINITIALIZE DriverReinitializationRoutine, //被呼叫的重初始化例程的地址
INPVOID Context //指向傳遞給驅動程式的初始化例程上下文指標
)
如果要隱藏某個驅動,就要將它從PsLoadedModuleList這個雙向連結串列中去掉。
下圖是修改前Flink和Blink指標的指向情況
下圖是修改後Flink和Blink指標的指向情況
下面的函式通過修改雙向連結串列來實現驅動的隱藏。
VOID HideDriver(IN PDRIVER_OBJECTpDriverObject)
{
PLIST_ENTRY entry = &((PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection)->InLoadOrderLinks;
PKLDR_DATA_TABLE_ENTRYModuleEntry =CONTAINING_RECORD(entry,KLDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
KdPrint(("隱藏驅動 %ws 成功!\n", ModuleEntry->BaseDllName.Buffer));
//通過RemoveEntryList函式修改連結串列的指標
RemoveEntryList(entry);
entry->Flink = entry;
entry->Blink = entry;
}
在Xuetr中還是可以檢測出來
如果想要隱藏的更隱蔽,還要從以下幾個方面進行處理:
一、從PsLoadedModuleList連結串列中斷開,此方法僅對ZwQuerySystemInformation(SystemModuleInformation)有效
二、從\Driver物件目錄刪除
三、從TypeList中刪除
四、抹PE映象
五、抹DriverObject