ETW-Ti 的应用记录

参考文章:

记一次调用ETW-TI-编程技术-看雪-安全社区|安全招聘|kanxue.com

ETW-TI介绍

其实就是对 Microsoft-Windows-Threat-Intelligence 这个事件提供程序进行应用,不过这个事件提供程序用起来需要一点手段

就是要将使用该提供程序的进程提升至PPL,具体来说提升至

PsProtectedTypeProtectedLightPsProtectedSignerAntimalware,才可以使用这个Microsoft-Windows-Threat-Intelligence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef enum _PS_PROTECTED_TYPE
{
PsProtectedTypeNone = 0,
PsProtectedTypeProtectedLight = 1,
PsProtectedTypeProtected = 2
} PS_PROTECTED_TYPE, * PPS_PROTECTED_TYPE;


typedef enum _PS_PROTECTED_SIGNER
{
PsProtectedSignerNone = 0, // 0
PsProtectedSignerAuthenticode, // 1
PsProtectedSignerCodeGen, // 2
PsProtectedSignerAntimalware, // 3
PsProtectedSignerLsa, // 4
PsProtectedSignerWindows, // 5
PsProtectedSignerWinTcb, // 6
PsProtectedSignerWinSystem, // 7
PsProtectedSignerApp, // 8
PsProtectedSignerMax // 9
} PS_PROTECTED_SIGNER, * PPS_PROTECTED_SIGNER;

具体如何设置可以看我上一篇文章,要通过驱动设置的

具体咱来看看这个Microsoft-Windows-Threat-Intelligence可以拦截到什么东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
提供程序                                 GUID
-------------------------------------------------------------------------------
Microsoft-Windows-Threat-Intelligence {F4E1897C-BB5D-5668-F1D8-040F4D8DD344}

值 关键字 描述
-------------------------------------------------------------------------------
0x0000000000000001 KERNEL_THREATINT_KEYWORD_ALLOCVM_LOCAL
0x0000000000000002 KERNEL_THREATINT_KEYWORD_ALLOCVM_LOCAL_KERNEL_CALLER
0x0000000000000004 KERNEL_THREATINT_KEYWORD_ALLOCVM_REMOTE
0x0000000000000008 KERNEL_THREATINT_KEYWORD_ALLOCVM_REMOTE_KERNEL_CALLER
0x0000000000000010 KERNEL_THREATINT_KEYWORD_PROTECTVM_LOCAL
0x0000000000000020 KERNEL_THREATINT_KEYWORD_PROTECTVM_LOCAL_KERNEL_CALLER
0x0000000000000040 KERNEL_THREATINT_KEYWORD_PROTECTVM_REMOTE
0x0000000000000080 KERNEL_THREATINT_KEYWORD_PROTECTVM_REMOTE_KERNEL_CALLER
0x0000000000000100 KERNEL_THREATINT_KEYWORD_MAPVIEW_LOCAL
0x0000000000000200 KERNEL_THREATINT_KEYWORD_MAPVIEW_LOCAL_KERNEL_CALLER
0x0000000000000400 KERNEL_THREATINT_KEYWORD_MAPVIEW_REMOTE
0x0000000000000800 KERNEL_THREATINT_KEYWORD_MAPVIEW_REMOTE_KERNEL_CALLER
0x0000000000001000 KERNEL_THREATINT_KEYWORD_QUEUEUSERAPC_REMOTE
0x0000000000002000 KERNEL_THREATINT_KEYWORD_QUEUEUSERAPC_REMOTE_KERNEL_CALLER
0x0000000000004000 KERNEL_THREATINT_KEYWORD_SETTHREADCONTEXT_REMOTE
0x0000000000008000 KERNEL_THREATINT_KEYWORD_SETTHREADCONTEXT_REMOTE_KERNEL_CALLER
0x0000000000010000 KERNEL_THREATINT_KEYWORD_READVM_LOCAL
0x0000000000020000 KERNEL_THREATINT_KEYWORD_READVM_REMOTE
0x0000000000040000 KERNEL_THREATINT_KEYWORD_WRITEVM_LOCAL
0x0000000000080000 KERNEL_THREATINT_KEYWORD_WRITEVM_REMOTE
0x0000000000100000 KERNEL_THREATINT_KEYWORD_SUSPEND_THREAD
0x0000000000200000 KERNEL_THREATINT_KEYWORD_RESUME_THREAD
0x0000000000400000 KERNEL_THREATINT_KEYWORD_SUSPEND_PROCESS
0x0000000000800000 KERNEL_THREATINT_KEYWORD_RESUME_PROCESS
0x0000000001000000 KERNEL_THREATINT_KEYWORD_FREEZE_PROCESS
0x0000000002000000 KERNEL_THREATINT_KEYWORD_THAW_PROCESS
0x0000000004000000 KERNEL_THREATINT_KEYWORD_CONTEXT_PARSE
0x0000000008000000 KERNEL_THREATINT_KEYWORD_EXECUTION_ADDRESS_VAD_PROBE
0x0000000010000000 KERNEL_THREATINT_KEYWORD_EXECUTION_ADDRESS_MMF_NAME_PROBE
0x0000000020000000 KERNEL_THREATINT_KEYWORD_READWRITEVM_NO_SIGNATURE_RESTRICTION
0x0000000040000000 KERNEL_THREATINT_KEYWORD_DRIVER_EVENTS
0x0000000080000000 KERNEL_THREATINT_KEYWORD_DEVICE_EVENTS
0x0000000100000000 KERNEL_THREATINT_KEYWORD_READVM_REMOTE_FILL_VAD
0x0000000200000000 KERNEL_THREATINT_KEYWORD_WRITEVM_REMOTE_FILL_VAD
0x0000000400000000 KERNEL_THREATINT_KEYWORD_PROTECTVM_LOCAL_FILL_VAD
0x0000000800000000 KERNEL_THREATINT_KEYWORD_PROTECTVM_LOCAL_KERNEL_CALLER_FILL_VAD
0x0000001000000000 KERNEL_THREATINT_KEYWORD_PROTECTVM_REMOTE_FILL_VAD
0x0000002000000000 KERNEL_THREATINT_KEYWORD_PROTECTVM_REMOTE_KERNEL_CALLER_FILL_VAD
0x0000004000000000 KERNEL_THREATINT_KEYWORD_PROCESS_IMPERSONATION_UP
0x0000008000000000 KERNEL_THREATINT_KEYWORD_PROCESS_IMPERSONATION_REVERT
0x0000010000000000 KERNEL_THREATINT_KEYWORD_PROCESS_SYSCALL_USAGE
0x0000020000000000 KERNEL_THREATINT_KEYWORD_QUEUEUSERAPC_AT_DPC
0x0000040000000000 KERNEL_THREATINT_KEYWORD_PROCESS_IMPERSONATION_DOWN
0x8000000000000000 Microsoft-Windows-Threat-Intelligence/Analytic

