windows:驅動模塊隱藏

   windwos下想要搞點事,權限固然是越大越好;驅動模塊天生在0環,和操做提供平級,你們互相是兄弟,因此不少外掛、木馬、病毒都會使用驅動達到本身的目的。那麼問題來了:PCHUNTER這種工具能查到系統裏面全部驅動模塊,外掛\木馬\病毒該怎麼隱藏了?windows

         

 

   常見隱藏驅動的方式:函數

  •  驅動模塊斷鏈
  •    調用MiProcessLoadEntry刪除驅動對象(聽說不會觸發PG)
  •    清理MmUnloadDriver List 和 PiDDBCacheTable兩處
  •    driveEntry返回失敗
  •    驅動模塊加載後當即卸載

  今天介紹一種driveEntry返回失敗隱藏驅動的方法 —— DriverEntry返回失敗;工具

  windows會根據DriverEntry的返回值判斷驅動是否加載成功。若是返回成功,會在註冊表詳細記錄,並將sys文件複製到System32/drivers目錄下;若是失敗,會回收執行代碼時分配的棧空間,但此時代碼已經執行,該方法隱藏驅動最核心的點就在這了:spa

  •  driverEntry執行的時候操做系統分配的棧內存,執行完畢會被回收,數據和代碼都不會留下,只能額外在堆空間分配一塊內存,把須要繼續執行的代碼和數據(本實驗是回調函數)都留在堆上
  •     本例中,回調函數須要打印。但call函數後面的操做數都是相對偏移,不是絕對地址。回調函數被複制到堆上,自身位置改變,打印函數的偏移確定也變了,這裏須要重定位,怎麼辦?

    先自定義一個函數指針,指向打印函數,但地址隨便用個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把操做系統內核的全部操做都能監控到,因此如今的對抗進一步演變成了對系統更底層權限的爭奪;誰先得到了更底層的權限,誰就能監控上一層的一舉一動。

  

相關文章
相關標籤/搜索