監視程序在後台靜默運行,實時捕獲關鍵系統變更:
核心價值:
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。
BOOL FindNextChangeNotification(HANDLE hChangeHandle);
處理完一次通知後必須調用此函數重置句柄,否則不再接收後續事件。
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);
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
);
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)。
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。
FILE_LIST_DIRECTORY | READ_CONTROL 權限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 原理,配合上層框架封裝,即可構建企業級的系統變更審計系統。