对于这些关键字有如下的解释

虚拟内存操作监控

  • ALLOCVM_LOCALALLOCVM_REMOTE:监控本地或远程的内存分配操作。
  • PROTECTVM_LOCALPROTECTVM_REMOTE:监控本地或远程的内存保护操作。
  • MAPVIEW_LOCALMAPVIEW_REMOTE:监控本地或远程的内存映射操作(如 MapViewOfFile)。
  • READVM_LOCALREADVM_REMOTE:监控本地或远程的内存读取操作。
  • WRITEVM_LOCALWRITEVM_REMOTE:监控本地或远程的内存写入操作。
  • READWRITEVM_NO_SIGNATURE_RESTRICTION:监控没有签名限制的内存读写操作。

线程和进程管理监控

  • SUSPEND_THREADRESUME_THREAD:监控线程挂起和恢复。
  • SUSPEND_PROCESSRESUME_PROCESS:监控进程挂起和恢复。
  • FREEZE_PROCESSTHAW_PROCESS:监控进程冻结和解冻。
  • PROCESS_IMPERSONATION_UPPROCESS_IMPERSONATION_REVERTPROCESS_IMPERSONATION_DOWN:监控进程伪装的提升、恢复和降低操作。

线程上下文与系统调用监控

  • SETTHREADCONTEXT_REMOTE:监控远程设置线程上下文操作(如通过 SetThreadContext)。
  • PROCESS_SYSCALL_USAGE:监控进程的系统调用使用情况。

驱动程序与设备事件监控

  • DRIVER_EVENTS:监控与驱动程序相关的事件。
  • DEVICE_EVENTS:监控与设备相关的事件。

内存访问与映射保护监控

  • PROTECTVM_LOCAL_FILL_VADPROTECTVM_REMOTE_FILL_VAD:监控内存保护的 VAD(虚拟地址描述符)操作。
  • PROTECTVM_LOCAL_KERNEL_CALLER_FILL_VADPROTECTVM_REMOTE_KERNEL_CALLER_FILL_VAD:监控内核调用者的 VAD 填充操作。

其他威胁检测行为

  • QUEUEUSERAPC_REMOTEQUEUEUSERAPC_REMOTE_KERNEL_CALLER:监控远程线程队列中的 APC(异步过程调用)。
  • EXECUTION_ADDRESS_VAD_PROBEEXECUTION_ADDRESS_MMF_NAME_PROBE:监控执行地址的 VAD 或 MMF(内存映射文件)探测。

