Panoptes 1.0.0
Endpoint Detection and Response
Loading...
Searching...
No Matches
events.cpp
Go to the documentation of this file.
1#include <Windows.h>
2#include <evntrace.h>
3#include <stdio.h>
4#include <evntcons.h>
5#include <string>
6#include <tdh.h>
7#include <assert.h>
8#include <memory>
9#include <in6addr.h>
10#include <chrono>
11#include <iomanip>
12#include <sstream>
13#include <nlohmann/json.hpp>
14#include "pano_log.h"
15#include "utils.h"
16#include "service_constants.h"
17#include "grpc.hpp"
18#include "panoptes_service.h"
19
20
21TRACEHANDLE hTrace = 0;
23EVENT_TRACE_LOGFILEW trace;
24EVENT_TRACE_PROPERTIES* traceProp = nullptr;
25
26std::string FormatSystemTime(const FILETIME& ft) {
27 SYSTEMTIME st;
28 FileTimeToSystemTime(&ft, &st);
29
30 std::ostringstream ss;
31 ss << std::setfill('0')
32 << st.wYear << '/'
33 << std::setw(2) << st.wMonth << '/'
34 << std::setw(2) << st.wDay << ' '
35 << std::setw(2) << st.wHour << ':'
36 << std::setw(2) << st.wMinute << ':'
37 << std::setw(2) << st.wSecond;
38 return ss.str();
39}
40
41std::optional<GUID> GetProviderGuid(const std::string& providerNameToFind) {
42 ULONG bufferSize = 0;
43 PROVIDER_ENUMERATION_INFO* providerInfo = nullptr;
44 std::optional<GUID> result;
45
46 // Get the required buffer size
47 ULONG status = TdhEnumerateProviders(nullptr, &bufferSize);
48 if (status == ERROR_INSUFFICIENT_BUFFER) {
49 providerInfo = (PROVIDER_ENUMERATION_INFO*)malloc(bufferSize);
50 if (providerInfo == nullptr) {
51 throw std::runtime_error("Failed to allocate memory");
52 }
53
54 // Enumerate providers
55 status = TdhEnumerateProviders(providerInfo, &bufferSize);
56 if (status == ERROR_SUCCESS) {
57 for (ULONG i = 0; i < providerInfo->NumberOfProviders; i++) {
58 TRACE_PROVIDER_INFO& provider = providerInfo->TraceProviderInfoArray[i];
59 wchar_t* providerName = (wchar_t*)((BYTE*)providerInfo + provider.ProviderNameOffset);
60
61 std::wstring wProviderName(providerName);
62 std::string providerNameStr(wProviderName.begin(), wProviderName.end());
63
64 if (providerNameStr == providerNameToFind) {
65 result = provider.ProviderGuid;
66 break;
67 }
68 }
69 }
70 else {
71 throw std::runtime_error("TdhEnumerateProviders failed with error: " + std::to_string(status));
72 }
73
74 free(providerInfo);
75 }
76 else {
77 throw std::runtime_error("TdhEnumerateProviders failed with error: " + std::to_string(status));
78 }
79
80 return result;
81}
82
83std::vector<GUID> GetProvidersGUID(std::vector<std::string> providers) {
84 std::vector<GUID> guids;
85 for (const auto& providerName : providers) {
86 auto guid = GetProviderGuid(providerName);
87 if (guid.has_value()) {
88 guids.push_back(guid.value());
89 }
90 else {
91 printf("Provider %s not found\n", providerName.c_str());
92 }
93 }
94 return guids;
95}
96
102void DisplayEventInfo(PEVENT_RECORD rec, PTRACE_EVENT_INFO info) {
103
104 //GUID providerId = { 0x7036af95, 0x9daf, 0x4486, 0x8d, 0x93, 0x70, 0x5, 0xd4, 0x5a, 0x6a, 0x6 };
105 //if (rec->EventHeader.ProviderId != providerId)
106 // return;
107
108 nlohmann::json jsonObject;
109 if (info->KeywordsNameOffset)
110 printf("Keywords: %ws ", (PCWSTR)((BYTE*)info + info->KeywordsNameOffset));
111 if (info->OpcodeNameOffset)
112 printf("Opcode: %ws ", (PCWSTR)((BYTE*)info + info->OpcodeNameOffset));
113 if (info->LevelNameOffset)
114 printf("Level: %ws ", (PCWSTR)((BYTE*)info + info->LevelNameOffset));
115 if (info->TaskNameOffset) {
116 printf("Task: %ws ", (PCWSTR)((BYTE*)info + info->TaskNameOffset));
117 std::wstring taskName = (PCWSTR)((BYTE*)info + info->TaskNameOffset);
118 jsonObject["Event"] = ToString(taskName);
119 }
120 if (info->EventMessageOffset)
121 printf("\nMessage: %ws", (PCWSTR)((BYTE*)info + info->EventMessageOffset));
122
123 printf("\nProperties: %u\n", info->TopLevelPropertyCount);
124
125 // properties data length and pointer
126 auto userlen = rec->UserDataLength;
127 auto data = (PBYTE)rec->UserData;
128
129 auto pointerSize = (rec->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER) ? 4 : 8;
130 ULONG len;
131 WCHAR value[512];
132
133 for (DWORD i = 0; i < info->TopLevelPropertyCount; i++) {
134 auto& pi = info->EventPropertyInfoArray[i];
135 auto propName = (PCWSTR)((BYTE*)info + pi.NameOffset);
136 printf(" Name: %ws ", propName);
137 std::string propNameStr = ToString(propName);
138
139 len = pi.length;
140 if ((pi.Flags & (PropertyStruct | PropertyParamCount)) == 0) {
141 //
142 // deal with simple properties only
143 //
144 PEVENT_MAP_INFO mapInfo = nullptr;
145 std::unique_ptr<BYTE[]> mapBuffer;
146 PWSTR mapName = nullptr;
147 //
148 // retrieve map information (if any)
149 //
150 if (pi.nonStructType.MapNameOffset) {
151 ULONG size = 0;
152 mapName = (PWSTR)((BYTE*)info + pi.nonStructType.MapNameOffset);
153 if (ERROR_INSUFFICIENT_BUFFER == ::TdhGetEventMapInformation(rec, mapName, mapInfo, &size)) {
154 mapBuffer = std::make_unique<BYTE[]>(size);
155 mapInfo = reinterpret_cast<PEVENT_MAP_INFO>(mapBuffer.get());
156 if (ERROR_SUCCESS != ::TdhGetEventMapInformation(rec, mapName, mapInfo, &size))
157 mapInfo = nullptr;
158 }
159 }
160
161 ULONG size = sizeof(value);
162 USHORT consumed;
163 // special case for IPv6 address
164 if (pi.nonStructType.InType == TDH_INTYPE_BINARY && pi.nonStructType.OutType == TDH_OUTTYPE_IPV6)
165 len = sizeof(IN6_ADDR);
166
167 auto error = ::TdhFormatProperty(info, mapInfo, pointerSize,
168 pi.nonStructType.InType, pi.nonStructType.OutType,
169 (USHORT)len, userlen, data, &size, value, &consumed);
170 if (ERROR_SUCCESS == error) {
171 printf("Value: %ws", value);
172 jsonObject[propNameStr] = ToString(value);
173 len = consumed;
174 if (mapName)
175 printf(" (%ws)", (PCWSTR)mapName);
176 printf("\n");
177 }
178 else if (mapInfo) {
179 error = ::TdhFormatProperty(info, nullptr, pointerSize,
180 pi.nonStructType.InType, pi.nonStructType.OutType,
181 (USHORT)len, userlen, data, &size, value, &consumed);
182 if (ERROR_SUCCESS == error) {
183 printf("Value: %ws\n", value);
184 jsonObject[propNameStr] = ToString(value);
185 }
186 }
187 if (ERROR_SUCCESS != error)
188 printf("(failed to get value)\n");
189 }
190 else {
191 printf("(not a simple property)\n");
192 }
193 userlen -= (USHORT)len;
194 data += len;
195 }
196 auto& header = rec->EventHeader;
197 jsonObject["TID"] = header.ThreadId;
198 jsonObject["PID"] = header.ProcessId;
199 if (header.ProcessId == GetCurrentProcessId()) {
200 return;
201 }
202 std::string timeLog = FormatSystemTime(*(FILETIME*)&header.TimeStamp);
203 jsonObject["Time"] = timeLog;
204
205 try {
206 std::string eventName = jsonObject["Event"].get<std::string>();
207 if (!eventName.empty()) {
208 if (eventName == "FileCreated" || eventName == "FileModified") {
209 std::string fileName = jsonObject["FileName"].get<std::string>();
210 SelfQueuePeScan(fileName, "");
211 }
212 else if (eventName == "KERNEL_NETWORK_TASK_TCPIP" || eventName == "KERNEL_NETWORK_TASK_UDPIP"){
213 auto destAddr = jsonObject["daddr"].get<std::string>();
214 auto srcAddr = jsonObject["saddr"].get<std::string>();
215 if (srcAddr == "127.0.0.1" || destAddr == "127.0.0.1") {
216 return;
217 }
218 if (srcAddr == "::1" || destAddr == "::1") {
219 return;
220 }
221 }
222 }
223
224 }
225 catch (...){
226 WriteToLogFile(jsonObject.dump() + "\n");
227 return;
228 }
229
230 WriteToLogFile(jsonObject.dump() + "\n");
231}
232
233//void DisplayGeneralEventInfo(PEVENT_RECORD rec) {
234// WCHAR sguid[64];
235// auto& header = rec->EventHeader;
236// ::StringFromGUID2(header.ProviderId, sguid, _countof(sguid));
237//
238// printf("Provider: %ws Time: %ws PID: %u TID: %u\n",
239// sguid, (PCWSTR)CTime(*(FILETIME*)&header.TimeStamp).Format(L"%c"),
240// header.ProcessId, header.ThreadId);
241//}
242
243VOID WINAPI EventRecordCallback(EVENT_RECORD* pEventRecord) {
244 //DisplayGeneralEventInfo(pEventRecord);
245
246 ULONG size = 0;
247 auto status = ::TdhGetEventInformation(pEventRecord, 0, nullptr, nullptr, &size);
248 assert(status == ERROR_INSUFFICIENT_BUFFER);
249
250 auto buffer = std::make_unique<BYTE[]>(size);
251 if (!buffer) {
252 printf("Out of memory!\n");
253 ::ExitProcess(1);
254 }
255
256 auto info = reinterpret_cast<PTRACE_EVENT_INFO>(buffer.get());
257 status = ::TdhGetEventInformation(pEventRecord, 0, nullptr, info, &size);
258 if (status != ERROR_SUCCESS) {
259 printf("Error processing event!\n");
260 return;
261 }
262
263 DisplayEventInfo(pEventRecord, info);
264}
265
266ULONG WINAPI BufferCallback(EVENT_TRACE_LOGFILE* pLogFile) {
267 return TRUE;
268}
269
271{
272 std::wstring sessionName = TRACE_NAMEW;
273 EVENT_TRACE_PROPERTIES* pProperties = NULL;
274 ULONG bufferSize = 0;
275 ULONG status = ERROR_SUCCESS;
276
277 // Calculate the buffer size
278 bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + (wcslen(sessionName.c_str()) + 1) * sizeof(WCHAR);
279 pProperties = (EVENT_TRACE_PROPERTIES*)malloc(bufferSize);
280 if (pProperties == NULL)
281 {
282 return ERROR_OUTOFMEMORY;
283 }
284
285 ZeroMemory(pProperties, bufferSize);
286 pProperties->Wnode.BufferSize = bufferSize;
287 pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
288 pProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
289
290 // Stop and delete the trace session
291 status = ControlTraceW(NULL, sessionName.c_str(), pProperties, EVENT_TRACE_CONTROL_STOP);
292
293 free(pProperties);
294 return status;
295}
296
298 std::wstring Name = TRACE_NAMEW;
299 ControlTraceW(NULL, Name.c_str(), traceProp, EVENT_TRACE_CONTROL_STOP);
300 if (hTrace != NULL) {
301 CloseTrace(hTrace); // Ensure hTrace is closed
302 }
303}
304
305ULONG StartPanoptesTrace(LPVOID lpParam) {
308 auto providers = serviceContext.config->m_eventProviders;
309
310 // Initialize properties for the single trace session
311 ULONG bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + (MAX_PATH * sizeof(WCHAR));
312 EVENT_TRACE_PROPERTIES* pProperties = (EVENT_TRACE_PROPERTIES*)malloc(bufferSize);
313 ZeroMemory(pProperties, bufferSize);
314
315 pProperties->Wnode.BufferSize = bufferSize;
316 pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
317 pProperties->Wnode.ClientContext = 1; // QPC clock resolution
318 pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
319 pProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
320 pProperties->LogFileNameOffset = 0;
321
322 // Start the trace session
323 TRACEHANDLE hTrace;
324 WCHAR sessionName[] = L"Panoptes";
325 ULONG result = StartTraceW(&hTrace, sessionName, pProperties);
326 if (result != ERROR_SUCCESS)
327 {
328 // Handle error
329 free(pProperties);
330 return 1;
331 }
332
333 // Enable multiple providers
334 for (const auto& provider : providers)
335 {
336 auto [provName, provMatchAny, provMatchAll] = provider;
337
338 GUID provGUID = GetProviderGuid(provName).value_or(GUID{});
339 if (provGUID == GUID{}) {
340 printf("[!] Could not retrieve GUID for %s\n", provName);
341 continue;
342 }
343
344 result = EnableTraceEx2(
345 hTrace,
346 &provGUID,
347 EVENT_CONTROL_CODE_ENABLE_PROVIDER,
348 TRACE_LEVEL_INFORMATION,
349 provMatchAny,
350 provMatchAll,
351 0,
352 NULL
353 );
354 if (result != ERROR_SUCCESS)
355 {
356 // Handle error
357 printf("[!] Could not enable trace for %s\n", provName);
358 continue;
359 }
360 }
361
362 // Set up the trace session
363 EVENT_TRACE_LOGFILEW trace;
364 ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
365 trace.LoggerName = (LPWSTR)sessionName;
366 trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
367 trace.EventRecordCallback = EventRecordCallback;
368
369 // Start processing events
370 TRACEHANDLE hProcessTrace = OpenTraceW(&trace);
371 if (hProcessTrace == INVALID_PROCESSTRACE_HANDLE)
372 {
373 // Handle error
374 ControlTraceW(hTrace, NULL, pProperties, EVENT_TRACE_CONTROL_STOP);
375 free(pProperties);
376 return 1;
377 }
378
379 ProcessTrace(&hProcessTrace, 1, NULL, NULL);
380
381 // Clean up
382 CloseTrace(hProcessTrace);
383 ControlTraceW(hTrace, NULL, pProperties, EVENT_TRACE_CONTROL_STOP);
384 free(pProperties);
385
386 return 1;
387
388}
389
390
391
392
#define MAX_PATH
Definition callbacks.h:6
std::vector< std::tuple< std::string, unsigned long, unsigned long > > m_eventProviders
The event providers from the configuration file.
VOID StopPanoptesTrace()
Definition events.cpp:297
std::string FormatSystemTime(const FILETIME &ft)
Definition events.cpp:26
VOID WINAPI EventRecordCallback(EVENT_RECORD *pEventRecord)
Definition events.cpp:243
ULONG result
Definition events.cpp:22
ULONG StartPanoptesTrace(LPVOID lpParam)
Definition events.cpp:305
EVENT_TRACE_LOGFILEW trace
Definition events.cpp:23
std::optional< GUID > GetProviderGuid(const std::string &providerNameToFind)
Definition events.cpp:41
ULONG bufferSize
Definition events.cpp:22
ULONG WINAPI BufferCallback(EVENT_TRACE_LOGFILE *pLogFile)
Definition events.cpp:266
void DisplayEventInfo(PEVENT_RECORD rec, PTRACE_EVENT_INFO info)
https://github.com/zodiacon/Win10SysProgBookSamples/blob/9f2d1bb61a24fee4e08ec46738680e44f6c132de/Cha...
Definition events.cpp:102
std::vector< GUID > GetProvidersGUID(std::vector< std::string > providers)
Definition events.cpp:83
TRACEHANDLE hTrace
Definition events.cpp:21
ULONG StopAndDeleteTrace()
Definition events.cpp:270
EVENT_TRACE_PROPERTIES * traceProp
Definition events.cpp:24
PanoptesContext * serviceContext
Definition grpc.cpp:27
void SelfQueuePeScan(std::string pePath, std::string fileHash)
Definition grpc.cpp:224
unsigned char BYTE
Definition inject.h:4
unsigned long DWORD
Definition inject.h:2
void WriteToLogFile(const std::string &message)
Definition pano_log.cpp:32
#define TRACE_NAMEW
Configuration * config
std::string ToString(const std::wstring &wstr)
Definition utils.cpp:50