萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 電腦基礎知識 >  >> 健康知識

Windows 核心層進程/執行緒監控驅動開發:動態卸載藍屏問題根因與解決方案

問題背景

使用 PsSetCreateProcessNotifyRoutine、PsSetCreateThreadNotifyRoutine 註冊回調實現進程/執行緒監控時,驅動動態卸載若未清除回調,會導致 BUGCHECK 0xCE: DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS。原因:驅動卸載後,系統仍嘗試呼叫已卸載記憶體中的回調函數指標。

核心資料結構逆向分析 (Windows 2000 原始碼)

// 進程建立回調陣列
#define PSP_MAX_CREATE_PROCESS_NOTIFY 8
ULONG PspCreateProcessNotifyRoutineCount;
PCREATE_PROCESS_NOTIFY_ROUTINE PspCreateProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];

// 執行緒建立回調陣列
#define PSP_MAX_CREATE_THREAD_NOTIFY 8
ULONG PspCreateThreadNotifyRoutineCount;
PCREATE_THREAD_NOTIFY_ROUTINE PspCreateThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];

// 回調函數原型
typedef VOID (*PCREATE_THREAD_NOTIFY_ROUTINE)(IN HANDLE ProcessId, IN HANDLE ThreadId, IN BOOLEAN Create);
typedef VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE)(IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create);

官方 API 行為差異

API註冊移除機制
PsSetCreateProcessNotifyRoutine陣列尋找 NULL 填入,計數器 +1傳入 Remove=TRUE,匹配函數指標設 NULL,計數器 -1
PsSetCreateThreadNotifyRoutine (XP 前)同進程回調無官方移除 API,導致無法乾淨卸載
PsRemoveCreateThreadNotifyRoutine (XP/2003+)—遍歷陣列匹配指標清零,配合 ExWaitForRundownProtectionRelease 等待進行中回調完成

ICESword 2000 版變通做法

釋放 detport.sys 常駐核心、隱藏檔案、從不卸載,規避藍屏但屬權宜之計。

通用解決方案:手動定位並清零回調陣列

  1. 透過模式掃描或匯出表定位 PspCreateThreadNotifyRoutine 陣列基址
  2. 驅動卸載例程 (DriverUnload) 中遍歷陣列,將屬於本驅動的函數指標設為 NULL
  3. 同步處理進程回調陣列(雖有官方 API,手動清零更保險)
  4. 確保所有待決回調完成後再返回卸載流程

關鍵實現片段 (含遠端執行緒監控)

// 驅動卸載時清零回調陣列
VOID CleanupNotifyRoutines() {
    // 定位陣列基址 (需根據 OS 版本動態解析)
    PULONG pThreadArray = LocatePspCreateThreadNotifyRoutineArray();
    PULONG pProcessArray = LocatePspCreateProcessNotifyRoutineArray();

    for (INT i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
        if (pThreadArray[i] == (ULONG)MyThreadNotifyRoutine)
            pThreadArray[i] = 0;
    }
    for (INT i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
        if (pProcessArray[i] == (ULONG)MyProcessNotifyRoutine)
            pProcessArray[i] = 0;
    }
}

// 遠端執行緒建立偵測:掛鉤 NtCreateThreadEx / RtlCreateUserThread
NTSTATUS HookedNtCreateThreadEx(...) {
    // 記錄目標進程 PID、執行緒起始位址、呼叫堆疊
    LogRemoteThreadCreation(TargetProcess, StartAddress);
    return OriginalNtCreateThreadEx(...);
}

版本相容性處理

  • 透過 RtlGetVersion 取得 BuildNumber,載入對應偏移量表
  • 支援 Win2K/XP/2003/Vista/Win7 多版本動態定位
  • 簽名驅動載入需測試模式或正式憑證

工程化建議

  1. 封裝為獨立庫,提供 InstallMonitor()/UninstallMonitor() 介面
  2. 加入自我完整性檢查(CRC/數位簽章)防篡改
  3. 配合 ETW (Event Tracing for Windows) 輸出事件,減少自定義日誌機制
  4. 測試矩陣:各 OS 版本 × 啟用/停用 Driver Verifier × 壓力測試
copyright © 萬盛學電腦網 all rights reserved