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

監視程序設計實戰:文件系統與注冊表變更實時捕獲

     編輯:VC 教學

什麼是監視程序?

監視程序在後台靜默運行,實時捕獲關鍵系統變更:

  • 文件系統:創建、刪除、重命名、屬性變更、內容修改
  • 注冊表:鍵值增刪改、權限變更
  • 進程/線程:啟動、退出、注入

核心價值:

  1. 軟件安裝審計:記錄安裝前後差異,生成精準卸載腳本,徹底清理殘留
  2. 安全防護:檢測惡意軟件竄改系統關鍵路徑/啟動項
  3. 合規審計:滿足等保、GDPR等合規要求的變更留痕

核心 API 深度解析

FindFirstChangeNotification - 建立監視句柄

HANDLE FindFirstChangeNotification(
    LPCTSTR lpPathName,      // 監視目錄路徑
    BOOL    bWatchSubtree,   // 是否遞歸子目錄
    DWORD   dwNotifyFilter   // 監視事件過濾器
);

dwNotifyFilter 常用標誌位:

常量含義
FILE_NOTIFY_CHANGE_FILE_NAME文件創建/刪除/重命名
FILE_NOTIFY_CHANGE_DIR_NAME目錄創建/刪除/重命名
FILE_NOTIFY_CHANGE_ATTRIBUTES屬性變更
FILE_NOTIFY_CHANGE_SIZE文件大小變化
FILE_NOTIFY_CHANGE_LAST_WRITE最後寫入時間變化
FILE_NOTIFY_CHANGE_SECURITY安全描述符變化

成功返回目錄監視句柄,失敗返回 INVALID_HANDLE_VALUE。

FindNextChangeNotification - 繼續監視

BOOL FindNextChangeNotification(HANDLE hChangeHandle);

處理完一次通知後必須調用此函數重置句柄,否則不再接收後續事件。

WaitForSingleObject - 事件等待

DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

阻塞等待監視句柄觸發,返回 WAIT_OBJECT_0 表示有事件發生。

完整監視循環模型

// 1. 創建監視句柄
HANDLE hWatch = FindFirstChangeNotification(
    L"C:\\WatchedDir", TRUE,
    FILE_NOTIFY_CHANGE_FILE_NAME |
    FILE_NOTIFY_CHANGE_LAST_WRITE |
    FILE_NOTIFY_CHANGE_DIR_NAME);

if (hWatch == INVALID_HANDLE_VALUE) {
    // 錯誤處理
    return;
}

// 2. 事件循環
while (running) {
    DWORD dwWait = WaitForSingleObject(hWatch, INFINITE);
    if (dwWait == WAIT_OBJECT_0) {
        // 3. 這裡僅知道"有變化",需配合ReadDirectoryChangesW獲取具體信息
        ProcessChanges(); 

        // 4. 重置句柄繼續監視
        if (!FindNextChangeNotification(hWatch)) break;
    }
}

// 5. 清理
FindCloseChangeNotification(hWatch);

進階方案:ReadDirectoryChangesW 獲取詳細變更

FindFirstChangeNotification 只能告知"有變化",無法獲取具體文件名、操作類型。生產級監視需使用:

BOOL ReadDirectoryChangesW(
    HANDLE hDirectory,           // 目錄句柄(FILE_FLAG_BACKUP_SEMANTICS)
    LPVOID lpBuffer,             // 接收FILE_NOTIFY_INFORMATION數組
    DWORD nBufferLength,         // 緩衝區大小
    BOOL bWatchSubtree,          // 遞歸子目錄
    DWORD dwNotifyFilter,        // 過濾器(同FindFirstChangeNotification)
    LPDWORD lpBytesReturned,     // 實際返回字節數
    LPOVERLAPPED lpOverlapped,   // 異步操作用
    LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

FILE_NOTIFY_INFORMATION 結構

typedef struct _FILE_NOTIFY_INFORMATION {
    DWORD NextEntryOffset;  // 下一條記錄偏移(0表示結束)
    DWORD Action;           // 操作類型
    DWORD FileNameLength;   // 文件名字節長度
    WCHAR FileName[1];      // 文件名(非null結尾)
} FILE_NOTIFY_INFORMATION;

Action 值:FILE_ACTION_ADDED (1)、FILE_ACTION_REMOVED (2)、FILE_ACTION_MODIFIED (3)、FILE_ACTION_RENAMED_OLD_NAME (4)、FILE_ACTION_RENAMED_NEW_NAME (5)。

注冊表監視:RegNotifyChangeKeyValue

LONG RegNotifyChangeKeyValue(
    HKEY hKey,                // 監視的鍵
    BOOL bWatchSubtree,       // 遞歸子鍵
    DWORD dwNotifyFilter,     // 過濾器
    HANDLE hEvent,            // 同步事件對象
    BOOL fAsynchronous        // 異步模式
);

dwNotifyFilter:REG_NOTIFY_CHANGE_NAME、REG_NOTIFY_CHANGE_ATTRIBUTES、REG_NOTIFY_CHANGE_LAST_SET、REG_NOTIFY_CHANGE_SECURITY。

工程化最佳實踐

  1. 異步 I/O + 完成端口:避免阻塞線程,支持海量目錄並發監視
  2. 緩衝區管理:預分配 64KB 緩衝區,防止高頻變更導致溢出丟失事件
  3. 去抖動處理:同一文件短時間多次觸發合併為單一事件
  4. 權限最小化:以標準用戶權限運行,僅請求必要目錄的 FILE_LIST_DIRECTORY | READ_CONTROL 權限
  5. 持久化存儲:異步寫入 SQLite/LevelDB,支持離線查詢與匯出
  6. 自我保護:防止監視進程被終止、監視目錄被刪除導致句柄失效

經典應用場景代碼片段(C# FileSystemWatcher 封裝)

public class DirectoryMonitor : IDisposable {
    private FileSystemWatcher _watcher;
    private BlockingCollection _queue = new BlockingCollection();
    private Task _processTask;

    public DirectoryMonitor(string path, bool recursive) {
        _watcher = new FileSystemWatcher(path) {
            IncludeSubdirectories = recursive,
            NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName 
                         | NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.Attributes,
            EnableRaisingEvents = true
        };
        _watcher.Created += OnChanged;
        _watcher.Deleted += OnChanged;
        _watcher.Renamed += OnRenamed;
        _watcher.Changed += OnChanged;
        _watcher.Error += OnError;

        _processTask = Task.Run(ProcessQueue);
    }

    private void OnChanged(object sender, FileSystemEventArgs e) {
        _queue.Add(new FileChangeEvent(e.ChangeType, e.FullPath, e.Name));
    }

    private void OnRenamed(object sender, RenamedEventArgs e) {
        _queue.Add(new FileChangeEvent(WatcherChangeTypes.Renamed, e.FullPath, e.Name, e.OldName));
    }

    private void ProcessQueue() {
        foreach (var evt in _queue.GetConsumingEnumerable()) {
            // 持久化、過濾、告警等業務邏輯
            LogToDatabase(evt);
        }
    }

    public void Dispose() {
        _watcher.EnableRaisingEvents = false;
        _watcher.Dispose();
        _queue.CompleteAdding();
        _processTask.Wait();
    }
}

掌握底層 API 原理,配合上層框架封裝,即可構建企業級的系統變更審計系統。

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