特定模式的操作

  • EXECUTION_ADDRESS_VAD_PROBEEXECUTION_ADDRESS_MMF_NAME_PROBE:监控执行地址的 VAD 和 MMF 名称探测。
  • QUEUEUSERAPC_AT_DPC:监控 DPC 级别的 APC 队列。

代码展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#define INITGUID  // Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <windows.h>
#include <evntrace.h>
#include <evntcons.h>
#include <iostream>
#include <iomanip>
#include <dbghelp.h>
#include <unordered_map>
#pragma comment(lib, "dbghelp.lib")
#include <psapi.h>

// GUID for Microsoft-Windows-Kernel-Memory
static const GUID KernelMemoryGuid = { 0xD1D93EF7, 0xE1F2, 0x4F45, { 0x99, 0x43, 0x03, 0xD2, 0x45, 0xFE, 0x6C, 0x00 } };


static const GUID Microsoft_Windows_Threat_Intelligence = { 0xF4E1897C, 0xBB5D, 0x5668, { 0xF1, 0xD8, 0x04, 0x0F, 0x4D, 0x8D, 0xD3, 0x44 } };


// Store initialized process handles for symbol resolution
std::unordered_map<DWORD, HANDLE> processHandleMap;

// Initialize the symbol handler for a specific process
bool InitializeSymbolHandlerForProcess(DWORD processId) {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (hProcess == nullptr) {
std::cerr << "Failed to open process " << processId << ". Error: " << GetLastError() << std::endl;
return false;
}

if (!SymInitialize(hProcess, NULL, TRUE)) {
std::cerr << "Failed to initialize symbol handler for process " << processId
<< ". Error: " << GetLastError() << std::endl;
CloseHandle(hProcess);
return false;
}

// Store the process handle
processHandleMap[processId] = hProcess;
return true;
}

// Cleanup all symbol handlers and process handles
void CleanupSymbolHandlers() {
for (auto& entry : processHandleMap) {
SymCleanup(entry.second);
CloseHandle(entry.second);
}
processHandleMap.clear();
}

// Helper to resolve function name from address for a specific process
std::string ResolveFunctionNameForProcess(HANDLE hProcess, ULONG64 address) {
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = { 0 };
PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;

DWORD64 displacement = 0;
if (SymFromAddr(hProcess, address, &displacement, symbol)) {
return std::string(symbol->Name);
}
else {
return "Unknown";
}
}

// Global variable to store the last stack address or memory address
ULONG64 lastAddress = 0;
int flag = 0;
// Callback function to process events
// Callback function to process events
VOID WINAPI EventCallback(PEVENT_RECORD EventRecord) {

DWORD processId = EventRecord->EventHeader.ProcessId;

std::cout << "Event ID: " << EventRecord->EventHeader.EventDescriptor.Id << std::endl;
std::cout << "Process ID: " << processId << std::endl;

// 获取进程名
char processName[MAX_PATH] = { 0 };
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (hProcess) {
DWORD length = GetModuleFileNameExA(hProcess, NULL, processName, sizeof(processName));
if (length > 0) {
std::cout << "Process Name: " << processName << std::endl;
}
else {
std::cout << "Failed to get process name." << std::endl;
}
CloseHandle(hProcess);
}
else {
std::cout << "Failed to open process." << std::endl;
}
}


// Callback function for trace buffer processing
ULONG WINAPI BufferCallback(PEVENT_TRACE_LOGFILE Buffer)
{
return TRUE; // Continue processing
}

int main() {
system("pause");
__debugbreak();
TRACEHANDLE sessionHandle = 0;
TRACEHANDLE traceHandle = 0;

// Start the ETW session
EVENT_TRACE_PROPERTIES* traceProperties = (EVENT_TRACE_PROPERTIES*)malloc(sizeof(EVENT_TRACE_PROPERTIES) + 1024);
if (!traceProperties) {
std::cerr << "Failed to allocate memory for EVENT_TRACE_PROPERTIES." << std::endl;
system("pause");
return 1;
}

ZeroMemory(traceProperties, sizeof(EVENT_TRACE_PROPERTIES) + 1024);
traceProperties->Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + 1024;
traceProperties->Wnode.Guid = Microsoft_Windows_Threat_Intelligence;
traceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
traceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
traceProperties->MaximumFileSize = 0; // No log file
traceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);

WCHAR sessionName[] = L"MyKernelMemorySession";
ULONG status = StartTrace(&sessionHandle, sessionName, traceProperties);
if (status != ERROR_SUCCESS) {
std::cerr << "Failed to start ETW session. Error: " << status << std::endl;
free(traceProperties);
system("pause");
return 1;
}
ENABLE_TRACE_PARAMETERS enableParameters = { 0 };
enableParameters.Version = ENABLE_TRACE_PARAMETERS_VERSION;
enableParameters.EnableProperty = EVENT_ENABLE_PROPERTY_STACK_TRACE;
// Enable the provider
status = EnableTraceEx2(
sessionHandle,
&Microsoft_Windows_Threat_Intelligence,
EVENT_CONTROL_CODE_ENABLE_PROVIDER,
TRACE_LEVEL_INFORMATION,
0x8000000000000040, // Keyword
0, // Match any level
0, // No timeout
NULL//&enableParameters
);

