如何用C++蜜罐检测Windows中修改/删除特定文件的进程?
检测修改/删除特定诱饵文件的进程(Windows C++实现)
方法一:使用ETW(用户态实现,无需驱动)
ETW(Event Tracing for Windows)可捕获内核级文件操作事件,包含触发操作的进程ID,通过该ID可反向获取进程具体信息,适合快速搭建测试环境。
核心步骤
- 启用
Microsoft-Windows-Kernel-File事件提供者,捕获FileDelete(删除)和FileWrite(修改)事件。 - 在事件回调中解析事件数据,提取目标文件路径与进程ID。
- 通过
OpenProcess和GetModuleFileNameEx将进程ID转换为进程路径/名称。
代码片段
#include <windows.h> #include <evntrace.h> #include <evntcons.h> #include <psapi.h> #include <iostream> #include <string> #pragma comment(lib, "advapi32.lib") #pragma comment(lib, "psapi.lib") // ETW事件回调函数 VOID WINAPI EtwEventCallback(PEVENT_RECORD pEventRecord) { // 匹配Microsoft-Windows-Kernel-File提供者GUID const GUID fileProviderGuid = {0x3D6FA8D0, 0xFE05, 0x11D0, {0x9D, 0xDA, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C}}; if (pEventRecord->EventHeader.ProviderId != fileProviderGuid) return; DWORD processId = pEventRecord->EventHeader.ProcessId; EVENT_DATA_DESCRIPTOR dataDesc; EventDataDescGet(&dataDesc, pEventRecord->UserData, pEventRecord->UserDataLength); wchar_t* filePath = (wchar_t*)dataDesc.DataPtr; // 检查是否为目标诱饵文件 if (wcscmp(filePath, L"C:\\HoneyPot\\bait.txt") != 0) return; // 获取进程路径 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); if (hProcess == NULL) return; wchar_t processPath[MAX_PATH]; if (GetModuleFileNameExW(hProcess, NULL, processPath, MAX_PATH)) { std::wcout << L"检测到操作诱饵文件的进程:" << processPath << L" (PID: " << processId << L")" << std::endl; } CloseHandle(hProcess); } int main() { TRACEHANDLE sessionHandle = 0; ULONG bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + MAX_PATH * sizeof(WCHAR); EVENT_TRACE_PROPERTIES* pSessionProps = (EVENT_TRACE_PROPERTIES*)malloc(bufferSize); ZeroMemory(pSessionProps, bufferSize); pSessionProps->Wnode.BufferSize = bufferSize; pSessionProps->Wnode.Flags = WNODE_FLAG_TRACED_GUID; pSessionProps->EnableFlags = EVENT_TRACE_FLAG_FILE_IO; wcscpy_s(pSessionProps->LoggerName, MAX_PATH, L"HoneyPotMonitor"); // 创建ETW会话 if (StartTrace(&sessionHandle, pSessionProps->LoggerName, pSessionProps) != ERROR_SUCCESS) { std::cerr << "启动ETW会话失败" << std::endl; free(pSessionProps); return 1; } // 启用文件操作事件提供者 if (EnableTraceEx2(sessionHandle, (LPGUID)&fileProviderGuid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_VERBOSE, 0, 0, 0, NULL) != ERROR_SUCCESS) { std::cerr << "启用事件提供者失败" << std::endl; ControlTrace(sessionHandle, pSessionProps->LoggerName, pSessionProps, EVENT_TRACE_CONTROL_STOP); free(pSessionProps); return 1; } // 开始处理事件 EVENT_TRACE_LOGFILE traceLog = {0}; traceLog.LoggerName = pSessionProps->LoggerName; traceLog.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; traceLog.EventRecordCallback = EtwEventCallback; std::cout << "监控已启动,按任意键退出..." << std::endl; ProcessTrace(&traceLog, 1, NULL, NULL); // 清理资源 ControlTrace(sessionHandle, pSessionProps->LoggerName, pSessionProps, EVENT_TRACE_CONTROL_STOP); free(pSessionProps); return 0; }
方法二:使用Minifilter驱动(内核态实现,高可靠性)
Minifilter是文件系统过滤驱动,可在文件操作执行前/后拦截事件,直接获取触发进程信息,无遗漏,适合精准检测勒索软件行为。
核心步骤
- 实现Minifilter驱动,注册
PreOperationCallback回调函数。 - 在回调中检查目标文件路径,匹配诱饵文件。
- 通过
IoGetCurrentProcess获取当前进程对象,PsGetProcessImageFileName获取进程名称。
代码片段(驱动核心部分)
#include <fltKernel.h> PFLT_FILTER gFilterHandle; // 预操作回调,拦截文件修改/删除操作 FLT_PREOP_CALLBACK_STATUS PreOperationCallback( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID* CompletionContext ) { UNREFERENCED_PARAMETER(CompletionContext); // 过滤目标操作类型:写入、删除、修改文件信息 if (Data->Iopb->MajorFunction != IRP_MJ_WRITE && Data->Iopb->MajorFunction != IRP_MJ_DELETE && Data->Iopb->MajorFunction != IRP_MJ_SET_INFORMATION) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } // 获取文件路径 UNICODE_STRING filePath; NTSTATUS status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &filePath); if (!NT_SUCCESS(status)) return FLT_PREOP_SUCCESS_NO_CALLBACK; // 匹配诱饵文件 if (RtlCompareUnicodeString(&filePath, &(UNICODE_STRING)RTL_CONSTANT_STRING(L"C:\\HoneyPot\\bait.txt"), TRUE) == 0) { PEPROCESS process = IoGetCurrentProcess(); CHAR processName[16]; PsGetProcessImageFileName(process, processName, sizeof(processName)); DbgPrint("检测到操作诱饵文件的进程:%s\n", processName); } FltReleaseFileNameInformation(&filePath); return FLT_PREOP_SUCCESS_NO_CALLBACK; } // 驱动入口 NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); FLT_REGISTRATION filterRegistration = { sizeof(FLT_REGISTRATION), FLT_REGISTRATION_VERSION, 0, NULL, { { IRP_MJ_WRITE, 0, PreOperationCallback, NULL }, { IRP_MJ_DELETE, 0, PreOperationCallback, NULL }, { IRP_MJ_SET_INFORMATION, 0, PreOperationCallback, NULL }, { IRP_MJ_OPERATION_END } }, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; NTSTATUS status = FltRegisterFilter(DriverObject, &filterRegistration, &gFilterHandle); if (NT_SUCCESS(status)) { status = FltStartFiltering(gFilterHandle); if (!NT_SUCCESS(status)) FltUnregisterFilter(gFilterHandle); } return status; } // 驱动卸载 NTSTATUS DriverUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags) { UNREFERENCED_PARAMETER(Flags); FltUnregisterFilter(gFilterHandle); return STATUS_SUCCESS; }
方法对比
- ETW方法:用户态实现,无需驱动签名,开发成本低;但可能丢失少量事件,无法捕获内核态直接操作文件的行为。
- Minifilter方法:内核态实现,检测无遗漏,覆盖所有文件操作场景;但需要驱动签名(测试环境可开启测试签名模式),开发复杂度高,需掌握Windows内核编程知识。
内容的提问来源于stack exchange,提问作者ericbetin4e2
相关产品推荐
相关产品推荐

