获取发起DNS请求的真实进程及请求域名,不是取服务进程svchost.exe,做网络过滤或网络加速用得上。
做网络过滤或者加速类项目时,有时候要取发起dns的真实进程。但是windows的dns都是通过dnscache服务进程,也就是svchost.exe发出的,所以普通方法取到的进程都是svchost.exe。其实还有很多方法,如修改服务状态,hook dns查询api,拦截rpc请求,修改句柄及nsp等。不过这个最简单稳定。
const wchar_t* sessionName = L"MyDNSSession1";
static const GUID DNSClientProviderGuid = { 0x1C95126E, 0x7EEA, 0x49A9, { 0xA3, 0xFE, 0xA3, 0x78, 0xB0, 0x3D, 0xDB, 0x4D } }; // DNS Client Provider GUIDstd::string GetProcessName(DWORD ProcessId)
{std::string ProcessName;HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (hProcessSnap != INVALID_HANDLE_VALUE){PROCESSENTRY32 pe32 = { sizeof(pe32) };BOOL bFind = Process32First(hProcessSnap, &pe32);while (bFind){if (pe32.th32ProcessID == ProcessId){ProcessName = pe32.szExeFile;break;}bFind = Process32Next(hProcessSnap, &pe32);}}::CloseHandle(hProcessSnap);return ProcessName;
}void EnableDNSClientProvider(TRACEHANDLE sessionHandle) {ULONG enableStatus = EnableTraceEx(&DNSClientProviderGuid,nullptr,sessionHandle,EVENT_CONTROL_CODE_ENABLE_PROVIDER,TRACE_LEVEL_INFORMATION,0, 0, 0, nullptr);if (enableStatus != ERROR_SUCCESS) {std::cerr << "Failed to enable DNS client provider. Error: " << enableStatus << std::endl;}
}bool GetPropertyValue(PEVENT_RECORD evt, LPCWSTR propName, std::unique_ptr<BYTE[]>& data) {PROPERTY_DATA_DESCRIPTOR dataDesc = {};dataDesc.PropertyName = reinterpret_cast<ULONGLONG>(propName);dataDesc.ArrayIndex = 0;ULONG propertySize = 0;ULONG status = TdhGetPropertySize(evt, 0, nullptr, 1, &dataDesc, &propertySize);if (status != ERROR_SUCCESS) return false;data = std::make_unique<BYTE[]>(propertySize);status = TdhGetProperty(evt, 0, nullptr, 1, &dataDesc, propertySize, data.get());return status == ERROR_SUCCESS;
}void WINAPI ProcessEvent(PEVENT_RECORD pEvent) {if (pEvent->EventHeader.ProviderId == DNSClientProviderGuid) {std::wstring domain;std::unique_ptr<BYTE[]> value;if (GetPropertyValue(pEvent, L"QueryName", value)) {domain.assign(reinterpret_cast<wchar_t*>(value.get()));}DWORD processId = pEvent->EventHeader.ProcessId;std::wcout << L"DNS Query Event: ProcessName: " << GetProcessName(processId).c_str() << " ProcessId: " << processId << L" Domain: " << domain << std::endl;}
}void StopExistingSession(const wchar_t* sessionName) {EVENT_TRACE_PROPERTIES traceProps = {};traceProps.Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(WCHAR) * 100;traceProps.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);ULONG status = ControlTraceW(0, sessionName, &traceProps, EVENT_TRACE_CONTROL_STOP);if (status != ERROR_SUCCESS && status != ERROR_WMI_INSTANCE_NOT_FOUND) {std::cerr << "Failed to stop existing ETW session. Error: " << status << std::endl;}
}void StartETWSession(LPCWSTR sessionName) {StopExistingSession(sessionName);auto traceProps = std::make_unique<BYTE[]>(sizeof(EVENT_TRACE_PROPERTIES) + sizeof(WCHAR) * 100);auto traceProperties = reinterpret_cast<EVENT_TRACE_PROPERTIES*>(traceProps.get());ZeroMemory(traceProperties, sizeof(EVENT_TRACE_PROPERTIES) + sizeof(WCHAR) * 100);traceProperties->Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(WCHAR) * 100;traceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;traceProperties->Wnode.ClientContext = 1; // QPC clock resolutiontraceProperties->Wnode.Guid = DNSClientProviderGuid;traceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;traceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);wcscpy_s(reinterpret_cast<LPWSTR>(traceProps.get() + traceProperties->LoggerNameOffset), 100, sessionName);TRACEHANDLE sessionHandle = 0;ULONG status = StartTraceW(&sessionHandle, sessionName, traceProperties);if (status != ERROR_SUCCESS) {std::cerr << "Failed to start ETW session. Error: " << status << std::endl;return;}EnableDNSClientProvider(sessionHandle);EVENT_TRACE_LOGFILEW logFile = {};logFile.LoggerName = const_cast<LPWSTR>(sessionName);logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;logFile.EventRecordCallback = ProcessEvent;TRACEHANDLE traceHandle = OpenTraceW(&logFile);if (traceHandle == INVALID_PROCESSTRACE_HANDLE) {std::cerr << "Failed to open trace. Error: " << GetLastError() << std::endl;ControlTraceW(sessionHandle, nullptr, traceProperties, EVENT_TRACE_CONTROL_STOP);return;}ProcessTrace(&traceHandle, 1, nullptr, nullptr);ControlTraceW(sessionHandle, nullptr, traceProperties, EVENT_TRACE_CONTROL_STOP);
}