if (status != ERROR_SUCCESS)
{
system("pause");
std::cerr << "Failed to enable ETW provider. Error: " << status << std::endl;
StopTrace(sessionHandle, sessionName, traceProperties);
free(traceProperties);
system("pause");
return 1;
}

// Open a trace for real-time processing
EVENT_TRACE_LOGFILE logFile = { 0 };
logFile.LoggerName = sessionName;
logFile.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_REAL_TIME;
logFile.EventRecordCallback = (PEVENT_RECORD_CALLBACK)(EventCallback); //每次有新事件记录时触发
logFile.BufferCallback = BufferCallback;//当 ETW 内部完成了 一个缓冲区的处理 或 当缓冲区中的事件记录即将被传递到 EventCallback 时触发。

traceHandle = OpenTrace(&logFile);
if (traceHandle == INVALID_PROCESSTRACE_HANDLE) {
system("pause");
std::cerr << "Failed to open trace. Error: " << GetLastError() << std::endl;
StopTrace(sessionHandle, sessionName, traceProperties);
free(traceProperties);
system("pause");
return 1;
}

std::cout << "Listening for ETW events. Press Ctrl+C to stop..." << std::endl;

// Process the events
status = ProcessTrace(&traceHandle, 1, NULL, NULL);
if (status != ERROR_SUCCESS) {
system("pause");
std::cerr << "Failed to process trace. Error: " << status << std::endl;
}

// Clean up
CloseTrace(traceHandle);
StopTrace(sessionHandle, sessionName, traceProperties);
free(traceProperties);
system("pause");
std::cout << "ETW session stopped." << std::endl;
system("pause");
return 0;
}

效果展示:

让AI写了一个注入的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <windows.h>
#include <iostream>

unsigned char shellcode[] = {
0x90, 0x90, 0x90, 0x90, // 假的 NOP (No Operation) 示例,实际 shellcode 会更复杂
// 示例中添加了简单的 nop 滑行字节;实际 shellcode 会在这里包含有意义的机器码
0x90, 0x90, 0x90, 0x90
};

// 注入远程线程
bool InjectShellcode(HANDLE hTargetProcess) {
SIZE_T bytesWritten;

// Step 1: 在目标进程分配内存
LPVOID remoteMemory = VirtualAllocEx(hTargetProcess, nullptr, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (remoteMemory == nullptr) {
std::cerr << "VirtualAllocEx failed: " << GetLastError() << std::endl;
return false;
}

// Step 2: 写入 shellcode
if (!WriteProcessMemory(hTargetProcess, remoteMemory, shellcode, sizeof(shellcode), &bytesWritten)) {
std::cerr << "WriteProcessMemory failed: " << GetLastError() << std::endl;
VirtualFreeEx(hTargetProcess, remoteMemory, 0, MEM_RELEASE);
return false;
}

// Step 3: 创建远程线程执行 shellcode
HANDLE hRemoteThread = CreateRemoteThread(hTargetProcess, nullptr, 0,
(LPTHREAD_START_ROUTINE)remoteMemory,
nullptr, 0, nullptr);
if (hRemoteThread == nullptr) {
std::cerr << "CreateRemoteThread failed: " << GetLastError() << std::endl;
VirtualFreeEx(hTargetProcess, remoteMemory, 0, MEM_RELEASE);
return false;
}

// 等待线程完成
WaitForSingleObject(hRemoteThread, INFINITE);

// 清理
CloseHandle(hRemoteThread);
VirtualFreeEx(hTargetProcess, remoteMemory, 0, MEM_RELEASE);

return true;
}

int main() {
system("pause");
std::cout << "请输入你要注入的PID" << std::endl;
DWORD targetProcessId; // 替换为目标进程的 PID
std::cin >> targetProcessId;


// Step 1: 打开目标进程
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcessId);
if (hTargetProcess == nullptr) {
std::cerr << "OpenProcess failed: " << GetLastError() << std::endl;
return 1;
}

// Step 2: 注入 shellcode
if (InjectShellcode(hTargetProcess)) {
std::cout << "Shellcode injected successfully!" << std::endl;
}
else {
std::cerr << "Failed to inject shellcode." << std::endl;
}

// Step 3: 关闭目标进程句柄
CloseHandle(hTargetProcess);
return 0;
}

跑起来,果然监控到了(我开的是远程线程注入监控,即关键字KERNEL_THREATINT_KEYWORD_PROTECTVM_REMOTE

1738834431449