This commit is contained in:
cccs-mog
2024-03-06 22:00:22 +00:00
parent 999c5023ef
commit 9fb030d13c
182 changed files with 25421 additions and 110 deletions
+3
View File
@@ -4,3 +4,6 @@
[submodule "paramkit"]
path = paramkit
url = https://github.com/hasherezade/paramkit
[submodule "krabsetw"]
path = krabsetw
url = https://github.com/microsoft/krabsetw.git
+22 -4
View File
@@ -4,6 +4,20 @@ project (hollows_hunter)
option(HH_BUILD_TESTING "Enable testing for HollowsHunter" ON)
option (PECONV_LIB_INSTALL OFF)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set (KRABS_DIR "${CMAKE_SOURCE_DIR}/krabs_lib" CACHE PATH "KrabsETV main path" )
#if (BUILD_32)
# set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS
# "-m32" LINK_FLAGS "-m32")
# MESSAGE(STATUS "Excluding 64bit library paths from search.")
# set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS OFF)
# set(ARCH i686)
#elseif (BUILD_64)
# set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS
# "-m64" LINK_FLAGS "-m64")
# set(ARCH amd64)
#else()
# set(ARCH amd64)
#endif()
# static linking for GNU compilers
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -19,8 +33,10 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif()
# modules:
set ( PESIEVE_AS_STATIC_LIB "pe-sieve" ON )
set ( M_PESIEVE "pe-sieve" )
set ( M_PARAMKIT "paramkit" )
set ( M_KRABS "${KRABS_DIR}/Microsoft.O365.Security.Native.ETW.lib")
# modules paths:
set (PESIEVE_DIR "${PROJECT_SOURCE_DIR}/${M_PESIEVE}" CACHE PATH "PE-sieve main path")
@@ -54,6 +70,7 @@ set (hdrs
util/process_privilege.h
util/time_util.h
util/strings_util.h
krabsetw/krabs/krabs.hpp
)
set (rsrc
resources.h
@@ -75,16 +92,17 @@ set ( PESIEVE_LIB $<TARGET_FILE:pe-sieve> CACHE PATH "PE-sieve library path" )
add_subdirectory ( ${PARAMKIT_DIR} )
set ( PARAMKIT_LIB $<TARGET_FILE:paramkit> CACHE PATH "ParamKit library path" )
set ( KRABS_LIB "${CMAKE_SOURCE_DIR}/krabsetw/krabs/x64/Release/net462" )
cmake_policy(SET CMP0015 NEW)
LINK_DIRECTORIES ( ${PESIEVE_LIB} )
LINK_DIRECTORIES ( ${PESIEVE_LIB} ${KRABS_LIB})
add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} ${rsrc} main.cpp )
target_link_libraries ( ${PROJECT_NAME} ${M_PESIEVE} ${M_PARAMKIT} "psapi.lib" "ntdll.lib")
target_link_libraries ( ${PROJECT_NAME} ${M_PESIEVE} ${M_PARAMKIT} "psapi.lib" "ntdll.lib" ${M_KRABS})
# dependencies
add_dependencies( ${PROJECT_NAME} ${M_PESIEVE} ${M_PARAMKIT} )
target_compile_definitions(${PROJECT_NAME} PUBLIC -DUNICODE)
target_compile_definitions(${M_PARAMKIT} PUBLIC -DUNICODE)
#install
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} )
+4
View File
@@ -1,6 +1,10 @@
# hollows_hunter
![](./logo/logo2_128.png)
(Modified to be driven by ETW Events)
This requires https://github.com/microsoft/krabsetw. In order to compile Hollows Hunter, a static version of krabs is required and the header file krabsetw/krabs/krabs.hpp. The static version of krabs can be compiled from the project directly or the version given in the folder krabs_lib can be used by changing the CMAKEList.txt KRABS_LIB variable to that path instead. There is also a posibility to get it from nugget. (The version we are interested is Microsoft.O365.Security.Native.ETW.dll from net 4.6.2) Krabs can be completely added to the solution by : Inside krabs directory, you will see krabs.hpp and another directory “krabs”. Drop these two in your project directory, thats it!
[![Build status](https://ci.appveyor.com/api/projects/status/nsc2eux5986y1shq?svg=true)](https://ci.appveyor.com/project/hasherezade/hollows-hunter)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/0c149fcd62084f96ac0c131e4473dbdf)](https://app.codacy.com/gh/hasherezade/hollows_hunter/dashboard?branch=master)
[![Commit activity](https://img.shields.io/github/commit-activity/m/hasherezade/hollows_hunter)](https://github.com/hasherezade/hollows_hunter/commits)
+1
View File
@@ -14,6 +14,7 @@ void hh_args_init(t_hh_params &hh_args)
hh_args.suspend_suspicious = false;
hh_args.kill_suspicious = false;
hh_args.loop_scanning = false;
hh_args.etw_scan = false;
hh_args.unique_dir = false;
hh_args.quiet = false;
+3 -2
View File
@@ -12,15 +12,16 @@ typedef struct {
std::string out_dir;
bool unique_dir;
bool loop_scanning;
bool etw_scan;
bool suspend_suspicious;
bool kill_suspicious;
bool quiet;
bool log;
bool json_output;
LONGLONG ptimes;
std::set<std::string> names_list;
std::set<std::wstring> names_list;
std::set<long> pids_list;
std::set<std::string> ignored_names_list;
std::set<std::wstring> ignored_names_list;
pesieve::t_params pesieve_args; //PE-sieve parameters
} t_hh_params;
+65 -64
View File
@@ -2,7 +2,8 @@
#include <string>
#include <sstream>
#include <codecvt>
#include <locale>
#include <iostream>
#include <iomanip>
#include <cmath>
@@ -22,7 +23,7 @@ bool is_suspicious_process(pesieve::t_report report)
return false;
}
bool HHScanReport::appendReport(pesieve::t_report &scan_report, const std::string &img_name)
bool HHScanReport::appendReport(pesieve::t_report &scan_report, const std::wstring &img_name)
{
pidToReport[scan_report.pid] = scan_report;
pidToName[scan_report.pid] = img_name;
@@ -32,7 +33,7 @@ bool HHScanReport::appendReport(pesieve::t_report &scan_report, const std::strin
return true;
}
size_t HHScanReport::reportsToString(std::stringstream &stream)
size_t HHScanReport::reportsToString(std::wstringstream &stream)
{
std::vector<DWORD>::const_iterator itr;
@@ -41,123 +42,123 @@ size_t HHScanReport::reportsToString(std::stringstream &stream)
const size_t max_len = size_t(std::floor(std::log10(double(suspicious.size() - 1))) + 1);
for (itr = this->suspicious.begin(); itr != suspicious.end(); ++itr) {
DWORD pid = *itr;
stream << "[" << std::setw(max_len) << counter++ << "]: PID: " << std::dec << pid << ", ";
stream << "Name: " << this->pidToName[pid] << "\n";
stream << L"[" << std::setw(max_len) << counter++ << L"]: PID: " << std::dec << pid << L", ";
stream << L"Name: " << this->pidToName[pid] << L"\n";
printed++;
}
return printed;
}
size_t HHScanReport::reportsToJSON(std::stringstream &stream, size_t level, const t_hh_params &params)
size_t HHScanReport::reportsToJSON(std::wstringstream &stream, size_t level, const t_hh_params &params)
{
std::vector<DWORD>::const_iterator itr;
OUT_PADDED(stream, level, "\"suspicious\" : [\n");
OUT_PADDED(stream, level, L"\"suspicious\" : [\n");
level++;
size_t printed = 0;
for (itr = this->suspicious.begin(); itr != suspicious.end(); ++itr) {
DWORD pid = *itr;
OUT_PADDED(stream, level, "{\n");
OUT_PADDED(stream, level, L"{\n");
level++;
OUT_PADDED(stream, level, "\"pid\" : ");
stream << std::dec << pid << ",\n";
OUT_PADDED(stream, level, "\"is_managed\" : ");
stream << std::dec << pidToReport[pid].is_managed << ",\n";
OUT_PADDED(stream, level, "\"name\" : ");
stream << "\"" << this->pidToName[pid] << "\",\n";
OUT_PADDED(stream, level, "\"replaced\" : ");
stream << std::dec << pidToReport[pid].replaced << ",\n";
OUT_PADDED(stream, level, "\"hdr_modified\" : ");
stream << std::dec << pidToReport[pid].hdr_mod << ",\n";
OUT_PADDED(stream, level, L"\"pid\" : ");
stream << std::dec << pid << L",\n";
OUT_PADDED(stream, level, L"\"is_managed\" : ");
stream << std::dec << pidToReport[pid].is_managed << L",\n";
OUT_PADDED(stream, level, L"\"name\" : ");
stream << L"\"" << this->pidToName[pid] << L"\",\n";
OUT_PADDED(stream, level, L"\"replaced\" : ");
stream << std::dec << pidToReport[pid].replaced << L",\n";
OUT_PADDED(stream, level, L"\"hdr_modified\" : ");
stream << std::dec << pidToReport[pid].hdr_mod << L",\n";
if (!params.pesieve_args.no_hooks) {
OUT_PADDED(stream, level, "\"patched\" : ");
stream << std::dec << pidToReport[pid].patched << ",\n";
OUT_PADDED(stream, level, L"\"patched\" : ");
stream << std::dec << pidToReport[pid].patched << L",\n";
}
if (params.pesieve_args.iat != pesieve::PE_IATS_NONE) {
OUT_PADDED(stream, level, "\"iat_hooked\" : ");
stream << std::dec << pidToReport[pid].iat_hooked << ",\n";
OUT_PADDED(stream, level, L"\"iat_hooked\" : ");
stream << std::dec << pidToReport[pid].iat_hooked << L",\n";
}
OUT_PADDED(stream, level, "\"implanted_pe\" : ");
stream << std::dec << pidToReport[pid].implanted_pe << ",\n";
OUT_PADDED(stream, level, "\"implanted_shc\" : ");
stream << std::dec << pidToReport[pid].implanted_shc << ",\n";
OUT_PADDED(stream, level, "\"unreachable_file\" : ");
stream << std::dec << pidToReport[pid].unreachable_file << ",\n";
OUT_PADDED(stream, level, "\"other\" : ");
stream << std::dec << pidToReport[pid].other << "\n";
OUT_PADDED(stream, level, L"\"implanted_pe\" : ");
stream << std::dec << pidToReport[pid].implanted_pe << L",\n";
OUT_PADDED(stream, level, L"\"implanted_shc\" : ");
stream << std::dec << pidToReport[pid].implanted_shc << L",\n";
OUT_PADDED(stream, level, L"\"unreachable_file\" : ");
stream << std::dec << pidToReport[pid].unreachable_file << L",\n";
OUT_PADDED(stream, level, L"\"other\" : ");
stream << std::dec << pidToReport[pid].other << L"\n";
level--;
OUT_PADDED(stream, level, "}");
OUT_PADDED(stream, level, L"}");
printed++;
if (printed < suspicious.size()) {
stream << ",";
stream << L",";
}
stream << "\n";
stream << L"\n";
}
level--;
OUT_PADDED(stream, level, "]\n");
OUT_PADDED(stream, level, L"]\n");
return printed;
}
std::string HHScanReport::toJSON(const t_hh_params &params)
{
std::stringstream stream;
std::wstringstream stream;
size_t level = 0;
OUT_PADDED(stream, level, "{\n");
OUT_PADDED(stream, level, L"{\n");
level++;
//summary:
const size_t suspicious_count = countSuspicious();
OUT_PADDED(stream, level, "\"scan_date_time\" : ");
stream << std::dec << "\"" << util::strtime(this->startTime) << "\"" << ",\n";
OUT_PADDED(stream, level, "\"scan_timestamp\" : ");
stream << std::dec << startTime << ",\n";
OUT_PADDED(stream, level, "\"scan_time_ms\" : ");
stream << std::dec << getScanTime() << ",\n";
OUT_PADDED(stream, level, "\"scanned_count\" : ");
stream << std::dec << countTotal() << ",\n";
OUT_PADDED(stream, level, "\"suspicious_count\" : ");
OUT_PADDED(stream, level, L"\"scan_date_time\" : ");
stream << std::dec << L"\"" << util::strtime(this->startTime) << L"\"" << L",\n";
OUT_PADDED(stream, level, L"\"scan_timestamp\" : ");
stream << std::dec << startTime << L",\n";
OUT_PADDED(stream, level, L"\"scan_time_ms\" : ");
stream << std::dec << getScanTime() << L",\n";
OUT_PADDED(stream, level, L"\"scanned_count\" : ");
stream << std::dec << countTotal() << L",\n";
OUT_PADDED(stream, level, L"\"suspicious_count\" : ");
stream << std::dec << suspicious_count;
if (suspicious_count > 0) {
stream << ",\n";
stream << L",\n";
reportsToJSON(stream, level, params);
}
else {
stream << "\n";
stream << L"\n";
}
level--;
OUT_PADDED(stream, level, "}\n");
return stream.str();
OUT_PADDED(stream, level, L"}\n");
return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(stream.str());
}
void print_scantime(std::stringstream &stream, size_t timeInMs)
template<class STR_STREAM>
void print_scantime(STR_STREAM& stream, size_t timeInMs)
{
float seconds = ((float)timeInMs / 1000);
float minutes = ((float)timeInMs / 60000);
stream << std::dec << timeInMs << " ms.";
stream << std::dec << timeInMs << L" ms.";
if (seconds > 0.5) {
stream << " = " << seconds << " sec.";
stream << L" = " << seconds << L" sec.";
}
if (minutes > 0.5) {
stream << " = " << minutes << " min.";
stream << L" = " << minutes << L" min.";
}
}
std::string HHScanReport::toString()
{
std::stringstream stream;
std::wstringstream stream;
//summary:
stream << "--------" << std::endl;
stream << "SUMMARY:\n";
stream << "Scan at: " << util::strtime(this->startTime) << " (" << std::dec << startTime << ")\n";
stream << "Finished scan in: ";
stream << L"--------" << std::endl;
stream << L"SUMMARY:\n";
stream << L"Scan at: " << util::strtime(this->startTime) << L" (" << std::dec << startTime << L")\n";
stream << L"Finished scan in: ";
print_scantime(stream, getScanTime());
stream << "\n";
stream << "[*] Total scanned: " << std::dec << countTotal() << "\n";
stream << "[*] Total suspicious: " << std::dec << countSuspicious() << "\n";
stream << L"\n";
stream << L"[*] Total scanned: " << std::dec << countTotal() << L"\n";
stream << L"[*] Total suspicious: " << std::dec << countSuspicious() << L"\n";
if (countSuspicious() > 0) {
stream << "[+] List of suspicious: \n";
stream << L"[+] List of suspicious: \n";
reportsToString(stream);
}
return stream.str();
return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(stream.str());
}
+4 -4
View File
@@ -34,7 +34,7 @@ public:
return (this->endTick - this->startTick);
}
bool appendReport(pesieve::t_report &scan_report, const std::string &img_name);
bool appendReport(pesieve::t_report &scan_report, const std::wstring &img_name);
size_t countSuspicious() const
{
@@ -49,10 +49,10 @@ public:
std::string toString();
protected:
size_t reportsToString(std::stringstream &stream);
size_t reportsToString(std::wstringstream &stream);
std::string toJSON(const t_hh_params &params);
size_t reportsToJSON(std::stringstream &stream, size_t level, const t_hh_params &params);
size_t reportsToJSON(std::wstringstream &stream, size_t level, const t_hh_params &params);
time_t startTime;
time_t endTime;
@@ -61,7 +61,7 @@ protected:
DWORD endTick;
std::map<DWORD, pesieve::t_report> pidToReport;
std::map<DWORD, std::string> pidToName;
std::map<DWORD, std::wstring> pidToName;
std::vector<DWORD> suspicious;
friend class HHScanner;
+12 -10
View File
@@ -4,7 +4,8 @@
#include <fstream>
#include <sstream>
#include <iomanip>
#include <codecvt>
#include <locale>
#include <time.h>
#include <tlhelp32.h>
@@ -154,12 +155,12 @@ namespace files_util {
namespace util {
bool is_searched_name(const char* processName, std::set<std::string> &names_list)
bool is_searched_name(const WCHAR* processName, std::set<std::wstring> &names_list)
{
std::set<std::string>::iterator itr;
std::set<std::wstring>::iterator itr;
for (itr = names_list.begin(); itr != names_list.end(); ++itr) {
const char* searchedName = itr->c_str();
if (_stricmp(processName, searchedName) == 0) {
const WCHAR* searchedName = itr->c_str();
if (_wcsicmp(processName, searchedName) == 0) {
return true;
}
}
@@ -178,16 +179,17 @@ namespace util {
template <typename TYPE_T>
std::string list_to_str(std::set<TYPE_T> &list)
{
std::stringstream stream;
std::wstringstream stream;
for (auto itr = list.begin(); itr != list.end(); ) {
std::set<TYPE_T>::iterator itr;
for (itr = list.begin(); itr != list.end(); ) {
stream << *itr;
++itr;
if (itr != list.end()) {
stream << ", ";
}
}
return stream.str();
return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(stream.str());
}
}; //namespace util
@@ -322,7 +324,7 @@ void HHScanner::printSingleReport(pesieve::t_report& report)
}
}
t_single_scan_status HHScanner::scanNextProcess(DWORD pid, char* exe_file, HHScanReport &my_report)
t_single_scan_status HHScanner::scanNextProcess(DWORD pid, WCHAR* exe_file, HHScanReport &my_report)
{
bool found = false;
@@ -362,7 +364,7 @@ t_single_scan_status HHScanner::scanNextProcess(DWORD pid, char* exe_file, HHSca
}
if (!hh_args.quiet) {
std::cout << ">> Scanning PID: " << std::setw(PID_FIELD_SIZE) << std::dec << pid;
std::cout << " : " << exe_file;
std::wcout << " : " << exe_file;
if (is_process_wow64) {
std::cout << " : 32b";
+1 -1
View File
@@ -35,7 +35,7 @@ protected:
size_t scanProcesses(HHScanReport &my_report);
void printSingleReport(pesieve::t_report& report);
t_single_scan_status scanNextProcess(DWORD pid, char* image_buf, HHScanReport &report);
t_single_scan_status scanNextProcess(DWORD pid, WCHAR* image_buf, HHScanReport &report);
void initOutDir(time_t scan_time, pesieve::t_params &pesieve_args);
t_hh_params &hh_args;
Binary file not shown.
@@ -0,0 +1,696 @@
ImageRuntimeVersion: v4.0.30319
Assembly Microsoft.O365.Security.Native.ETW, Version=1.0.*, Culture=Invariant Language (Invariant Country):
hash=SHA1, flags=PublicKey
Assembly mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089:
hash=None, flags=None
Assembly System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089:
hash=None, flags=None
Assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089:
hash=None, flags=None
Assembly System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089:
hash=None, flags=None
Class Microsoft.O365.Security.ETW.TraceAlreadyRegistered: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.InvalidParameter: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.OpenTraceFailure: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.CouldNotFindSchema: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.UnexpectedError: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.ParserException: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.TypeMismatchAssert: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.ContainerIdFormatException: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.NoTraceSessionsRemaining: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:System.Exception
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.EventTraceProperties: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Fields:
UInt32 BufferSize : Public
UInt32 MinimumBuffers : Public
UInt32 MaximumBuffers : Public
UInt32 LogFileMode : Public
UInt32 FlushTimer : Public
Interface Microsoft.O365.Security.ETW.IEventRecordMetadata: AutoLayout, AnsiClass, Class, Public, ClassSemanticsMask, Abstract, BeforeFieldInit
Properties:
IntPtr UserData 'get ' :
UInt16 UserDataLength 'get ' :
System.Guid ActivityId 'get ' :
System.Guid ProviderId 'get ' :
System.DateTime Timestamp 'get ' :
UInt32 ThreadId 'get ' :
UInt32 ProcessId 'get ' :
Microsoft.O365.Security.ETW.EventHeaderProperty EventProperty 'get ' :
UInt16 Flags 'get ' :
Byte Level 'get ' :
Byte Version 'get ' :
Byte Opcode 'get ' :
UInt16 Id 'get ' :
Methods:
get_Id(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_Opcode(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_Version(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_Level(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_Flags(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_EventProperty(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_ProcessId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_ThreadId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_Timestamp(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_ProviderId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_ActivityId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_UserDataLength(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_UserData(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
CopyUserData(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetContainerId(Guid&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Class Microsoft.O365.Security.ETW.EventRecordMetadata: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Interfaces:
Microsoft.O365.Security.ETW.IEventRecordMetadata
Fields:
UInt64 CONTAINER_ID_DATA_LENGTH_IN_BYTES IsConst : Public, Static, HasDefault
Properties:
IntPtr UserData 'get ' :
UInt16 UserDataLength 'get ' :
System.Guid ActivityId 'get ' :
System.Guid ProviderId 'get ' :
System.DateTime Timestamp 'get ' :
UInt32 ThreadId 'get ' :
UInt32 ProcessId 'get ' :
Microsoft.O365.Security.ETW.EventHeaderProperty EventProperty 'get ' :
UInt16 Flags 'get ' :
Byte Level 'get ' :
Byte Version 'get ' :
Byte Opcode 'get ' :
UInt16 Id 'get ' :
Methods:
get_Id(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_Opcode(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_Version(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_Level(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_Flags(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_EventProperty(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_ProcessId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_ThreadId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_Timestamp(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_ProviderId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_ActivityId(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_UserDataLength(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_UserData(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
CopyUserData(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetContainerId(Guid&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Class Microsoft.O365.Security.ETW.Property: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.String, UInt32, UInt32): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
System.IDisposable
Properties:
Int32 OutType 'get ' :
Int32 Type 'get ' :
System.String Name 'get ' :
Methods:
get_Name(): PrivateScope, Public, HideBySig, SpecialName
get_Type(): PrivateScope, Public, HideBySig, SpecialName
get_OutType(): PrivateScope, Public, HideBySig, SpecialName
~Property(): PrivateScope, Public, HideBySig
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.PropertyEnumerator: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Interfaces:
System.Collections.Generic.IEnumerator`1[Microsoft.O365.Security.ETW.Property]
System.IDisposable
System.Collections.IEnumerator
Methods:
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.PropertyEnumerable: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Interfaces:
System.Collections.Generic.IEnumerable`1[Microsoft.O365.Security.ETW.Property]
System.Collections.IEnumerable
Methods:
GetEnumerator(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetEnumerator2(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Interface Microsoft.O365.Security.ETW.IEventRecord: AutoLayout, AnsiClass, Class, Public, ClassSemanticsMask, Abstract, BeforeFieldInit
Interfaces:
Microsoft.O365.Security.ETW.IEventRecordMetadata
Properties:
System.Collections.Generic.IEnumerable`1[Microsoft.O365.Security.ETW.Property] Properties 'get ' :
System.String ProviderName 'get ' :
System.String TaskName 'get ' :
System.String OpcodeName 'get ' :
System.String Name 'get ' :
Methods:
get_Name(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_OpcodeName(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_TaskName(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_ProviderName(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
GetUnicodeString(String, String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUnicodeString(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetUnicodeString(String, String&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetAnsiString(String, String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetAnsiString(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetAnsiString(String, String&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetCountedString(String, String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetCountedString(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetCountedString(String, String&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetIPAddress(String, IPAddress): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetIPAddress(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetIPAddress(String, IPAddress&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetSocketAddress(String, SocketAddress): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetSocketAddress(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetSocketAddress(String, SocketAddress&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetDateTime(String, ValueType DateTime IsBoxed): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetDateTime(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetDateTime(String, ValueType&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt8(String, SByte): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt8(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetInt8(String, SByte&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt8(String, Byte): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt8(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetUInt8(String, Byte&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt16(String, Int16): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt16(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetInt16(String, Int16&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt16(String, UInt16): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt16(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetUInt16(String, UInt16&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt32(String, Int32): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt32(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetInt32(String, Int32&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt32(String, UInt32): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt32(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetUInt32(String, UInt32&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt64(String, Int64): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetInt64(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetInt64(String, Int64&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt64(String, UInt64): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetUInt64(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetUInt64(String, UInt64&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
get_Properties(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
GetBinary(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
TryGetBinary(String, Byte[]&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
GetStackTrace(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Class Microsoft.O365.Security.ETW.EventRecord: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.EventRecordMetadata
Interfaces:
Microsoft.O365.Security.ETW.IEventRecord
Properties:
System.Collections.Generic.IEnumerable`1[Microsoft.O365.Security.ETW.Property] Properties 'get ' :
System.String ProviderName 'get ' :
System.String TaskName 'get ' :
System.String OpcodeName 'get ' :
System.String Name 'get ' :
Methods:
get_Name(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_OpcodeName(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_TaskName(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_ProviderName(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
GetUnicodeString(String, String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUnicodeString(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetUnicodeString(String, String&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetAnsiString(String, String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetAnsiString(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetAnsiString(String, String&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetCountedString(String, String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetCountedString(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetCountedString(String, String&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetIPAddress(String, IPAddress): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetIPAddress(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetIPAddress(String, IPAddress&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetSocketAddress(String, SocketAddress): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetSocketAddress(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetSocketAddress(String, SocketAddress&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetSecurityIdentifier(String, SecurityIdentifier): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetSecurityIdentifier(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetSecurityIdentifier(String, SecurityIdentifier&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetPointer(String, ValueType IntPtr IsBoxed): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetPointer(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetPointer(String, ValueType&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetDateTime(String, ValueType DateTime IsBoxed): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetDateTime(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetDateTime(String, ValueType&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt8(String, SByte): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt8(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetInt8(String, SByte&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt8(String, Byte): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt8(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetUInt8(String, Byte&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt16(String, Int16): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt16(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetInt16(String, Int16&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt16(String, UInt16): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt16(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetUInt16(String, UInt16&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt32(String, Int32): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt32(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetInt32(String, Int32&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt32(String, UInt32): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt32(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetUInt32(String, UInt32&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt64(String, Int64): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetInt64(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetInt64(String, Int64&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt64(String, UInt64): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetUInt64(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetUInt64(String, UInt64&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
get_Properties(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
GetBinary(String): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
TryGetBinary(String, Byte[]&(Out)): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
GetStackTrace(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Interface Microsoft.O365.Security.ETW.IEventRecordError: AutoLayout, AnsiClass, Class, Public, ClassSemanticsMask, Abstract, BeforeFieldInit
Properties:
Microsoft.O365.Security.ETW.IEventRecordMetadata Record 'get ' :
System.String Message 'get ' :
Methods:
get_Message(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
get_Record(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Class Microsoft.O365.Security.ETW.EventRecordError: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Interfaces:
Microsoft.O365.Security.ETW.IEventRecordError
Properties:
Microsoft.O365.Security.ETW.IEventRecordMetadata Record 'get ' :
System.String Message 'get ' :
Methods:
get_Message(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
get_Record(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, SpecialName
Class Microsoft.O365.Security.ETW.Testing.SynthRecord: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Interfaces:
System.IDisposable
Properties:
UInt16 Flags 'get set' :
Byte Opcode 'get set' :
Byte Version 'get set' :
UInt16 Id 'get set' :
System.Guid ProviderId 'get set' :
Methods:
get_ProviderId(): PrivateScope, Public, HideBySig, SpecialName
set_ProviderId(Guid): PrivateScope, Public, HideBySig, SpecialName
get_Id(): PrivateScope, Public, HideBySig, SpecialName
set_Id(UInt16): PrivateScope, Public, HideBySig, SpecialName
get_Version(): PrivateScope, Public, HideBySig, SpecialName
set_Version(Byte): PrivateScope, Public, HideBySig, SpecialName
get_Opcode(): PrivateScope, Public, HideBySig, SpecialName
set_Opcode(Byte): PrivateScope, Public, HideBySig, SpecialName
get_Flags(): PrivateScope, Public, HideBySig, SpecialName
set_Flags(UInt16): PrivateScope, Public, HideBySig, SpecialName
~SynthRecord(): PrivateScope, Public, HideBySig
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.Predicate: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Interfaces:
System.IDisposable
Methods:
op_LogicalAnd(Predicate): PrivateScope, Public, HideBySig, SpecialName
op_LogicalOr(Predicate): PrivateScope, Public, HideBySig, SpecialName
op_LogicalNot(): PrivateScope, Public, HideBySig, SpecialName
And(Predicate): PrivateScope, Public, HideBySig
Or(Predicate): PrivateScope, Public, HideBySig
Test(SynthRecord): PrivateScope, Public, HideBySig
~Predicate(): PrivateScope, Public, HideBySig
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.IEventRecordDelegate: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.MulticastDelegate
Void .ctor(System.Object, IntPtr): PrivateScope, Public, SpecialName, RTSpecialName
Methods:
Invoke(IEventRecord): PrivateScope, Public, Final, Virtual, VtableLayoutMask
BeginInvoke(IEventRecord, AsyncCallback, Object): PrivateScope, Public, Final, Virtual, VtableLayoutMask
EndInvoke(IAsyncResult): PrivateScope, Public, Final, Virtual, VtableLayoutMask
Class Microsoft.O365.Security.ETW.EventRecordErrorDelegate: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.MulticastDelegate
Void .ctor(System.Object, IntPtr): PrivateScope, Public, SpecialName, RTSpecialName
Methods:
Invoke(IEventRecordError): PrivateScope, Public, Final, Virtual, VtableLayoutMask
BeginInvoke(IEventRecordError, AsyncCallback, Object): PrivateScope, Public, Final, Virtual, VtableLayoutMask
EndInvoke(IAsyncResult): PrivateScope, Public, Final, Virtual, VtableLayoutMask
Class Microsoft.O365.Security.ETW.EventFilter: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.Collections.Generic.List`1[System.UInt16], Microsoft.O365.Security.ETW.Predicate): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(System.Collections.Generic.List`1[System.UInt16]): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(UInt16, Microsoft.O365.Security.ETW.Predicate): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(UInt16): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(Microsoft.O365.Security.ETW.Predicate): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
System.IDisposable
Events:
Microsoft.O365.Security.ETW.EventRecordErrorDelegate OnError: SpecialName
Microsoft.O365.Security.ETW.IEventRecordDelegate OnEvent: SpecialName
Methods:
add_OnEvent(IEventRecordDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnEvent(IEventRecordDelegate): PrivateScope, Public, HideBySig, SpecialName
add_OnError(EventRecordErrorDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnError(EventRecordErrorDelegate): PrivateScope, Public, HideBySig, SpecialName
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.KernelProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.Guid, UInt32): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(UInt32, System.Guid): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
System.IDisposable
Properties:
System.Guid Id 'get ' :
Events:
Microsoft.O365.Security.ETW.EventRecordErrorDelegate OnError: SpecialName
Microsoft.O365.Security.ETW.IEventRecordDelegate OnEvent: SpecialName
Methods:
AddFilter(EventFilter): PrivateScope, Public, HideBySig
add_OnEvent(IEventRecordDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnEvent(IEventRecordDelegate): PrivateScope, Public, HideBySig, SpecialName
add_OnError(EventRecordErrorDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnError(EventRecordErrorDelegate): PrivateScope, Public, HideBySig, SpecialName
get_Id(): PrivateScope, Public, HideBySig, SpecialName
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.Provider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(System.Guid): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
System.IDisposable
Fields:
UInt64 AllBitsSet IsConst : Public, Static
Properties:
Microsoft.O365.Security.ETW.TraceFlags TraceFlags 'get set' :
Byte Level 'set' :
UInt64 All 'set' :
UInt64 Any 'set' :
Events:
Microsoft.O365.Security.ETW.EventRecordErrorDelegate OnError: SpecialName
Microsoft.O365.Security.ETW.IEventRecordDelegate OnEvent: SpecialName
Methods:
set_Any(UInt64): PrivateScope, Public, HideBySig, SpecialName
set_All(UInt64): PrivateScope, Public, HideBySig, SpecialName
set_Level(Byte): PrivateScope, Public, HideBySig, SpecialName
get_TraceFlags(): PrivateScope, Public, HideBySig, SpecialName
set_TraceFlags(TraceFlags): PrivateScope, Public, HideBySig, SpecialName
EnableRundownEvents(): PrivateScope, Public, HideBySig
AddFilter(EventFilter): PrivateScope, Public, HideBySig
add_OnEvent(IEventRecordDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnEvent(IEventRecordDelegate): PrivateScope, Public, HideBySig, SpecialName
add_OnError(EventRecordErrorDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnError(EventRecordErrorDelegate): PrivateScope, Public, HideBySig, SpecialName
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.IEventRecordMetadataDelegate: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.MulticastDelegate
Void .ctor(System.Object, IntPtr): PrivateScope, Public, SpecialName, RTSpecialName
Methods:
Invoke(IEventRecordMetadata): PrivateScope, Public, Final, Virtual, VtableLayoutMask
BeginInvoke(IEventRecordMetadata, AsyncCallback, Object): PrivateScope, Public, Final, Virtual, VtableLayoutMask
EndInvoke(IAsyncResult): PrivateScope, Public, Final, Virtual, VtableLayoutMask
Class Microsoft.O365.Security.ETW.RawProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(System.Guid): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
System.IDisposable
Fields:
UInt64 AllBitsSet IsConst : Public, Static
Properties:
Microsoft.O365.Security.ETW.TraceFlags TraceFlags 'get set' :
Byte Level 'set' :
UInt64 All 'set' :
UInt64 Any 'set' :
Events:
Microsoft.O365.Security.ETW.IEventRecordMetadataDelegate OnEvent: SpecialName
Methods:
set_Any(UInt64): PrivateScope, Public, HideBySig, SpecialName
set_All(UInt64): PrivateScope, Public, HideBySig, SpecialName
set_Level(Byte): PrivateScope, Public, HideBySig, SpecialName
get_TraceFlags(): PrivateScope, Public, HideBySig, SpecialName
set_TraceFlags(TraceFlags): PrivateScope, Public, HideBySig, SpecialName
add_OnEvent(IEventRecordMetadataDelegate): PrivateScope, Public, HideBySig, SpecialName
remove_OnEvent(IEventRecordMetadataDelegate): PrivateScope, Public, HideBySig, SpecialName
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Struct Microsoft.O365.Security.ETW.TraceStats: AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit
:System.ValueType
Fields:
UInt32 BuffersCount : Public, InitOnly
UInt32 BuffersFree : Public, InitOnly
UInt32 BuffersWritten : Public, InitOnly
UInt32 BuffersLost : Public, InitOnly
UInt64 EventsTotal : Public, InitOnly
UInt64 EventsHandled : Public, InitOnly
UInt32 EventsLost : Public, InitOnly
Interface Microsoft.O365.Security.ETW.ITrace: AutoLayout, AnsiClass, Class, Public, ClassSemanticsMask, Abstract, BeforeFieldInit
Methods:
SetTraceProperties(EventTraceProperties): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Start(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Stop(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
QueryStats(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Interface Microsoft.O365.Security.ETW.IUserTrace: AutoLayout, AnsiClass, Class, Public, ClassSemanticsMask, Abstract, BeforeFieldInit
Interfaces:
Microsoft.O365.Security.ETW.ITrace
Methods:
Enable(RawProvider): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Enable(Provider): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Interface Microsoft.O365.Security.ETW.IKernelTrace: AutoLayout, AnsiClass, Class, Public, ClassSemanticsMask, Abstract, BeforeFieldInit
Interfaces:
Microsoft.O365.Security.ETW.ITrace
Methods:
Enable(KernelProvider): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Class Microsoft.O365.Security.ETW.UserTrace: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
Microsoft.O365.Security.ETW.IUserTrace
Microsoft.O365.Security.ETW.ITrace
System.IDisposable
Methods:
Enable(RawProvider): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Enable(Provider): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
SetTraceProperties(EventTraceProperties): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Open(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Start(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Stop(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
QueryStats(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.Filter: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Methods:
Not(Predicate): PrivateScope, Public, Static, HideBySig
AnyEvent(): PrivateScope, Public, Static, HideBySig
EventOpcodeIs(Int32): PrivateScope, Public, Static, HideBySig
EventIdIs(Int32): PrivateScope, Public, Static, HideBySig
EventVersionIs(Int32): PrivateScope, Public, Static, HideBySig
ProcessIdIs(Int32): PrivateScope, Public, Static, HideBySig
IsUInt32(String, UInt32): PrivateScope, Public, Static, HideBySig
Class Microsoft.O365.Security.ETW.UnicodeString: AutoLayout, AnsiClass, Class, Public, Abstract, Sealed, BeforeFieldInit
Methods:
Is(String, String): PrivateScope, Public, Static, HideBySig
IEquals(String, String): PrivateScope, Public, Static, HideBySig
Contains(String, String): PrivateScope, Public, Static, HideBySig
IContains(String, String): PrivateScope, Public, Static, HideBySig
StartsWith(String, String): PrivateScope, Public, Static, HideBySig
IStartsWith(String, String): PrivateScope, Public, Static, HideBySig
EndsWith(String, String): PrivateScope, Public, Static, HideBySig
IEndsWith(String, String): PrivateScope, Public, Static, HideBySig
Class Microsoft.O365.Security.ETW.AnsiString: AutoLayout, AnsiClass, Class, Public, Abstract, Sealed, BeforeFieldInit
Methods:
Is(String, String): PrivateScope, Public, Static, HideBySig
IEquals(String, String): PrivateScope, Public, Static, HideBySig
Contains(String, String): PrivateScope, Public, Static, HideBySig
IContains(String, String): PrivateScope, Public, Static, HideBySig
StartsWith(String, String): PrivateScope, Public, Static, HideBySig
IStartsWith(String, String): PrivateScope, Public, Static, HideBySig
EndsWith(String, String): PrivateScope, Public, Static, HideBySig
IEndsWith(String, String): PrivateScope, Public, Static, HideBySig
Class Microsoft.O365.Security.ETW.CountedString: AutoLayout, AnsiClass, Class, Public, Abstract, Sealed, BeforeFieldInit
Methods:
Is(String, String): PrivateScope, Public, Static, HideBySig
IEquals(String, String): PrivateScope, Public, Static, HideBySig
Contains(String, String): PrivateScope, Public, Static, HideBySig
IContains(String, String): PrivateScope, Public, Static, HideBySig
StartsWith(String, String): PrivateScope, Public, Static, HideBySig
IStartsWith(String, String): PrivateScope, Public, Static, HideBySig
EndsWith(String, String): PrivateScope, Public, Static, HideBySig
IEndsWith(String, String): PrivateScope, Public, Static, HideBySig
Class Microsoft.O365.Security.ETW.KernelTrace: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.String): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
Microsoft.O365.Security.ETW.IKernelTrace
Microsoft.O365.Security.ETW.ITrace
System.IDisposable
Methods:
Enable(KernelProvider): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
SetTraceProperties(EventTraceProperties): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Open(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Start(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Stop(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
QueryStats(): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
SetDefaultEventCallback(IEventRecordDelegate): PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.Kernel.AlpcProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ContextSwitchProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.DebugPrintProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.DiskFileIoProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.DiskIoProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.DiskInitIoProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.FileIoProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.FileInitIoProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ThreadDispatchProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.DpcProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.DriverProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ImageLoadProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.InterruptProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.MemoryHardFaultProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.MemoryPageFaultProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.NetworkTcpipProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ProcessProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ProcessCounterProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ProfileProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.RegistryProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.SplitIoProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.SystemCallProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ThreadProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.VaMapProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.VirtualAllocProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Kernel.ObjectManagerProvider: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
:Microsoft.O365.Security.ETW.KernelProvider
Void .ctor(): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Class Microsoft.O365.Security.ETW.Testing.EventHeader: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(_EVENT_HEADER*): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Properties:
UInt16 Flags 'get set' :
Methods:
get_Flags(): PrivateScope, Public, HideBySig, SpecialName
set_Flags(UInt16): PrivateScope, Public, HideBySig, SpecialName
Class Microsoft.O365.Security.ETW.Testing.RecordBuilder: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(System.Guid, Int32, Int32): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(System.Guid, Int32, Int32, Int32): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Interfaces:
System.IDisposable
Properties:
Microsoft.O365.Security.ETW.Testing.EventHeader Header 'get ' :
Methods:
Pack(): PrivateScope, Public, HideBySig
PackIncomplete(): PrivateScope, Public, HideBySig
get_Header(): PrivateScope, Public, HideBySig, SpecialName
AddAnsiString(String, String): PrivateScope, Public, HideBySig
AddUnicodeString(String, String): PrivateScope, Public, HideBySig
AddValue(String, T): PrivateScope, Public, HideBySig
AddContainerId(Guid): PrivateScope, Public, HideBySig
~RecordBuilder(): PrivateScope, Public, HideBySig
Dispose(): PrivateScope, Public, Final, Virtual, HideBySig
Class Microsoft.O365.Security.ETW.Testing.Proxy: AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
Void .ctor(Microsoft.O365.Security.ETW.EventFilter): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(Microsoft.O365.Security.ETW.KernelTrace): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Void .ctor(Microsoft.O365.Security.ETW.UserTrace): PrivateScope, Public, HideBySig, SpecialName, RTSpecialName
Methods:
PushEvent(SynthRecord): PrivateScope, Public, HideBySig
Struct Microsoft.O365.Security.ETW.LogFileModeFlags: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.Enum
Fields:
UInt32 value__ : Public, SpecialName, RTSpecialName
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_FILE_MODE_NONE = 0 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_FILE_MODE_SEQUENTIAL = 1 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_FILE_MODE_CIRCULAR = 2 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_FILE_MODE_APPEND = 4 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_REAL_TIME_MODE = 256 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_DELAY_OPEN_FILE_MODE = 512 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_BUFFERING_MODE = 1024 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_PRIVATE_LOGGER_MODE = 2048 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_ADD_HEADER_MODE = 4096 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_USE_GLOBAL_SEQUENCE = 16384 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_USE_LOCAL_SEQUENCE = 32768 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_RELOG_MODE = 65536 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_USE_PAGED_MEMORY = 16777216 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_FILE_MODE_NEWFILE = 8 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_FILE_MODE_PREALLOCATE = 32 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_NONSTOPPABLE_MODE = 64 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_SECURE_MODE = 128 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_USE_KBYTES_FOR_SIZE = 8192 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_PRIVATE_IN_PROC = 131072 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_MODE_RESERVED = 1048576 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = 268435456 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_SYSTEM_LOGGER_MODE = 33554432 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_ADDTO_TRIAGE_DUMP = 2147483648 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN = 4194304 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN = 8388608 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_INDEPENDENT_SESSION_MODE = 134217728 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.LogFileModeFlags FLAG_EVENT_TRACE_COMPRESSED_MODE = 67108864 : Public, Static, Literal, HasDefault
Struct Microsoft.O365.Security.ETW.EventHeaderProperty: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.Enum
Fields:
UInt16 value__ : Public, SpecialName, RTSpecialName
Microsoft.O365.Security.ETW.EventHeaderProperty XML = 1 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.EventHeaderProperty FORWARDED_XML = 2 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.EventHeaderProperty LEGACY_EVENTLOG = 4 : Public, Static, Literal, HasDefault
Struct Microsoft.O365.Security.ETW.TraceFlags: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.Enum
Fields:
Int32 value__ : Public, SpecialName, RTSpecialName
Microsoft.O365.Security.ETW.TraceFlags IncludeUserSid = 1 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags IncludeTerminalSessionId = 2 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags IncludeStackTrace = 4 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags IgnoreKeyword0 = 16 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags EnableProviderGroup = 32 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags IncludeProcessStartKey = 128 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags IncludeProcessEventKey = 256 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags ExcludeInPrivateEventKey = 512 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags EnableSilosEventKey = 1024 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.TraceFlags SourceContainerTrackingEventKey = 2048 : Public, Static, Literal, HasDefault
Struct Microsoft.O365.Security.ETW.Testing.EventHeaderFlags: AutoLayout, AnsiClass, Class, Public, Sealed, BeforeFieldInit
:System.Enum
Fields:
UInt16 value__ : Public, SpecialName, RTSpecialName
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags EXTENDED_INFO = 1 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags PRIVATE_SESSION = 2 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags STRING_ONLY = 4 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags TRACE_MESSAGE = 8 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags NO_CPUTIME = 16 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags HEADER_32_BIT = 32 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags HEADER_64_BIT = 64 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags CLASSIC_HEADER = 256 : Public, Static, Literal, HasDefault
Microsoft.O365.Security.ETW.Testing.EventHeaderFlags PROCESSOR_INDEX = 512 : Public, Static, Literal, HasDefault
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+63
View File
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
+30
View File
@@ -0,0 +1,30 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: windows-2022
steps:
- uses: actions/checkout@v2
- uses: microsoft/setup-msbuild@v1
- uses: NuGet/[email protected]
- uses: darenm/Setup-VSTest@v1
- name: nuget restore
run: nuget.exe restore krabs\krabs.sln
- name: build release
run: msbuild.exe /nologo /m /t:Rebuild /p:Configuration=Release krabs\krabs.sln
- name: build debug
run: msbuild.exe /nologo /m /t:Rebuild /p:Configuration=Debug krabs\krabs.sln
- name: test native debug
run: vstest.console.exe krabs\x64\Debug\krabstests.dll
- name: test debug net462
run: vstest.console.exe tests\ManagedETWTests\bin\Debug\net462\EtwTestsCS.dll
- name: test debug net6.0
run: vstest.console.exe tests\ManagedETWTests\bin\Debug\net6.0\EtwTestsCS.dll
+45
View File
@@ -0,0 +1,45 @@
# Good Reference
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
bin
obj
*.user
*.suo
*.VC.opendb
TestResults/
FakesAssemblies/
# Native Stuff
*.sdf
*.opensdf
*.ipch
*.aps
[Dd]ebug/
[Rr]elease/
x64/
# NuGet Packages
**/packages/*
#!**/packages/repositories.config
*.nupkg
# githooks specific
githooks/*.dll
# VS2015 db
*.VC.db
# ignore cert files
*.snk
*.pfx
# ignore Mac stuff
.DS_Store
# Visual Studio files.
.vs/
# Vim files
*~
*.swp
*.swo
+20
View File
@@ -0,0 +1,20 @@
# Contributing to krabsetw
This project welcomes contributions and suggestions. Most contributions require you to
agree to a Contributor License Agreement (CLA) declaring that you have the right to,
and actually do, grant us the rights to use your contribution. For details, visit
https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need
to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the
instructions provided by the bot. You will only need to do this once across all repositories using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
## Governance
At this time, all technical decisions are made by a 3-person technical committee from the OneDrive/SharePoint Security team. Feature requests and bug fixes in the form of GitHub Issues will be reviewed by this group and prioritized with other existing work assuming they're approved.
## Questions?
Please create GitHub issues for any questions you have and someone will get back to you.
+25
View File
@@ -0,0 +1,25 @@
krabsetw
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the ""Software""), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugSigning|x64">
<Configuration>DebugSigning</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseSigning|x64">
<Configuration>ReleaseSigning</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9DE6788C-5759-4A75-B484-ABA4C7EF5F08}</ProjectGuid>
<TargetFramework>net6.0</TargetFramework>
<Keyword>NetCoreCProj</Keyword>
<RootNamespace>ETWLib</RootNamespace>
<ProjectName>Microsoft.O365.Security.Native.ETW.NetCore</ProjectName>
<AssemblyName>Microsoft.O365.Security.Native.ETW</AssemblyName>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">.\</SolutionDir>
<RestorePackages>true</RestorePackages>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<ReadOnlyProject>true</ReadOnlyProject>
<ReplaceWildcardsInProjectItems>true</ReplaceWildcardsInProjectItems>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFramework)\</OutDir>
</PropertyGroup>
<!--
Manually creating the path because MSBuild doesn't create this folder which causes:
warning MSB3101: Could not write state file "x64\ReleaseSigning\net6.0\Microsoft.O365.Security.Native.ETW.NetCore.vcxproj.AssemblyReference.cache".
Could not find a part of the path [...]
-->
<Target Name="CreateDirectories" BeforeTargets="PrepareForBuild" >
<MakeDir Directories="$(Platform)\$(Configuration)\$(TargetFramework)\"/>
</Target>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>NetCore</CLRSupport>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>NetCore</CLRSupport>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PlatformToolset>v143</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CLRSupport>NetCore</CLRSupport>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CLRSupport>NetCore</CLRSupport>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<EmbedManifest>false</EmbedManifest>
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LinkIncremental>true</LinkIncremental>
<LinkKeyFile>
</LinkKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'">
<EmbedManifest>false</EmbedManifest>
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LinkIncremental>true</LinkIncremental>
<LinkKeyFile>$(SolutionDir)..\35MSSharedLib1024.snk</LinkKeyFile>
<LinkDelaySign>true</LinkDelaySign>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
<LinkKeyFile>
</LinkKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
<LinkKeyFile>$(SolutionDir)..\35MSSharedLib1024.snk</LinkKeyFile>
<LinkDelaySign>true</LinkDelaySign>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>TYPEASSERT;_DEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'">
<ClCompile>
<PreprocessorDefinitions>TYPEASSERT;_DEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>NDEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<ClCompile>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>NDEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\Microsoft.O365.Security.Native.ETW\*.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Microsoft.O365.Security.Native.ETW\**\*.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
@@ -0,0 +1,3 @@
Summary
=======
This project is used for multi-targetting .net and .net core C++/CLI project and contains a copy of the [Microsoft.O365.Security.Native.ETW](../Microsoft.O365.Security.Native.ETW/Microsoft.O365.Security.Native.ETW.vcxproj) project except that files are included using wildcard.
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
@@ -0,0 +1,25 @@
# Good Reference
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
bin
obj
*.user
*.suo
TestResults/
FakesAssemblies/
# Native Stuff
*.sdf
*.opensdf
*.ipch
*.aps
[Dd]ebug/
[Rr]elease/
x64/
# NuGet Packages
**/packages/*
#!**/packages/repositories.config
# githooks specific
githooks/*.dll
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<packageSources>
<clear/>
<add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
<!-- Enable the restore command to run before builds -->
<RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
<!-- Property that enables building a package from a project -->
<BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
<!-- Determines if package restore consent is required to restore packages -->
<RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
<!-- Download NuGet.exe if it does not already exist -->
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageSources)' == '' ">
<!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
<!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
<!--
<PackageSource Include="https://www.nuget.org/api/v2/" />
<PackageSource Include="https://my-nuget-source/nuget/" />
-->
</ItemGroup>
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
<!-- Windows specific commands -->
<NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
<!-- We need to launch nuget.exe with the mono command if we're not on windows -->
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
</PropertyGroup>
<PropertyGroup>
<PackagesProjectConfig>packages.$(MSBuildProjectName.Replace(' ', '_')).config</PackagesProjectConfig>
</PropertyGroup>
<Choose>
<When Condition="Exists('$(PackagesProjectConfig)')">
<PropertyGroup>
<PackagesConfig>$(PackagesProjectConfig)</PackagesConfig>
</PropertyGroup>
</When>
<When Condition="Exists('packages.config')">
<PropertyGroup>
<PackagesConfig>packages.config</PackagesConfig>
</PropertyGroup>
</When>
</Choose>
<PropertyGroup>
<!-- NuGet command -->
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
<PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
<RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
<NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
<PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>
<!-- Commands -->
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
<!-- We need to ensure packages are restored prior to assembly resolve -->
<BuildDependsOn Condition="$(RestorePackages) == 'true'">
RestorePackages;
$(BuildDependsOn);
</BuildDependsOn>
<!-- Make the build depend on restore packages -->
<BuildDependsOn Condition="$(BuildPackage) == 'true'">
$(BuildDependsOn);
BuildPackage;
</BuildDependsOn>
</PropertyGroup>
<Target Name="CheckPrerequisites">
<!-- Raise an error if we're unable to locate nuget.exe -->
<Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
<!--
Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
This effectively acts as a lock that makes sure that the download operation will only happen once and all
parallel builds will have to wait for it to complete.
-->
<MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
</Target>
<Target Name="_DownloadNuGet">
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
</Target>
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
<Exec Command="$(RestoreCommand)"
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
<Exec Command="$(RestoreCommand)"
LogStandardErrorAsError="true"
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
</Target>
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
<Exec Command="$(BuildCommand)"
Condition=" '$(OS)' != 'Windows_NT' " />
<Exec Command="$(BuildCommand)"
LogStandardErrorAsError="true"
Condition=" '$(OS)' == 'Windows_NT' " />
</Target>
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<OutputFilename ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Reference Include="System.Core" />
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Net" />
<Using Namespace="Microsoft.Build.Framework" />
<Using Namespace="Microsoft.Build.Utilities" />
<Code Type="Fragment" Language="cs">
<![CDATA[
try {
OutputFilename = Path.GetFullPath(OutputFilename);
Log.LogMessage("Downloading latest version of NuGet.exe...");
WebClient webClient = new WebClient();
webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
return true;
}
catch (Exception ex) {
Log.LogErrorFromException(ex);
return false;
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Permissions;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly:AssemblyTitleAttribute(L"Microsoft.O365.Security.Native.ETW")];
[assembly:AssemblyDescriptionAttribute(L"")];
[assembly:AssemblyConfigurationAttribute(L"")];
[assembly:AssemblyCompanyAttribute(L"Microsoft")];
[assembly:AssemblyProductAttribute(L"Microsoft.O365.Security.Native.ETW")];
[assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2016")];
[assembly:AssemblyTrademarkAttribute(L"")];
[assembly:AssemblyCultureAttribute(L"")];
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the value or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly:AssemblyVersionAttribute("1.0.*")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <type_traits>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft::O365::Security::ETW {
// Converts a CLR List<T> of arithmetic types to a corresponding std::vector<T>
template <typename T, typename std::enable_if_t<std::is_arithmetic<T>::value, T> = 0>
std::vector<T> to_vector(List<T>^ list)
{
std::vector<T> vector(list->Count);
for each (auto item in list)
{
vector.push_back(item);
}
return vector;
}
}
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This is the main DLL file.
#include "Guid.hpp"
#include "Errors.hpp"
#include "UserTrace.hpp"
#include "TraceStats.hpp"
#include "Provider.hpp"
#include "RawProvider.hpp"
#include "KernelProvider.hpp"
#include "ITrace.hpp"
#include "IEventRecordMetadata.hpp"
#include "IEventRecord.hpp"
#include "EventRecordMetadata.hpp"
#include "EventRecord.hpp"
#include "EventRecordError.hpp"
#include "Property.hpp"
#include "Filtering/Predicate.hpp"
#include "Filtering/EventFilter.hpp"
#include "Filtering/Fluent.hpp"
#include "Filtering/UnicodeString.hpp"
#include "Filtering/AnsiString.hpp"
#include "Filtering/CountedString.hpp"
#include "KernelProvider.hpp"
#include "KernelTrace.hpp"
#include "Kernel/KernelProviders.hpp"
#include "Testing/EventHeader.hpp"
#include "Testing/SynthRecord.hpp"
#include "Testing/RecordBuilder.hpp"
#include "Testing/Proxy.hpp"
@@ -0,0 +1,104 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Thrown when the ETW trace object is already registered.
/// </summary>
public ref struct TraceAlreadyRegistered : public System::Exception {};
/// <summary>
/// Thrown when an invalid parameter is provided.
/// </summary>
public ref struct InvalidParameter : public System::Exception {};
/// <summary>
/// Thrown when the trace fails to open.
/// </summary>
public ref struct OpenTraceFailure : public System::Exception {};
/// <summary>
/// Thrown when the schema for an event could not be found.
/// </summary>
public ref struct CouldNotFindSchema : public System::Exception {
/// <param name="msg">Additional context related to the error</param>
CouldNotFindSchema(System::String^ msg) : System::Exception(msg) { }
};
/// <summary>
/// Thrown when an error occurs that we did not explicitly handle.
/// </summary>
public ref struct UnexpectedError : public System::Exception {
/// <param name="msg">Additional context related to the error</param>
UnexpectedError(System::String^ msg) : System::Exception(msg) { }
};
/// <summary>
/// Thrown when an error is encountered parsing an ETW property.
/// </summary>
public ref struct ParserException : public System::Exception {
/// <param name="msg">the error message returned while parsing</param>
ParserException(System::String^ msg) : System::Exception(msg) { }
};
/// <summary>
/// Thrown when a requested type does not match the ETW property type.
/// NOTE: This is only thrown in debug builds.
/// </summary>
public ref struct TypeMismatchAssert : public System::Exception {
/// <param name="msg">the error message returned when types mismatched</param>
TypeMismatchAssert(System::String^ msg) : System::Exception(msg) { }
};
/// <summary>
/// Thrown on internal parsing errors when retrieving container ID's.
/// </summary>
public ref struct ContainerIdFormatException : public System::Exception {
ContainerIdFormatException(System::String^ msg) : System::Exception(msg) {}
};
/// <summary>
/// Thrown when no trace sessions remaining to register. An existing trace
/// session must be deleted first.
/// </summary>
public ref struct NoTraceSessionsRemaining : public System::Exception {};
#define ExecuteAndConvertExceptions(e) \
try { e; } \
catch (const krabs::trace_already_registered &) \
{ \
throw gcnew TraceAlreadyRegistered; \
} \
catch (const krabs::invalid_parameter &) \
{ \
throw gcnew InvalidParameter; \
} \
catch (const krabs::open_trace_failure &) \
{ \
throw gcnew OpenTraceFailure; \
} \
catch (const krabs::no_trace_sessions_remaining &) \
{ \
throw gcnew NoTraceSessionsRemaining; \
} \
catch (const krabs::need_to_be_admin_failure &) \
{ \
throw gcnew UnauthorizedAccessException("Need to be admin"); \
} \
catch (const krabs::function_not_supported &) \
{ \
throw gcnew NotSupportedException(); \
} \
catch (const krabs::could_not_find_schema &ex) \
{ \
throw gcnew CouldNotFindSchema(gcnew String(ex.what())); \
} \
catch (const krabs::unexpected_error &ex) \
{ \
throw gcnew UnexpectedError(gcnew String(ex.what())); \
} \
} } } }
@@ -0,0 +1,904 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "Errors.hpp"
#include "EventRecordMetadata.hpp"
#include "IEventRecord.hpp"
#include "Property.hpp"
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace System;
using namespace System::Net;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Principal;
using namespace msclr::interop;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// EventRecord represents a managed instance of an event from ETW.
/// </summary>
public ref class EventRecord : public EventRecordMetadata, public IEventRecord
{
private:
const krabs::schema* schema_;
krabs::parser* parser_;
internal:
EventRecord(
const EVENT_RECORD& record,
const krabs::schema& schema,
krabs::parser& parser)
: EventRecordMetadata(record)
, schema_(&schema)
, parser_(&parser) { }
public:
#pragma region Schema
/// <summary>
/// Retrieves the name of the event.
/// </summary>
virtual property String^ Name
{
String^ get() { return gcnew String(schema_->event_name()); }
}
/// <summary>
/// Retrieves the opcode_name of the event.
/// </summary>
virtual property String^ OpcodeName
{
String^ get() { return gcnew String(schema_->opcode_name()); }
}
/// <summary>
/// Retrieves the task_name of the event.
/// </summary>
virtual property String^ TaskName
{
String^ get() { return gcnew String(schema_->task_name()); }
}
/// <summary>
/// Retrieves the name of the provider that fires this event.
/// </summary>
virtual property String^ ProviderName
{
String^ get() { return gcnew String(schema_->provider_name()); }
}
#pragma endregion
#pragma region Parser
#pragma region Unicode String
/// <summary>
/// Get a unicode string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the unicode string value associated with the specified property</returns>
virtual String^ GetUnicodeString(String^ name)
{
const auto& str = GetValue<std::wstring>(name);
return gcnew String(str.c_str());
}
/// <summary>
/// Get a unicode string from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the unicode string value associated with the specified property or the specified default value</returns>
virtual String^ GetUnicodeString(String^ name, String^ defaultValue)
{
String^ str;
if (TryGetUnicodeString(name, str))
return str;
return defaultValue;
}
/// <summary>
/// Attempt to get a unicode string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting string</param>
/// <returns>true if fetching the string succeeded, false otherwise</returns>
virtual bool TryGetUnicodeString(String^ name, [Out] String^% result)
{
std::wstring str;
bool success = TryGetValue(name, str);
if (success)
result = gcnew String(str.c_str());
return success;
}
#pragma endregion
#pragma region Ansi String
/// <summary>
/// Get a ANSI string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the ANSI string value associated with the specified property</returns>
virtual String^ GetAnsiString(String^ name)
{
const auto& str = GetValue<std::string>(name);
return gcnew String(str.c_str());
}
/// <summary>
/// Get a ANSI string from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the ANSI string value associated with the specified property or the specified default value</returns>
virtual String^ GetAnsiString(String^ name, String^ defaultValue)
{
String^ str;
if (TryGetAnsiString(name, str))
return str;
return defaultValue;
}
/// <summary>
/// Attempt to get a ANSI string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting string</param>
/// <returns>true if fetching the string succeeded, false otherwise</returns>
virtual bool TryGetAnsiString(String^ name, [Out] String^% result)
{
std::string str;
bool success = TryGetValue(name, str);
if (success)
result = gcnew String(str.c_str());
return success;
}
#pragma endregion
#pragma region Counted String
/// <summary>
/// Get a counted string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the counted string value associated with the specified property</returns>
virtual String^ GetCountedString(String^ name)
{
const auto& str = GetValue<const krabs::counted_string*>(name);
return ConvertToString(*str);
}
/// <summary>
/// Get a counted string from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the counted string value associated with the specified property or the specified default value</returns>
virtual String^ GetCountedString(String^ name, String^ defaultValue)
{
String^ str;
if (TryGetCountedString(name, str))
return str;
return defaultValue;
}
/// <summary>
/// Attempt to get a counted string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting string</param>
/// <returns>true if fetching the string succeeded, false otherwise</returns>
virtual bool TryGetCountedString(String^ name, [Out] String^% result)
{
const krabs::counted_string* str;
bool success = TryGetValue(name, str);
if (success)
result = ConvertToString(*str);
return success;
}
#pragma endregion
#pragma region IPAddress
/// <summary>
/// Get an IPAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the IPAddress value associated with the specified property</returns>
virtual IPAddress^ GetIPAddress(String^ name)
{
const auto& addr = GetValue<krabs::ip_address>(name);
return ConvertToIPAddress(addr);
}
/// <summary>
/// Get an IPAddress from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the IPAddress value associated with the specified property or the specified default value</returns>
virtual IPAddress^ GetIPAddress(String^ name, IPAddress^ defaultValue)
{
IPAddress^ addr;
if (TryGetIPAddress(name, addr))
return addr;
return defaultValue;
}
/// <summary>
/// Attempt to get an IPAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting IPAddress</param>
/// <returns>true if fetching the IPAddress succeeded, false otherwise</returns>
virtual bool TryGetIPAddress(String^ name, [Out] IPAddress^% result)
{
krabs::ip_address addr;
bool success = TryGetValue(name, addr);
if (success)
result = ConvertToIPAddress(addr);
return success;
}
#pragma endregion
#pragma region Socket Address
/// <summary>
/// Get an SocketAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the SocketAddress value associated with the specified property</returns>
virtual SocketAddress^ GetSocketAddress(String^ name)
{
const auto& addr = GetValue<krabs::socket_address>(name);
return ConvertToSocketAddress(addr);
}
/// <summary>
/// Get an SocketAddress from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the SocketAddress value associated with the specified property or the specified default value</returns>
virtual SocketAddress^ GetSocketAddress(String^ name, SocketAddress^ defaultValue)
{
SocketAddress^ addr;
if (TryGetSocketAddress(name, addr))
return addr;
return defaultValue;
}
/// <summary>
/// Attempt to get an SocketAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting SocketAddress</param>
/// <returns>true if fetching the SocketAddress succeeded, false otherwise</returns>
virtual bool TryGetSocketAddress(String^ name, [Out] SocketAddress^% result)
{
krabs::socket_address addr;
bool success = TryGetValue(name, addr);
if (success)
result = ConvertToSocketAddress(addr);
return success;
}
#pragma endregion
#pragma region Security Identifier
/// <summary>
/// Get a Security Identifier (SID) from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the SID value associated with the specified property</returns>
virtual SecurityIdentifier^ GetSecurityIdentifier(String^ name)
{
const auto& addr = GetValue<krabs::sid>(name);
return ConvertToSecurityIdentifier(addr);
}
/// <summary>
/// Get a Security Identifier (SID) from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the SocketAddress value associated with the specified property or the specified default value</returns>
virtual SecurityIdentifier^ GetSecurityIdentifier(String^ name, SecurityIdentifier^ defaultValue)
{
SecurityIdentifier^ addr;
if (TryGetSecurityIdentifier(name, addr))
return addr;
return defaultValue;
}
/// <summary>
/// Attempt to get a Security Identifier (SID) from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting SocketAddress</param>
/// <returns>true if fetching the SocketAddress succeeded, false otherwise</returns>
virtual bool TryGetSecurityIdentifier(String^ name, [Out] SecurityIdentifier^% result)
{
krabs::sid addr;
bool success = TryGetValue(name, addr);
if (success)
result = ConvertToSecurityIdentifier(addr);
return success;
}
#pragma endregion
#pragma region Pointer
/// <summary>
/// Get a Pointer type from the from the specified property name
/// </summary>
/// <param name="name">property name</param>
/// <returns>The IntPtr associated with the specified property</returns>
virtual IntPtr^ GetPointer(String^ name)
{
const auto& addr = GetValue<krabs::pointer>(name);
return ConvertToPointer(addr);
}
/// <summary>
/// Get a Pointer from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the IntPtr value associated with the specified property or the specified default value</returns>
virtual IntPtr^ GetPointer(String^ name, IntPtr^ defaultValue)
{
IntPtr^ addr;
if (TryGetPointer(name, addr))
return addr;
return defaultValue;
}
/// <summary>
/// Attempt to get a Pointer from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting IntPtr</param>
/// <returns>true if fetching the IntPtr succeeded, false otherwise</returns>
virtual bool TryGetPointer(String^ name, [Out] IntPtr^% result)
{
krabs::pointer addr;
bool success = TryGetValue(name, addr);
if (success)
result = ConvertToPointer(addr);
return success;
}
#pragma endregion
#pragma region DateTime
/// <summary>
/// Get a DateTime from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the DateTime value associated with the specified property</returns>
virtual DateTime^ GetDateTime(String^ name)
{
const auto& time = GetValue<::FILETIME>(name);
LARGE_INTEGER *largeInt = (LARGE_INTEGER*)&time;
return DateTime::FromFileTimeUtc(largeInt->QuadPart);
}
/// <summary>
/// Get an DateTime from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the DateTime value associated with the specified property or the specified default value</returns>
virtual DateTime^ GetDateTime(String^ name, DateTime^ defaultValue)
{
DateTime^ time;
if (TryGetDateTime(name, time))
return time;
return defaultValue;
}
/// <summary>
/// Attempt to get an DateTime from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting DateTime</param>
/// <returns>true if fetching the DateTime succeeded, false otherwise</returns>
virtual bool TryGetDateTime(String^ name, [Out] DateTime^% result)
{
::FILETIME time;
bool success = TryGetValue(name, time);
LARGE_INTEGER *largeInt = (LARGE_INTEGER*)&time;
if (success)
result = DateTime::FromFileTimeUtc(largeInt->QuadPart);
return success;
}
#pragma endregion
#pragma region Integers
/// <summary>
/// Get an Int8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int8 value associated with the specified property</returns>
virtual int8_t GetInt8(String^ name)
{
return GetValue<int8_t>(name);
}
/// <summary>
/// Get an Int8 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int8 value associated with the specified property or the specified default value</returns>
virtual int8_t GetInt8(String^ name, int8_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an Int8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int8</param>
/// <returns>true if fetching the Int8 succeeded, false otherwise</returns>
virtual bool TryGetInt8(String^ name, [Out] int8_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an UInt8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt8 value associated with the specified property</returns>
virtual uint8_t GetUInt8(String^ name)
{
return GetValue<uint8_t>(name);
}
/// <summary>
/// Get an UInt8 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt8 value associated with the specified property or the specified default value</returns>
virtual uint8_t GetUInt8(String^ name, uint8_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an UInt8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt8</param>
/// <returns>true if fetching the UInt8 succeeded, false otherwise</returns>
virtual bool TryGetUInt8(String^ name, [Out] uint8_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an Int16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int16 value associated with the specified property</returns>
virtual int16_t GetInt16(String^ name)
{
return GetValue<int16_t>(name);
}
/// <summary>
/// Get an Int16 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int16 value associated with the specified property or the specified default value</returns>
virtual int16_t GetInt16(String^ name, int16_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an Int16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int16</param>
/// <returns>true if fetching the Int16 succeeded, false otherwise</returns>
virtual bool TryGetInt16(String^ name, [Out] int16_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an UInt16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt16 value associated with the specified property</returns>
virtual uint16_t GetUInt16(String^ name)
{
return GetValue<uint16_t>(name);
}
/// <summary>
/// Get an UInt16 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt16 value associated with the specified property or the specified default value</returns>
virtual uint16_t GetUInt16(String^ name, uint16_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an UInt16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt16</param>
/// <returns>true if fetching the UInt16 succeeded, false otherwise</returns>
virtual bool TryGetUInt16(String^ name, [Out] uint16_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an Int32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int32 value associated with the specified property</returns>
virtual int32_t GetInt32(String^ name)
{
return GetValue<int32_t>(name);
}
/// <summary>
/// Get an Int32 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int32 value associated with the specified property or the specified default value</returns>
virtual int32_t GetInt32(String^ name, int32_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an Int32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int32</param>
/// <returns>true if fetching the Int32 succeeded, false otherwise</returns>
virtual bool TryGetInt32(String^ name, [Out] int32_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an UInt32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt32 value associated with the specified property</returns>
virtual uint32_t GetUInt32(String^ name)
{
return GetValue<uint32_t>(name);
}
/// <summary>
/// Get an UInt32 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt32 value associated with the specified property or the specified default value</returns>
virtual uint32_t GetUInt32(String^ name, uint32_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an UInt32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt32</param>
/// <returns>true if fetching the UInt32 succeeded, false otherwise</returns>
virtual bool TryGetUInt32(String^ name, [Out] uint32_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an Int64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int64 value associated with the specified property</returns>
virtual int64_t GetInt64(String^ name)
{
return GetValue<int64_t>(name);
}
/// <summary>
/// Get an Int64 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int64 value associated with the specified property or the specified default value</returns>
virtual int64_t GetInt64(String^ name, int64_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an Int64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int64</param>
/// <returns>true if fetching the Int64 succeeded, false otherwise</returns>
virtual bool TryGetInt64(String^ name, [Out] int64_t% result)
{
return TryGetValue(name, result);
}
/// <summary>
/// Get an UInt64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt64 value associated with the specified property</returns>
virtual uint64_t GetUInt64(String^ name)
{
return GetValue<uint64_t>(name);
}
/// <summary>
/// Get an UInt64 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt64 value associated with the specified property or the specified default value</returns>
virtual uint64_t GetUInt64(String^ name, uint64_t defaultValue)
{
return GetValueOrDefault(name, defaultValue);
}
/// <summary>
/// Attempt to get an UInt64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt64</param>
/// <returns>true if fetching the UInt64 succeeded, false otherwise</returns>
virtual bool TryGetUInt64(String^ name, [Out] uint64_t% result)
{
return TryGetValue(name, result);
}
#pragma endregion
/// <summary>
/// Gets an IEnumerable of <see cref="O365::Security::ETW::Property"/>
/// representing the properties available on the EventRecord.
/// </summary>
/// <returns>IEnumerable of Property</returns>
virtual property IEnumerable<Property^>^ Properties
{
IEnumerable<Property^>^ get() { return gcnew PropertyEnumerable(*schema_); }
}
/// <summary>
/// Get a binary field with the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the byte array value associated with the specified property</returns>
virtual array<Byte>^ GetBinary(String^ name)
{
auto data = GetValue<krabs::binary>(name);
return ConvertToByteArray(data);
}
/// <summary>
/// Attempt to get a binary field with the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting byte array</param>
/// <returns>true if fetching the data succeeded, false otherwise</returns>
virtual bool TryGetBinary(String^ name, [Out] array<Byte>^% result)
{
krabs::binary data;
bool success = TryGetValue(name, data);
if (success)
result = ConvertToByteArray(data);
return success;
}
/// <summary>
/// Retrieves the call stack associated with the record, if enabled.
/// </summary>
/// <returns>a list of return addresses</returns>
virtual List<UIntPtr>^ GetStackTrace()
{
auto stackTrace = gcnew List<UIntPtr>();
for (auto& returnAddress : schema_->stack_trace())
{
stackTrace->Add(UIntPtr(returnAddress));
}
return stackTrace;
}
#pragma endregion
private:
template <typename T>
T GetValue(String^ name)
{
std::wstring propName = marshal_as<std::wstring>(name);
try
{
return parser_->parse<T>(propName);
}
catch (const krabs::type_mismatch_assert& ex)
{
// This can only happen in debug builds, we need
// to wrap the C++ exception for C#
auto msg = gcnew String(ex.what());
throw gcnew TypeMismatchAssert(msg);
}
catch (const std::exception& ex)
{
auto msg = gcnew String(ex.what());
throw gcnew ParserException(msg);
}
}
template <typename T>
T GetValueOrDefault(String^ name, T defaultValue)
{
T result;
bool success = TryGetValue(name, result);
if (success) return result;
return defaultValue;
}
template <typename T>
bool TryGetValue(String^ name, T% result)
{
try
{
T value;
std::wstring propName = marshal_as<std::wstring>(name);
bool success = parser_->try_parse(propName, value);
if (success) result = value;
return success;
}
catch (const krabs::type_mismatch_assert& ex)
{
// This can only happen in debug builds, we need
// to wrap the C++ exception for C#
auto msg = gcnew String(ex.what());
throw gcnew TypeMismatchAssert(msg);
}
}
IPAddress^ ConvertToIPAddress(const krabs::ip_address& addr)
{
int size = addr.is_ipv6 ? 16 : 4;
array<Byte>^ bytes = gcnew array<Byte>(size);
Marshal::Copy(IntPtr((void*)&addr), bytes, 0, size);
return gcnew IPAddress(bytes);
}
SocketAddress^ ConvertToSocketAddress(const krabs::socket_address& addr)
{
auto managed = gcnew SocketAddress((Sockets::AddressFamily)addr.sa_stor.ss_family);
BYTE* ptr = (BYTE*)&(addr.sa_stor);
int size = addr.sa_stor.ss_family == AF_INET ? sizeof addr.sa_in : sizeof addr.sa_in6;
for (int ii = 0; ii < size; ii++)
managed[ii] = ptr[ii];
return managed;
}
SecurityIdentifier^ ConvertToSecurityIdentifier(const krabs::sid& addr)
{
auto managed_string = gcnew String(addr.sid_string.c_str());
auto managed = gcnew SecurityIdentifier(managed_string);
return managed;
}
IntPtr^ ConvertToPointer(const krabs::pointer& addr)
{
auto managed = gcnew IntPtr(static_cast<long long>(addr.address));
return managed;
}
String^ ConvertToString(const krabs::counted_string& value)
{
return Marshal::PtrToStringUni(
IntPtr(reinterpret_cast<long long>(value.string())),
(int)value.length());
}
array<Byte>^ ConvertToByteArray(const krabs::binary& data)
{
auto managed = gcnew array<Byte>((int)data.bytes().size());
IntPtr start((void*)&data.bytes()[0]);
if (start == IntPtr::Zero) return nullptr;
Marshal::Copy(start, managed, 0, (int)data.bytes().size());
return managed;
}
};
} } } }
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include "IEventRecordError.hpp"
#include "IEventRecordMetadata.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Item passed to OnError handlers when an error is encountered
/// handling an event on the worker thread.
/// </summary>
public ref struct EventRecordError : public IEventRecordError
{
private:
initonly System::String^ msg_;
initonly IEventRecordMetadata^ record_;
public:
/// <summary>
/// Returns a string representing a message about the
/// error that was encountered in the EventRecord.
/// </summary>
virtual property System::String^ Message {
System::String^ get() {
return msg_;
}
}
/// <summary>
/// Returns an object representing metadata about the
/// record that was being processed when the error was
/// encountered.
/// </summary>
virtual property IEventRecordMetadata^ Record {
IEventRecordMetadata^ get() {
return record_;
}
}
internal:
EventRecordError(
System::String^ message,
IEventRecordMetadata^ record)
: msg_(message)
, record_(record)
{ }
};
} } } }
@@ -0,0 +1,216 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "IEventRecordMetadata.hpp"
#include "Guid.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Concrete implementation representing the metadata about an ETW event record.
/// </summary>
public ref class EventRecordMetadata : public IEventRecordMetadata
{
protected:
const EVENT_RECORD* record_;
const EVENT_HEADER* header_;
internal:
EventRecordMetadata(const EVENT_RECORD& record)
: record_(&record)
, header_(&record.EventHeader) { }
public:
// For container ID's, we are expecting format "00000000-0000-0000-0000-0000000000000",
// 32 hex digits with 4 hyphens, no braces.
static const size_t CONTAINER_ID_DATA_LENGTH_IN_BYTES = 36;
#pragma region EventDescriptor
/// <summary>
/// Retrieves the ID of this event.
/// </summary>
virtual property uint16_t Id
{
uint16_t get() { return header_->EventDescriptor.Id; }
}
/// <summary>
/// Returns the opcode of this event.
/// </summary>
virtual property byte Opcode
{
virtual byte get() { return header_->EventDescriptor.Opcode; }
}
/// <summary>
/// Returns the version of this event.
/// </summary>
virtual property byte Version
{
byte get() { return header_->EventDescriptor.Version; }
}
/// <summary>
/// Returns the level of this event.
/// </summary>
virtual property byte Level
{
byte get() { return header_->EventDescriptor.Level; }
}
#pragma endregion
#pragma region EventHeader
/// <summary>
/// Returns the flags of the event.
/// </summary>
virtual property uint16_t Flags
{
uint16_t get() { return header_->Flags; }
}
/// <summary>
/// Returns the EventProperty of the event.
/// </summary>
virtual property EventHeaderProperty EventProperty
{
EventHeaderProperty get()
{
return (EventHeaderProperty)(header_->EventProperty);
}
}
/// <summary>
/// Retrieves the PID associated with the event.
/// </summary>
virtual property unsigned int ProcessId
{
unsigned int get() { return header_->ProcessId; }
}
/// <summary>
/// Retrieves the Thread ID associated with the event.
/// </summary>
virtual property unsigned int ThreadId
{
unsigned int get() { return header_->ThreadId; }
}
/// <summary>
/// Returns the timestamp associated with this event.
/// </summary>
virtual property DateTime Timestamp
{
DateTime get()
{
return DateTime::FromFileTimeUtc(header_->TimeStamp.QuadPart);
}
}
/// <summary>
/// Returns the Thread ID associated with the event.
/// </summary>
virtual property Guid ProviderId
{
Guid get() { return ConvertGuid(header_->ProviderId); }
}
/// <summary>
/// Returns the Activity ID associated with the event.
/// </summary>
virtual property Guid ActivityId
{
Guid get() { return ConvertGuid(header_->ActivityId); }
}
#pragma endregion
#pragma region EventRecord
/// <summary>
/// Returns the size in bytes of the UserData buffer.
/// </summary>
/// <returns>the size of the EVENT_RECORD.UserData buffer</returns>
virtual property uint16_t UserDataLength
{
uint16_t get() { return record_->UserDataLength; }
}
/// <summary>
/// Returns a pointer to the UserData buffer.
/// </summary>
/// <returns>a pointer to the EVENT_RECORD.UserData buffer</returns>
virtual property IntPtr UserData
{
IntPtr get() { return IntPtr(record_->UserData); }
}
/// <summary>
/// Marshals the event UserData onto the managed heap.
/// </summary>
/// <returns>a byte array representing the marshalled EVENT_RECORD.UserData buffer</returns>
virtual array<uint8_t>^ CopyUserData()
{
auto dest = gcnew array<uint8_t>(UserDataLength);
Marshal::Copy(UserData, dest, 0, UserDataLength);
return dest;
}
#pragma endregion
#pragma region ExtendedData
/// <summary>
/// If the event's extended data contains a Windows container ID (i.e. event came from inside
/// a container using process isolation), retrieve it.
/// Can be expensive, avoid calling more than once per event.
/// </summary>
/// <returns>
/// True if a Guid was present. False if not. If a Guid was present, it will be written into the result
/// parameter. Throws a ContainerIdFormatException if the container ID is present but parsing fails.
/// </returns>
virtual bool TryGetContainerId([Out] System::Guid% result)
{
auto extended_data_count = record_->ExtendedDataCount;
for (USHORT i = 0; i < extended_data_count; i++)
{
auto& extended_data = record_->ExtendedData[i];
if (extended_data.ExtType == EVENT_HEADER_EXT_TYPE_CONTAINER_ID)
{
try
{
// Convert to managed System::Guid for returning to managed code.
result = ConvertGuid(
krabs::guid_parser::parse_guid(
reinterpret_cast<char*>(extended_data.DataPtr),
extended_data.DataSize));
}
catch (const std::runtime_error& err)
{
// Convert to managed exception coming from managed function.
throw gcnew ContainerIdFormatException(gcnew System::String(err.what()));
}
return true;
}
}
// Not found.
result = System::Guid::Empty;
return false;
}
#pragma endregion
};
} } } }
@@ -0,0 +1,81 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// EventTraceProperties represents the performance characteristics
/// for a trace session.
/// </summary>
public ref struct EventTraceProperties
{
uint32_t BufferSize; // buffer size for logging (kbytes)
uint32_t MinimumBuffers; // minimum buffers to preallocate
uint32_t MaximumBuffers; // maximum buffers allowed
uint32_t LogFileMode; // sequential, circular
uint32_t FlushTimer; // buffer flush timer, in seconds
};
/// <summary>
/// LogFileModeFlags enumerates the options for EventTraceProperties.LogFileMode
/// </summary>
public enum class LogFileModeFlags : uint32_t
{
FLAG_EVENT_TRACE_FILE_MODE_NONE = 0x00000000, // Logfile is off
FLAG_EVENT_TRACE_FILE_MODE_SEQUENTIAL = 0x00000001, // Log sequentially
FLAG_EVENT_TRACE_FILE_MODE_CIRCULAR = 0x00000002, // Log in circular manner
FLAG_EVENT_TRACE_FILE_MODE_APPEND = 0x00000004, // Append sequential log
FLAG_EVENT_TRACE_REAL_TIME_MODE = 0x00000100, // Real time mode on
FLAG_EVENT_TRACE_DELAY_OPEN_FILE_MODE = 0x00000200, // Delay opening file
FLAG_EVENT_TRACE_BUFFERING_MODE = 0x00000400, // Buffering mode only
FLAG_EVENT_TRACE_PRIVATE_LOGGER_MODE = 0x00000800, // Process Private Logger
FLAG_EVENT_TRACE_ADD_HEADER_MODE = 0x00001000, // Add a logfile header
FLAG_EVENT_TRACE_USE_GLOBAL_SEQUENCE = 0x00004000, // Use global sequence no.
FLAG_EVENT_TRACE_USE_LOCAL_SEQUENCE = 0x00008000, // Use local sequence no.
FLAG_EVENT_TRACE_RELOG_MODE = 0x00010000, // Relogger
FLAG_EVENT_TRACE_USE_PAGED_MEMORY = 0x01000000, // Use pageable buffers
//
// Logger Mode flags on XP and above
//
FLAG_EVENT_TRACE_FILE_MODE_NEWFILE = 0x00000008, // Auto-switch log file
FLAG_EVENT_TRACE_FILE_MODE_PREALLOCATE = 0x00000020, // Pre-allocate mode
//
// Logger Mode flags on Vista and above
//
FLAG_EVENT_TRACE_NONSTOPPABLE_MODE = 0x00000040, // Session cannot be stopped (Autologger only)
FLAG_EVENT_TRACE_SECURE_MODE = 0x00000080, // Secure session
FLAG_EVENT_TRACE_USE_KBYTES_FOR_SIZE = 0x00002000, // Use KBytes as file size unit
FLAG_EVENT_TRACE_PRIVATE_IN_PROC = 0x00020000, // In process private logger
FLAG_EVENT_TRACE_MODE_RESERVED = 0x00100000, // Reserved bit, used to signal Heap/Critsec tracing
//
// Logger Mode flags on Win7 and above
//
FLAG_EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = 0x10000000, // Use this for low frequency sessions
//
// Logger Mode flags on Win8 and above
//
FLAG_EVENT_TRACE_SYSTEM_LOGGER_MODE = 0x02000000, // Receive events from SystemTraceProvider
FLAG_EVENT_TRACE_ADDTO_TRIAGE_DUMP = 0x80000000, // Add ETW buffers to triage dumps
FLAG_EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN = 0x00400000, // Stop on hybrid shutdown
FLAG_EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN = 0x00800000, // Persist on hybrid shutdown
//
// Logger Mode flags on Blue and above
//
FLAG_EVENT_TRACE_INDEPENDENT_SESSION_MODE = 0x08000000, // Independent logger session
//
// Logger Mode flags on Redstone and above
//
FLAG_EVENT_TRACE_COMPRESSED_MODE = 0x04000000 // Compressed logger session
};
} } } }
@@ -0,0 +1,130 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include <string>
#include "../NativePtr.hpp"
#include "Predicate.hpp"
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace adapt = krabs::predicates::adapters;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Fluent filters for ANSI String properties
/// </summary>
public ref class AnsiString abstract sealed {
public:
/// <summary>
/// Accept event if ANSI string property equals the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value matches the specified string</returns>
static Predicate^ Is(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_equals<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property equals (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value matches (case invariant) the specified string</returns>
static Predicate^ IEquals(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_iequals<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property contains the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value contains the specified string</returns>
static Predicate^ Contains(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_contains<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property contains (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value contains (case invariant) the specified string</returns>
static Predicate^ IContains(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_icontains<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property starts with the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value starts with the specified string</returns>
static Predicate^ StartsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_starts_with<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property starts with (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value starts with (case invariant) the specified string</returns>
static Predicate^ IStartsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_istarts_with<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property ends with the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value ends with the specified string</returns>
static Predicate^ EndsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_ends_with<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
/// <summary>
/// Accept event if ANSI string property ends with (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value ends with (case invariant) the specified string</returns>
static Predicate^ IEndsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_iends_with<adapt::generic_string<char>>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::string>(value)));
}
};
} } } }
@@ -0,0 +1,130 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include <string>
#include "../NativePtr.hpp"
#include "Predicate.hpp"
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace adapt = krabs::predicates::adapters;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Fluent filters for ANSI String properties
/// </summary>
public ref class CountedString abstract sealed {
public:
/// <summary>
/// Accept event if counted string property equals the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value matches the specified string</returns>
static Predicate^ Is(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_equals<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property equals (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value matches (case invariant) the specified string</returns>
static Predicate^ IEquals(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_iequals<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property contains the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value contains the specified string</returns>
static Predicate^ Contains(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_contains<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property contains (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value contains (case invariant) the specified string</returns>
static Predicate^ IContains(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_icontains<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property starts with the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value starts with the specified string</returns>
static Predicate^ StartsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_starts_with<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property starts with (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value starts with (case invariant) the specified string</returns>
static Predicate^ IStartsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_istarts_with<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property ends with the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value ends with the specified string</returns>
static Predicate^ EndsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_ends_with<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if counted string property ends with (case invariant) the specified string
/// </summary>
/// <param name="name">represents the property name</param>
/// <param name="value">represents the value to match on</param>
/// <returns>a predicate that accepts an event if the value ends with (case invariant) the specified string</returns>
static Predicate^ IEndsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_iends_with<adapt::counted_string>(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
};
} } } }
@@ -0,0 +1,213 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "../Conversions.hpp"
#include "../EventRecordError.hpp"
#include "../EventRecord.hpp"
#include "../EventRecordMetadata.hpp"
#include "../Guid.hpp"
#include "../IEventRecord.hpp"
#include "../IEventRecordError.hpp"
#include "../NativePtr.hpp"
#include "Predicate.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Delegate called when a new ETW <see cref="O365::Security::ETW::EventRecord"/> is received.
/// </summary>
public delegate void IEventRecordDelegate(O365::Security::ETW::IEventRecord^ record);
/// <summary>
/// Delegate called on errors when processing an <see cref="O365::Security::ETW::EventRecord"/>.
/// </summary>
public delegate void EventRecordErrorDelegate(O365::Security::ETW::IEventRecordError^ error);
/// <summary>
/// Allows for filtering an event in the native layer before it bubbles
/// up to callbacks.
/// </summary>
public ref class EventFilter {
public:
/// <summary>
/// Constructs an EventFilter with the given Predicate.
/// </summary>
/// <param name="predicate">the predicate to use to filter an event</param>
EventFilter(O365::Security::ETW::Predicate ^predicate);
/// <summary>
/// Constructs an EventFilter with the given event ID.
/// </summary>
/// <param name="eventId">the event ID to filter using provider-based filtering</param>
EventFilter(unsigned short eventId);
/// <summary>
/// Constructs an EventFilter with the given event ID and Predicate.
/// </summary>
/// <param name="eventId">the event ID to filter using provider-based filtering</param>
/// <param name="predicate">the predicate to use to filter an event</param>
EventFilter(unsigned short eventId, O365::Security::ETW::Predicate^ predicate);
/// <summary>
/// Constructs an EventFilter with the given event IDs.
/// </summary>
/// <param name="eventIds">the event IDs to filter using provider-based filtering</param>
EventFilter(List<unsigned short>^ eventIds);
/// <summary>
/// Constructs an EventFilter with the given event IDs and Predicate.
/// </summary>
/// <param name="eventIds">the event IDs to filter using provider-based filtering</param>
/// <param name="predicate">the predicate to use to filter an event</param>
EventFilter(List<unsigned short>^ eventIds, O365::Security::ETW::Predicate^ predicate);
/// <summary>
/// Destructs an EventFilter.
/// </summary>
~EventFilter();
/// <summary>
/// An event that is invoked when an ETW event is fired on this
/// filter and the event meets the given predicate.
/// </summary>
event IEventRecordDelegate^ OnEvent;
/// <summary>
/// An event that is invoked when an ETW event is received
/// but an error occurs handling the record.
/// </summary>
event EventRecordErrorDelegate^ OnError;
internal:
/// <summary>
/// Allows implicit conversion to a krabs::event_filter.
/// </summary>
/// <returns>the native representation of an EventFilter</returns>
operator krabs::event_filter&()
{
return *filter_;
}
void EventNotification(const EVENT_RECORD &, const krabs::trace_context &);
void ErrorNotification(const EVENT_RECORD&, const std::string&);
internal:
delegate void EventReceivedNativeHookDelegate(const EVENT_RECORD &, const krabs::trace_context &);
delegate void ErrorReceivedNativeHookDelegate(const EVENT_RECORD &, const std::string &);
NativePtr<krabs::event_filter> filter_;
EventReceivedNativeHookDelegate^ eventReceivedDelegate_;
ErrorReceivedNativeHookDelegate^ errorReceivedDelegate_;
GCHandle eventReceivedDelegateHookHandle_;
GCHandle errorReceivedDelegateHookHandle_;
GCHandle eventReceivedDelegateHandle_;
GCHandle errorReceivedDelegateHandle_;
void RegisterCallbacks();
};
// Implementation
// ------------------------------------------------------------------------
EventFilter::EventFilter(O365::Security::ETW::Predicate ^pred)
: filter_(pred->to_underlying())
{
RegisterCallbacks();
}
EventFilter::EventFilter(unsigned short eventId)
: filter_(eventId)
{
RegisterCallbacks();
}
EventFilter::EventFilter(unsigned short eventId, O365::Security::ETW::Predicate^ pred)
: filter_(eventId, pred->to_underlying())
{
RegisterCallbacks();
}
EventFilter::EventFilter(List<unsigned short>^ eventIds)
: filter_(to_vector(eventIds))
{
RegisterCallbacks();
}
EventFilter::EventFilter(List<unsigned short>^ eventIds, O365::Security::ETW::Predicate^ pred)
: filter_(to_vector(eventIds), pred->to_underlying())
{
RegisterCallbacks();
}
inline EventFilter::~EventFilter()
{
if (eventReceivedDelegateHandle_.IsAllocated)
{
eventReceivedDelegateHandle_.Free();
}
if (eventReceivedDelegateHookHandle_.IsAllocated)
{
eventReceivedDelegateHookHandle_.Free();
}
if (errorReceivedDelegateHandle_.IsAllocated)
{
errorReceivedDelegateHandle_.Free();
}
if (errorReceivedDelegateHookHandle_.IsAllocated)
{
errorReceivedDelegateHookHandle_.Free();
}
}
inline void EventFilter::RegisterCallbacks()
{
eventReceivedDelegate_ = gcnew EventReceivedNativeHookDelegate(this, &EventFilter::EventNotification);
eventReceivedDelegateHandle_ = GCHandle::Alloc(eventReceivedDelegate_);
auto bridgedEventDelegate = Marshal::GetFunctionPointerForDelegate(eventReceivedDelegate_);
eventReceivedDelegateHookHandle_ = GCHandle::Alloc(bridgedEventDelegate);
filter_->add_on_event_callback((krabs::c_provider_callback)bridgedEventDelegate.ToPointer());
errorReceivedDelegate_ = gcnew ErrorReceivedNativeHookDelegate(this, &EventFilter::ErrorNotification);
errorReceivedDelegateHandle_ = GCHandle::Alloc(errorReceivedDelegate_);
auto bridgedErrorDelegate = Marshal::GetFunctionPointerForDelegate(errorReceivedDelegate_);
errorReceivedDelegateHookHandle_ = GCHandle::Alloc(bridgedErrorDelegate);
filter_->add_on_error_callback((krabs::c_provider_error_callback)bridgedErrorDelegate.ToPointer());
}
inline void EventFilter::EventNotification(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
{
try
{
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
OnEvent(gcnew EventRecord(record, schema, parser));
}
catch (const krabs::could_not_find_schema& ex)
{
ErrorNotification(record, ex.what());
}
}
inline void EventFilter::ErrorNotification(const EVENT_RECORD& record, const std::string& error_message)
{
auto msg = gcnew String(error_message.c_str());
auto metadata = gcnew EventRecordMetadata(record);
OnError(gcnew EventRecordError(msg, metadata));
}
} } } }
@@ -0,0 +1,107 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include <string>
#include "../NativePtr.hpp"
#include "Predicate.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace adpt = krabs::predicates::adapters;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Enables a more convenient mechanism to specify filters in
/// managed C++/C#.
/// </summary>
/// <remarks>
/// The idea here is that chains of complicated filters are built
/// iteratively, using the methods on this class. These chains are passed
/// into the native layer a single time, where they are used to do
/// filtering before they are bubbled up to the managed layer.
/// </remarks>
public ref class Filter {
public:
// Event Properties
// --------------------------------------------------------------------
/// <summary>
/// Used to negate the result of the predicate argument.
/// </summary>
/// <param name="other">the predicate to negate</param>
/// <returns>negated form of the predicate passed in</returns>
static Predicate ^Not(Predicate ^other)
{
return Predicate::make_predicate<KPD::not_filter<krabs::filter_predicate>>(*other->predicate_);
}
/// <summary>
/// Accepts any events.
/// </summary>
/// <returns>a predicate that accepts any event</returns>
static Predicate ^AnyEvent()
{
return Predicate::make_predicate<krabs::predicates::details::any_event>();
}
/// <summary>
/// Used to verify that an event opcode matches the expected value
/// </summary>
/// <param name="opcode">event opcode to verify</param>
/// <returns>predicate that verifies an event's opcode</returns>
static Predicate ^EventOpcodeIs(int opcode)
{
return Predicate::make_predicate<krabs::predicates::opcode_is>(opcode);
}
/// <summary>
/// Used to verify that an event matches the given id.
/// </summary>
/// <param name="id">the event id to match on</param>
/// <returns>a predicate that will match an event with the provided id</returns>
static Predicate ^EventIdIs(int id)
{
return Predicate::make_predicate<krabs::predicates::id_is>(id);
}
/// <summary>
/// Used to verify that an event version is the given version.
/// </summary>
/// <param name="version">the version to match on</param>
/// <returns>a predicate that matches events of the specified version</returns>
static Predicate ^EventVersionIs(int version)
{
return Predicate::make_predicate<krabs::predicates::version_is>(version);
}
/// <summary>
/// Used to verify that an event was emitted by a specific PID.
/// </summary>
/// <param name="processId">the PID to match on</param>
/// <returns>a predicate that matches events of the specified PID</returns>
static Predicate ^ProcessIdIs(int processId)
{
return Predicate::make_predicate<krabs::predicates::process_id_is>(processId);
}
/// <summary>
/// Used to verify that an event was emitted with a specific UInt32 property.
/// </summary>
/// <param name="propertyName">the name of the property to match on</param>
/// <param name="value">the value of the property to match on</param>
/// <returns>a predicate that matches events of the specified UInt32 property</returns>
static Predicate ^IsUInt32(String ^propertyName, UInt32 value)
{
return gcnew Predicate(krabs::predicates::property_is<UInt32>(
msclr::interop::marshal_as<std::wstring>(propertyName),
value));
}
};
} } } }
@@ -0,0 +1,113 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "../Testing/SynthRecord.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
namespace KP = krabs::predicates;
namespace KPD = krabs::predicates::details;
/// <summary>
/// An object representing a condition to match against for use in
/// EventFilter.
/// </summary>
public ref class Predicate {
internal:
template <typename T>
Predicate(const T &t)
: predicate_(t)
{ }
krabs::filter_predicate& to_underlying()
{
return *predicate_;
}
template <typename T, typename... Args>
static Predicate^ make_predicate(Args&&... args)
{
return gcnew Predicate(T(args...));
}
public:
/// <summary>
/// Creates a new <see cref="O365::Security::ETW::Predicate"/> representing
/// the logical and of the current predicate and another predicate.
/// </summary>
/// <param name="other">the predicate to perform the logical and against</param>
/// <returns>the resulting <see cref="O365::Security::ETW::Predicate"/> object</returns>
Predicate^ operator&&(Predicate^ other)
{
return Predicate::make_predicate<KPD::and_filter<krabs::filter_predicate, krabs::filter_predicate>>(*predicate_, *other->predicate_);
}
/// <summary>
/// Creates a new <see cref="O365::Security::ETW::Predicate"/> representing
/// the logical or of the current predicate and another predicate.
/// </summary>
/// <param name="other">the predicate to perform the logical or against</param>
/// <returns>the resulting <see cref="O365::Security::ETW::Predicate"/> object</returns>
Predicate^ operator||(Predicate^ other)
{
return Predicate::make_predicate<KPD::or_filter<krabs::filter_predicate, krabs::filter_predicate>>(*predicate_, *other->predicate_);
}
/// <summary>
/// Creates a new <see cref="O365::Security::ETW::Predicate"/> representing
/// the logical not of the current predicate.
/// </summary>
/// <returns>the resulting negated <see cref="O365::Security::ETW::Predicate"/> object</returns>
Predicate^ operator!()
{
return Predicate::make_predicate<KPD::not_filter<krabs::filter_predicate>>(*predicate_);
}
/// <summary>
/// Creates a new <see cref="O365::Security::ETW::Predicate"/> representing
/// the logical and of the current predicate and another predicate.
/// </summary>
/// <param name="other">the predicate to perform the logical and against</param>
/// <returns>the resulting <see cref="O365::Security::ETW::Predicate"/> object</returns>
Predicate^ And(Predicate^ other)
{
return Predicate::make_predicate<KPD::and_filter<krabs::filter_predicate, krabs::filter_predicate>>(*predicate_, *other->predicate_);
}
/// <summary>
/// Creates a new <see cref="O365::Security::ETW::Predicate"/> representing
/// the logical or of the current predicate and another predicate.
/// </summary>
/// <param name="other">the predicate to perform the logical or against</param>
/// <returns>the resulting <see cref="O365::Security::ETW::Predicate"/> object</returns>
Predicate^ Or(Predicate^ other)
{
return Predicate::make_predicate<KPD::or_filter<krabs::filter_predicate, krabs::filter_predicate>>(*predicate_, *other->predicate_);
}
/// <summary>
/// Used to test a <see cref="O365::Security::ETW::Testing::SynthRecord"/>
/// against a created Predicate.
/// </summary>
/// <param name="record">the SynthRecord to match against</param>
/// <returns>true if the SynthRecord matches the Predicate, false otherwise</returns>
/// <remarks>
/// This is for testing scenarios.
/// </remarks>
bool Test(Testing::SynthRecord^ record)
{
auto& nativeRecord = *(record->record_);
krabs::trace_context trace_context;
return to_underlying()(nativeRecord, trace_context);
}
internal:
NativePtr<krabs::filter_predicate> predicate_;
};
} } } }
@@ -0,0 +1,130 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include <string>
#include "../NativePtr.hpp"
#include "Predicate.hpp"
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace adapt = krabs::predicates::adapters;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Fluent filters for ANSI String properties
/// </summary>
public ref class UnicodeString abstract sealed {
public:
/// <summary>
/// Accept event if unicode string property equals the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property equals the specified value</returns>
static Predicate^ Is(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_equals(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property equals (case invariant) the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property equals (case invariant) the specified value</returns>
static Predicate^ IEquals(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_iequals(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property contains the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property contains the specified value</returns>
static Predicate^ Contains(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_contains(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property contains (case invariant) the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property contains (case invariant) the specified value</returns>
static Predicate^ IContains(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_icontains(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property starts with the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property starts with the specified value</returns>
static Predicate^ StartsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_starts_with(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property starts with (case invariant) the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property starts with (case invariant) the specified value</returns>
static Predicate^ IStartsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_istarts_with(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property ends with the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property ends with the specified value</returns>
static Predicate^ EndsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_ends_with(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
/// <summary>
/// Accept event if unicode string property ends with (case invariant) the specified string
/// </summary>
/// <param name="name">name of the property to match against</param>
/// <param name="value">the value to match against</param>
/// <returns>a predicate representing that the named property ends with (case invariant) the specified value</returns>
static Predicate^ IEndsWith(String^ name, String^ value)
{
return gcnew Predicate(krabs::predicates::property_iends_with(
msclr::interop::marshal_as<std::wstring>(name),
msclr::interop::marshal_as<std::wstring>(value)));
}
};
} } } }
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Converts a native GUID to a System::Guid
/// </summary>
inline System::Guid ConvertGuid(GUID guid)
{
return System::Guid(
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
}
/// <summary>
/// Converts a System::Guid to a native GUID
/// </summary>
inline GUID ConvertGuid(System::Guid guid)
{
array<System::Byte>^ bytes = guid.ToByteArray();
pin_ptr<System::Byte> data = &(bytes[0]);
return *((GUID*)data);
}
} } } }
@@ -0,0 +1,413 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include "Property.hpp"
#include "IEventRecordMetadata.hpp"
using namespace System;
using namespace System::Net;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Interface for handling records in C#. Abstracts
/// using the krabs API to make using krabs more efficient
/// and to improve testability of code that uses lobsters.
/// </summary>
public interface class IEventRecord : IEventRecordMetadata
{
public:
// Schema Methods
/// <summary>
/// Returns the name of the event.
/// </summary>
property String^ Name { String^ get(); }
/// <summary>
/// Retrieves the opcode_name of the event.
/// </summary>
property String^ OpcodeName { String^ get(); }
/// <summary>
/// Retrieves the task_name of the event.
/// </summary>
property String^ TaskName { String^ get(); }
/// <summary>
/// Returns the name of the provider that fires this event.
/// </summary>
property String^ ProviderName { String^ get(); }
// Parser Methods
/// <summary>
/// Get a unicode string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the unicode string value associated with the specified property</returns>
String^ GetUnicodeString(String^ name);
/// <summary>
/// Get a unicode string from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the unicode string value associated with the specified property or the specified default value</returns>
String^ GetUnicodeString(String^ name, String^ defaultValue);
/// <summary>
/// Attempt to get a unicode string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting string</param>
/// <returns>true if fetching the string succeeded, false otherwise</returns>
bool TryGetUnicodeString(String^ name, [Out] String^% result);
/// <summary>
/// Get a ANSI string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the ANSI string value associated with the specified property</returns>
String^ GetAnsiString(String^ name);
/// <summary>
/// Get a ANSI string from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the ANSI string value associated with the specified property or the specified default value</returns>
String^ GetAnsiString(String^ name, String^ defaultValue);
/// <summary>
/// Attempt to get a ANSI string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting string</param>
/// <returns>true if fetching the string succeeded, false otherwise</returns>
bool TryGetAnsiString(String^ name, [Out] String^% result);
/// <summary>
/// Get a counted string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the counted string value associated with the specified property</returns>
String^ GetCountedString(String^ name);
/// <summary>
/// Get a counted string from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the counted string value associated with the specified property or the specified default value</returns>
String^ GetCountedString(String^ name, String^ defaultValue);
/// <summary>
/// Attempt to get a counted string from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting string</param>
/// <returns>true if fetching the string succeeded, false otherwise</returns>
bool TryGetCountedString(String^ name, [Out] String^% result);
/// <summary>
/// Get an IPAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the IPAddress value associated with the specified property</returns>
IPAddress^ GetIPAddress(String^ name);
/// <summary>
/// Get an IPAddress from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the IPAddress value associated with the specified property or the specified default value</returns>
IPAddress^ GetIPAddress(String^ name, IPAddress^ defaultValue);
/// <summary>
/// Attempt to get an IPAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting IPAddress</param>
/// <returns>true if fetching the IPAddress succeeded, false otherwise</returns>
bool TryGetIPAddress(String^ name, [Out] IPAddress^% result);
/// <summary>
/// Get an SocketAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the SocketAddress value associated with the specified property</returns>
SocketAddress^ GetSocketAddress(String^ name);
/// <summary>
/// Get an SocketAddress from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the SocketAddress value associated with the specified property or the specified default value</returns>
SocketAddress^ GetSocketAddress(String^ name, SocketAddress^ defaultValue);
/// <summary>
/// Attempt to get an SocketAddress from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting SocketAddress</param>
/// <returns>true if fetching the SocketAddress succeeded, false otherwise</returns>
bool TryGetSocketAddress(String^ name, [Out] SocketAddress^% result);
/// <summary>
/// Get a DateTime from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the DateTime value associated with the specified property</returns>
DateTime^ GetDateTime(String^ name);
/// <summary>
/// Get an DateTime from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the DateTime value associated with the specified property or the specified default value</returns>
DateTime^ GetDateTime(String^ name, DateTime^ defaultValue);
/// <summary>
/// Attempt to get an DateTime from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting DateTime</param>
/// <returns>true if fetching the DateTime succeeded, false otherwise</returns>
bool TryGetDateTime(String^ name, [Out] DateTime^% result);
// Integers
/// <summary>
/// Get an Int8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int8 value associated with the specified property</returns>
int8_t GetInt8(String^ name);
/// <summary>
/// Get an Int8 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int8 value associated with the specified property or the specified default value</returns>
int8_t GetInt8(String^ name, int8_t defaultValue);
/// <summary>
/// Attempt to get an Int8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int8</param>
/// <returns>true if fetching the Int8 succeeded, false otherwise</returns>
bool TryGetInt8(String^ name, [Out] int8_t% result);
/// <summary>
/// Get an UInt8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt8 value associated with the specified property</returns>
uint8_t GetUInt8(String^ name);
/// <summary>
/// Get an UInt8 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt8 value associated with the specified property or the specified default value</returns>
uint8_t GetUInt8(String^ name, uint8_t defaultValue);
/// <summary>
/// Attempt to get an UInt8 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt8</param>
/// <returns>true if fetching the UInt8 succeeded, false otherwise</returns>
bool TryGetUInt8(String^ name, [Out] uint8_t% result);
/// <summary>
/// Get an Int16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int16 value associated with the specified property</returns>
int16_t GetInt16(String^ name);
/// <summary>
/// Get an Int16 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int16 value associated with the specified property or the specified default value</returns>
int16_t GetInt16(String^ name, int16_t defaultValue);
/// <summary>
/// Attempt to get an Int16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int16</param>
/// <returns>true if fetching the Int16 succeeded, false otherwise</returns>
bool TryGetInt16(String^ name, [Out] int16_t% result);
/// <summary>
/// Get an UInt16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt16 value associated with the specified property</returns>
uint16_t GetUInt16(String^ name);
/// <summary>
/// Get an UInt16 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt16 value associated with the specified property or the specified default value</returns>
uint16_t GetUInt16(String^ name, uint16_t defaultValue);
/// <summary>
/// Attempt to get an UInt16 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt16</param>
/// <returns>true if fetching the UInt16 succeeded, false otherwise</returns>
bool TryGetUInt16(String^ name, [Out] uint16_t% result);
/// <summary>
/// Get an Int32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int32 value associated with the specified property</returns>
int32_t GetInt32(String^ name);
/// <summary>
/// Get an Int32 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int32 value associated with the specified property or the specified default value</returns>
int32_t GetInt32(String^ name, int32_t defaultValue);
/// <summary>
/// Attempt to get an Int32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int32</param>
/// <returns>true if fetching the Int32 succeeded, false otherwise</returns>
bool TryGetInt32(String^ name, [Out] int32_t% result);
/// <summary>
/// Get an UInt32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt32 value associated with the specified property</returns>
uint32_t GetUInt32(String^ name);
/// <summary>
/// Get an UInt32 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt32 value associated with the specified property or the specified default value</returns>
uint32_t GetUInt32(String^ name, uint32_t defaultValue);
/// <summary>
/// Attempt to get an UInt32 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt32</param>
/// <returns>true if fetching the UInt32 succeeded, false otherwise</returns>
bool TryGetUInt32(String^ name, [Out] uint32_t% result);
/// <summary>
/// Get an Int64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the Int64 value associated with the specified property</returns>
int64_t GetInt64(String^ name);
/// <summary>
/// Get an Int64 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the Int64 value associated with the specified property or the specified default value</returns>
int64_t GetInt64(String^ name, int64_t defaultValue);
/// <summary>
/// Attempt to get an Int64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting Int64</param>
/// <returns>true if fetching the Int64 succeeded, false otherwise</returns>
bool TryGetInt64(String^ name, [Out] int64_t% result);
/// <summary>
/// Get an UInt64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the UInt64 value associated with the specified property</returns>
uint64_t GetUInt64(String^ name);
/// <summary>
/// Get an UInt64 from the specified property name or returns
/// the specified default value.
/// </summary>
/// <param name="name">property name</param>
/// <param name="defaultValue">the default value to return if the property lookup fails</param>
/// <returns>the UInt64 value associated with the specified property or the specified default value</returns>
uint64_t GetUInt64(String^ name, uint64_t defaultValue);
/// <summary>
/// Attempt to get an UInt64 from the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting UInt64</param>
/// <returns>true if fetching the UInt64 succeeded, false otherwise</returns>
bool TryGetUInt64(String^ name, [Out] uint64_t% result);
/// <summary>
/// Gets an IEnumerable of <see cref="O365::Security::ETW::Property"/>
/// representing the properties available on the EventRecord.
/// </summary>
/// <returns>IEnumerable of Property</returns>
property IEnumerable<Property^>^ Properties { IEnumerable<Property^>^ get(); }
/// <summary>
/// Get a binary field with the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <returns>the byte array value associated with the specified property</returns>
array<Byte>^ GetBinary(String^ name);
/// <summary>
/// Attempt to get a binary field with the specified property name.
/// </summary>
/// <param name="name">property name</param>
/// <param name="result">the resulting byte array</param>
/// <returns>true if fetching the data succeeded, false otherwise</returns>
bool TryGetBinary(String^ name, [Out] array<Byte>^% result);
/// <summary>
/// Retrieves the call stack associated with the record, if enabled.
/// </summary>
/// <returns>a list of return addresses</returns>
List<UIntPtr>^ GetStackTrace();
};
} } } }
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include "IEventRecordMetadata.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Item passed to OnError handlers when an error is encountered
/// handling an event on the worker thread.
/// </summary>
public interface struct IEventRecordError
{
/// <summary>
/// Returns a string representing a message about the
/// error that was encountered in the EventRecord.
/// </summary>
property System::String^ Message { System::String^ get(); }
/// <summary>
/// Returns an object representing metadata about the
/// record that was being processed when the error was
/// encountered.
/// </summary>
property IEventRecordMetadata^ Record { IEventRecordMetadata^ get(); }
};
} } } }
@@ -0,0 +1,133 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// From the EVENT_HEADER.EventProperty defines:
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363759(v=vs.85).aspx
/// </summary>
public enum class EventHeaderProperty : uint16_t
{
XML = 0x0001,
FORWARDED_XML = 0x0002,
LEGACY_EVENTLOG = 0x0004
};
/// <summary>
/// Interface for handling records without access to
/// the event schema. This can be useful for processing
/// events that do not have a registered schema.
/// </summary>
public interface class IEventRecordMetadata
{
#pragma region EventDescriptor
/// <summary>
/// Returns the ID of this event.
/// </summary>
property uint16_t Id { uint16_t get(); }
/// <summary>
/// Returns the opcode of this event.
/// </summary>
property uint8_t Opcode { uint8_t get(); }
/// <summary>
/// Returns the version of this event.
/// </summary>
property uint8_t Version { uint8_t get(); }
/// <summary>
/// Returns the level of this event.
/// </summary>
property uint8_t Level { uint8_t get(); }
#pragma endregion
#pragma region EventHeader
/// <summary>
/// Returns the flags of the event.
/// </summary>
property uint16_t Flags { uint16_t get(); }
/// <summary>
/// Returns the EventProperty of the event.
/// </summary>
property EventHeaderProperty EventProperty { EventHeaderProperty get(); }
/// <summary>
/// Returns the PID associated with the event.
/// </summary>
property unsigned int ProcessId { unsigned int get(); }
/// <summary>
/// Returns the Thread ID associated with the event.
/// </summary>
property unsigned int ThreadId { unsigned int get(); }
/// <summary>
/// Returns the timestamp associated with this event.
/// </summary>
property DateTime Timestamp { DateTime get(); }
/// <summary>
/// Returns the Thread ID associated with the event.
/// </summary>
property Guid ProviderId { Guid get(); }
/// <summary>
/// Returns the Activity ID associated with this event.
/// </summary>
property Guid ActivityId { Guid get(); }
#pragma endregion
#pragma region EventRecord
/// <summary>
/// Returns the size in bytes of the UserData buffer.
/// </summary>
/// <returns>the size of the EVENT_RECORD.UserData buffer</returns>
property uint16_t UserDataLength { uint16_t get(); }
/// <summary>
/// Returns a pointer to the UserData buffer.
/// </summary>
/// <returns>a pointer to the EVENT_RECORD.UserData buffer</returns>
property IntPtr UserData { IntPtr get(); }
/// <summary>
/// Marshals the event UserData onto the managed heap.
/// This is expensive. Use the parse methods unless your
/// event doesn't have a schema.
/// </summary>
/// <returns>a byte array representing the marshalled EVENT_RECORD.UserData buffer</returns>
array<uint8_t>^ CopyUserData();
#pragma endregion
#pragma region ExtendedData
/// <summary>
/// If the event's extended data contains a Windows container ID (i.e. event came from inside
/// a container using process isolation), retrieve it.
/// Can be expensive, avoid calling more than once per event.
/// </summary>
/// <returns>
/// True if a Guid was present. False if not. If a Guid was present, it will be written into the result
/// parameter. Throws a ContainerIdFormatException if the container ID is present but parsing fails.
/// </returns>
bool TryGetContainerId([Out] System::Guid% result);
#pragma endregion
};
} } } }
@@ -0,0 +1,75 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include "EventTraceProperties.hpp"
#include "KernelProvider.hpp"
#include "Provider.hpp"
#include "RawProvider.hpp"
#include "TraceStats.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Represents a instance of an ETW trace session.
/// </summary>
public interface class ITrace
{
public:
/// <summary>
/// Sets the trace properties for a session.
/// Must be called before Open()/Start().
/// </summary>
void SetTraceProperties(EventTraceProperties^ properties);
/// <summary>
/// Starts listening for events from the enabled providers.
/// </summary>
void Start();
/// <summary>
/// Stops listening for events.
/// </summary>
void Stop();
/// <summary>
/// Get stats about events handled by this trace.
/// </summary>
/// <returns>a <see cref="O365::Security::ETW::TraceStats"/> object representing the stats of the current trace</returns>
TraceStats QueryStats();
};
/// <summary>
/// User ETW trace specific interface of <see cref="O365::Security::ETW::ITrace"/>
/// </summary>
public interface class IUserTrace : public ITrace
{
public:
/// <summary>
/// Enables a provider for the given user trace.
/// </summary>
/// <param name="provider">The <see cref="O365::Security::ETW::Provider"/> to enable.</param>
void Enable(Provider^ provider);
/// <summary>
/// Enables a raw provider for the given user trace.
/// </summary>
/// <param name="provider">The <see cref="O365::Security::ETW::RawProvider"/> to enable.</param>
void Enable(RawProvider^ provider);
};
/// <summary>
/// Kernel ETW trace specific interface of <see cref="O365::Security::ETW::ITrace"/>
/// </summary>
public interface class IKernelTrace : public ITrace
{
public:
/// <summary>
/// Enables a provider for the given trace.
/// </summary>
/// <param name="provider">The <see cref="O365::Security::ETW::KernelProvider"/> to enable.</param>
void Enable(KernelProvider^ provider);
};
} } } }
@@ -0,0 +1,195 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs/kernel_providers.hpp>
namespace Microsoft { namespace O365 { namespace Security { namespace ETW { namespace Kernel {
#define CREATE_CONVENIENCE_KERNEL_PROVIDER(__name__, __value__, __guid__) \
public ref class __name__ : public KernelProvider { \
public: \
__name__() \
: KernelProvider(__value__, __guid__) \
{} \
};
#define CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK(__name__, __guid__, __mask__) \
public ref class __name__ : public KernelProvider { \
public: \
__name__() \
: KernelProvider(__guid__, __mask__) \
{} \
};
/// <summary>Converts a GUID to a Guid</summary>
Guid FromGuid(const GUID &guid)
{
return Guid(guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
}
/// <summary>A provider that enables ALPC events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
AlpcProvider,
EVENT_TRACE_FLAG_ALPC,
FromGuid(krabs::guids::alpc));
/// <summary>A provider that enables context switch events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ContextSwitchProvider,
EVENT_TRACE_FLAG_CSWITCH,
FromGuid(krabs::guids::thread));
/// <summary>A provider that enables debug print events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
DebugPrintProvider,
EVENT_TRACE_FLAG_DBGPRINT,
FromGuid(krabs::guids::debug));
/// <summary>A provider that enables file I/O name events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
DiskFileIoProvider,
EVENT_TRACE_FLAG_DISK_FILE_IO,
FromGuid(krabs::guids::file_io));
/// <summary>A provider that enables disk I/O completion events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
DiskIoProvider,
EVENT_TRACE_FLAG_DISK_IO,
FromGuid(krabs::guids::disk_io));
/// <summary>A provider that enables beginning of disk I/O events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
DiskInitIoProvider,
EVENT_TRACE_FLAG_DISK_IO_INIT,
FromGuid(krabs::guids::disk_io));
/// <summary>A provider that enables file I/O completion events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
FileIoProvider,
EVENT_TRACE_FLAG_FILE_IO,
FromGuid(krabs::guids::file_io));
/// <summary>A provider that enables file I/O events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
FileInitIoProvider,
EVENT_TRACE_FLAG_FILE_IO_INIT,
FromGuid(krabs::guids::file_io));
/// <summary>A provider that enables thread dispatch events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ThreadDispatchProvider,
EVENT_TRACE_FLAG_DISPATCHER,
FromGuid(krabs::guids::thread));
/// <summary>A provider that enables device deferred procedure call events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
DpcProvider,
EVENT_TRACE_FLAG_DPC,
FromGuid(krabs::guids::perf_info));
/// <summary>A provider that enables driver events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
DriverProvider,
EVENT_TRACE_FLAG_DRIVER,
FromGuid(krabs::guids::disk_io));
/// <summary>A provider that enables image load events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ImageLoadProvider,
EVENT_TRACE_FLAG_IMAGE_LOAD,
FromGuid(krabs::guids::image_load));
/// <summary>A provider that enables interrupt events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
InterruptProvider,
EVENT_TRACE_FLAG_INTERRUPT,
FromGuid(krabs::guids::perf_info));
/// <summary>A provider that enables memory hard fault events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
MemoryHardFaultProvider,
EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS,
FromGuid(krabs::guids::page_fault));
/// <summary>A provider that enables memory page fault events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
MemoryPageFaultProvider,
EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS,
FromGuid(krabs::guids::page_fault));
/// <summary>A provider that enables network tcp/ip events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
NetworkTcpipProvider,
EVENT_TRACE_FLAG_NETWORK_TCPIP,
FromGuid(krabs::guids::tcp_ip));
/// <summary>A provider that enables process events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ProcessProvider,
EVENT_TRACE_FLAG_PROCESS,
FromGuid(krabs::guids::process));
/// <summary>A provider that enables process counter events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ProcessCounterProvider,
EVENT_TRACE_FLAG_PROCESS_COUNTERS,
FromGuid(krabs::guids::process));
/// <summary>A provider that enables profiling events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ProfileProvider,
EVENT_TRACE_FLAG_PROFILE,
FromGuid(krabs::guids::perf_info));
/// <summary>A provider that enables registry events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
RegistryProvider,
EVENT_TRACE_FLAG_REGISTRY,
FromGuid(krabs::guids::registry));
/// <summary>A provider that enables split I/O events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
SplitIoProvider,
EVENT_TRACE_FLAG_SPLIT_IO,
FromGuid(krabs::guids::split_io));
/// <summary>A provider that enables system call events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
SystemCallProvider,
EVENT_TRACE_FLAG_SYSTEMCALL,
FromGuid(krabs::guids::system_trace));
/// <summary>A provider that enables thread start and stop events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
ThreadProvider,
EVENT_TRACE_FLAG_THREAD,
FromGuid(krabs::guids::thread));
/// <summary>A provider that enables file map and unmap (excluding images) events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
VaMapProvider,
EVENT_TRACE_FLAG_VAMAP,
FromGuid(krabs::guids::file_io));
/// <summary>A provider that enables VirtualAlloc and VirtualFree events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER(
VirtualAllocProvider,
EVENT_TRACE_FLAG_VIRTUAL_ALLOC,
FromGuid(krabs::guids::page_fault));
/// <summary>A provider that enables Object Manager events.</summary>
CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK(
ObjectManagerProvider,
FromGuid(krabs::guids::ob_trace),
PERF_OB_HANDLE);
#undef CREATE_CONVENIENCE_KERNEL_PROVIDER
#undef CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK
} } } } }
@@ -0,0 +1,161 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include <krabs/perfinfo_groupmask.hpp>
#include "EventRecord.hpp"
#include "EventRecordMetadata.hpp"
#include "Guid.hpp"
#include "NativePtr.hpp"
#include "Filtering/EventFilter.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Represents a kernel trace provider and its configuration.
/// </summary>
public ref class KernelProvider {
public:
/// <summary>
/// Constructs a KernelProvider that is identified by its GUID.
/// </summary>
/// <param name="flags">the trace flags to set</param>
/// <param name="id">the guid of the kernel trace</param>
/// <remarks>
/// More information about trace flags can be found on MSDN:
/// <see href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa363784(v=vs.85).aspx"/>
/// </remarks>
KernelProvider(unsigned int flags, System::Guid id);
/// <summary>
/// Constructs a KernelProvider that is identified by its GUID.
/// </summary>
/// <param name="id">the guid of the kernel trace</param>
/// <param name="mask">the group mask to set</param>
/// <remarks>
/// Only supported on Windows 8 and newer.
/// More information about group masks can be found here:
/// <see href="https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/etw/tracesup/perfinfo_groupmask.htm"/>
/// </remarks>
KernelProvider(System::Guid id, PERFINFO_MASK mask);
/// <summary>
/// Destructs a KernelProvider.
/// </summary>
~KernelProvider();
/// <summary>
/// Adds a new EventFilter to the provider.
/// </summary>
/// <param name="filter">
/// the <see cref="O365::Security::ETW::EventFilter"/> to
/// filter incoming events with
/// </param>
void AddFilter(O365::Security::ETW::EventFilter ^filter) {
provider_->add_filter(filter);
}
/// <summary>
/// An event that is invoked when an ETW event is fired in this
/// provider.
/// </summary>
event IEventRecordDelegate^ OnEvent;
/// <summary>
/// An event that is invoked when an ETW event is received
/// but an error occurs handling the record.
/// </summary>
event EventRecordErrorDelegate^ OnError;
/// <summary>
/// Retrieves the GUID associated with this provider
/// </summary>
/// <returns>returns the GUID associated with this provider object</returns>
property Guid Id {
Guid get() {
GUID guid = provider_->id();
return Guid(guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
}
}
internal:
void EventNotification(const EVENT_RECORD &, const krabs::trace_context &);
internal:
delegate void NativeHookDelegate(const EVENT_RECORD &, const krabs::trace_context &);
NativeHookDelegate ^del_;
NativePtr<krabs::kernel_provider> provider_;
GCHandle delegateHookHandle_;
GCHandle delegateHandle_;
};
// Implementation
// ------------------------------------------------------------------------
inline KernelProvider::KernelProvider(unsigned int flags, System::Guid id)
: provider_(flags, ConvertGuid(id))
{
del_ = gcnew NativeHookDelegate(this, &KernelProvider::EventNotification);
delegateHandle_ = GCHandle::Alloc(del_);
auto bridged = Marshal::GetFunctionPointerForDelegate(del_);
delegateHookHandle_ = GCHandle::Alloc(bridged);
provider_->add_on_event_callback((krabs::c_provider_callback)bridged.ToPointer());
}
inline KernelProvider::KernelProvider(System::Guid id, PERFINFO_MASK mask)
: provider_(ConvertGuid(id), mask)
{
del_ = gcnew NativeHookDelegate(this, &KernelProvider::EventNotification);
delegateHandle_ = GCHandle::Alloc(del_);
auto bridged = Marshal::GetFunctionPointerForDelegate(del_);
delegateHookHandle_ = GCHandle::Alloc(bridged);
provider_->add_on_event_callback((krabs::c_provider_callback)bridged.ToPointer());
}
inline KernelProvider::~KernelProvider()
{
if (delegateHandle_.IsAllocated)
{
delegateHandle_.Free();
}
if (delegateHookHandle_.IsAllocated)
{
delegateHookHandle_.Free();
}
}
inline void KernelProvider::EventNotification(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
{
try
{
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
OnEvent(gcnew EventRecord(record, schema, parser));
}
catch (const krabs::could_not_find_schema& ex)
{
auto msg = gcnew String(ex.what());
auto metadata = gcnew EventRecordMetadata(record);
OnError(gcnew EventRecordError(msg, metadata));
}
}
} } } }
@@ -0,0 +1,257 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
#include <krabs.hpp>
#include "ITrace.hpp"
#include "NativePtr.hpp"
#include "Provider.hpp"
#include "KernelProvider.hpp"
#include "Errors.hpp"
#include "TraceStats.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Represents an owned user trace.
/// </summary>
public ref class KernelTrace : public IKernelTrace, public IDisposable {
public:
/// <summary>
/// Constructs a kernel trace session with a generated name (or the
/// required kernel trace name on pre-Win8 machines)
/// </summary>
/// <example>
/// KernelTrace trace = new KernelTrace();
/// </example>
KernelTrace();
/// <summary>
/// Stops the trace when disposed.
/// </summary>
~KernelTrace();
/// <summary>
/// Constructs a named kernel trace session, where the name can be
/// any arbitrary, unique string. On pre-Win8 machines, the trace name
/// will be the required kernel trace name and not the given one.
/// </summary>
/// <param name="name">the name to use for the trace</param>
/// <example>
/// KernelTrace trace = new KernelTrace("Purdy kitty");
/// </example>
KernelTrace(String^ name);
/// <summary>
/// Enables a provider for the given trace.
/// </summary>
/// <param name="provider">
/// the <see cref="O365::Security::ETW::KernelProvider"/> to
/// register with the current trace object
/// </param>
/// <example>
/// KernelTrace trace = new KernelTrace();
/// KernelProvider provider = new Kernel.NetworkTcpipProvider()
/// trace.Enable(provider);
/// </example>
virtual void Enable(O365::Security::ETW::KernelProvider ^provider);
/// <summary>
/// Sets the trace properties for a session.
/// Must be called before Open()/Start().
/// See https://docs.microsoft.com/en-us/windows/win32/etw/event-trace-properties
/// for important details and restrictions.
///
/// Configurable properties are ->
/// - BufferSize. In KB. The maximum buffer size is 1024 KB.
/// - MinimumBuffers. Minimum number of buffers is two per processor* .
/// - MaximumBuffers.
/// - FlushTimer. How often, in seconds, the trace buffers are forcibly flushed.
/// - LogFileMode. EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING simulates a *single* sequential processor.
/// </summary>
/// <param name="properties">the <see cref="O365::Security::ETW::EventTraceProperties"/> to set on the trace</param>
/// <example>
/// var trace = new KernelTrace();
/// var properties = new EventTraceProperties
/// {
/// BufferSize = 256,
/// LogFileMode = (uint)LogFileModeFlags.FLAG_EVENT_TRACE_REAL_TIME_MODE
/// };
/// trace.SetTraceProperties(properties);
/// // ...
/// trace.Start();
/// </example>
virtual void SetTraceProperties(EventTraceProperties^ properties);
/// <summary>
/// Opens a trace session.
/// </summary>
/// <example>
/// var trace = new KernelTrace();
/// // ...
/// trace.Open();
/// // ...
/// trace.Start();
/// </example>
/// <remarks>
/// This is an optional call before Start() if you need the trace
/// registered with the ETW subsystem before you start processing events.
/// </remarks>
virtual void Open();
/// <summary>
/// Starts listening for events from the enabled providers.
/// </summary>
/// <example>
/// KernelTrace trace = new KernelTrace();
/// // ...
/// trace.Start();
/// </example>
/// <remarks>
/// This function is a blocking call. Whichever thread calls Start() is effectively
/// donating itself to the ETW subsystem as the processing thread for events.
///
/// A side effect of this is that it is expected that Stop() will be called on
/// a different thread.
/// </remarks>
virtual void Start();
/// <summary>
/// Stops listening for events.
/// </summary>
/// <example>
/// KernelTrace trace = new KernelTrace();
/// // ...
/// trace.Start();
/// trace.Stop();
/// </example>
virtual void Stop();
/// <summary>
/// Get stats about events handled by this trace
/// </summary>
/// <returns>a <see cref="O365::Security::ETW::TraceStats"/> object representing the stats of the current trace</returns>
virtual TraceStats QueryStats();
/// <summary>
/// Adds a function to call when an event is fired which has no corresponding provider.
/// </summary>
/// <param name="callback">the function to call into</param>
/// <example>
/// KernelTrace trace = new KernelTrace();
/// trace.SetDefaultEventCallback((record) => { ... });
/// </example>
virtual void SetDefaultEventCallback(IEventRecordDelegate^ callback);
internal:
bool disposed_ = false;
O365::Security::ETW::NativePtr<krabs::kernel_trace> trace_;
IEventRecordDelegate^ callback_;
void EventNotification(const EVENT_RECORD&, const krabs::trace_context&);
delegate void NativeHookDelegate(const EVENT_RECORD&, const krabs::trace_context&);
NativeHookDelegate^ del_;
GCHandle delegateHandle_;
GCHandle delegateHookHandle_;
};
// Implementation
// ------------------------------------------------------------------------
inline KernelTrace::KernelTrace()
: trace_(new krabs::kernel_trace())
{ }
inline KernelTrace::~KernelTrace()
{
if (disposed_) {
return;
}
Stop();
disposed_ = true;
if (delegateHandle_.IsAllocated)
{
delegateHandle_.Free();
}
if (delegateHookHandle_.IsAllocated)
{
delegateHookHandle_.Free();
}
}
inline KernelTrace::KernelTrace(String ^name)
: trace_()
{
std::wstring nativeName = msclr::interop::marshal_as<std::wstring>(name);
trace_.Swap(O365::Security::ETW::NativePtr<krabs::kernel_trace>(nativeName));
}
inline void KernelTrace::Enable(O365::Security::ETW::KernelProvider ^provider)
{
return trace_->enable(*provider->provider_);
}
inline void KernelTrace::SetTraceProperties(EventTraceProperties^ properties)
{
EVENT_TRACE_PROPERTIES _properties;
_properties.BufferSize = properties->BufferSize;
_properties.MinimumBuffers = properties->MinimumBuffers;
_properties.MaximumBuffers = properties->MaximumBuffers;
_properties.LogFileMode = properties->LogFileMode;
_properties.FlushTimer = properties->FlushTimer;
ExecuteAndConvertExceptions(return trace_->set_trace_properties(&_properties));
}
inline void KernelTrace::Open()
{
ExecuteAndConvertExceptions((void)trace_->open());
}
inline void KernelTrace::Start()
{
ExecuteAndConvertExceptions(return trace_->start());
}
inline void KernelTrace::Stop()
{
ExecuteAndConvertExceptions(return trace_->stop());
}
inline TraceStats KernelTrace::QueryStats()
{
ExecuteAndConvertExceptions(return TraceStats(trace_->query_stats()));
}
inline void KernelTrace::SetDefaultEventCallback(IEventRecordDelegate^ callback)
{
callback_ = callback;
if (!delegateHandle_.IsAllocated) {
del_ = gcnew NativeHookDelegate(this, &KernelTrace::EventNotification);
delegateHandle_ = GCHandle::Alloc(del_);
auto bridged = Marshal::GetFunctionPointerForDelegate(del_);
delegateHookHandle_ = GCHandle::Alloc(bridged);
ExecuteAndConvertExceptions((void)trace_->set_default_event_callback((krabs::c_provider_callback)bridged.ToPointer()));
}
}
inline void KernelTrace::EventNotification(const EVENT_RECORD& record, const krabs::trace_context& trace_context)
{
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
callback_(gcnew EventRecord(record, schema, parser));
}
} } } }
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- The configuration and platform will be used to determine which assemblies to include from solution and
project documentation sources -->
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2cc5580e-604f-4ff6-b8d4-a066246ac3f2}</ProjectGuid>
<SHFBSchemaVersion>2015.6.5.0</SHFBSchemaVersion>
<!-- AssemblyName, Name, and RootNamespace are not used by SHFB but Visual Studio adds them anyway -->
<AssemblyName>Documentation</AssemblyName>
<RootNamespace>Documentation</RootNamespace>
<Name>Documentation</Name>
<!-- SHFB properties -->
<FrameworkVersion>.NET Framework 4.5</FrameworkVersion>
<OutputPath>..\docs\</OutputPath>
<HtmlHelpName>Microsoft.O365.Security.Native.ETW</HtmlHelpName>
<Language>en-US</Language>
<SaveComponentCacheCapacity>100</SaveComponentCacheCapacity>
<BuildAssemblerVerbosity>OnlyWarningsAndErrors</BuildAssemblerVerbosity>
<HelpFileFormat>HtmlHelp1</HelpFileFormat>
<IndentHtml>False</IndentHtml>
<KeepLogFile>True</KeepLogFile>
<DisableCodeBlockComponent>False</DisableCodeBlockComponent>
<CleanIntermediates>True</CleanIntermediates>
<HelpFileVersion>1.0.0.0</HelpFileVersion>
<MaximumGroupParts>2</MaximumGroupParts>
<NamespaceGrouping>False</NamespaceGrouping>
<SyntaxFilters>Standard</SyntaxFilters>
<SdkLinkTarget>Blank</SdkLinkTarget>
<RootNamespaceContainer>False</RootNamespaceContainer>
<PresentationStyle>VS2013</PresentationStyle>
<Preliminary>False</Preliminary>
<NamingMethod>MemberName</NamingMethod>
<HelpTitle>Microsoft.O365.Security.Native.ETW Documentation</HelpTitle>
<CopyrightText>Copyright 2016 Microsoft Corporation</CopyrightText>
<ContentPlacement>AboveNamespaces</ContentPlacement>
<VisibleItems>Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, ProtectedInternalAsProtected</VisibleItems>
<DocumentationSources>
<DocumentationSource sourceFile="..\krabs\x64\Debug\Microsoft.O365.Security.Native.ETW.xml" />
<DocumentationSource sourceFile="..\krabs\x64\Debug\Microsoft.O365.Security.Native.ETW.dll" />
</DocumentationSources>
<NamespaceSummaries>
<NamespaceSummaryItem name="Microsoft.O365.Security.ETW" isDocumented="True" xmlns="">Global namespace for Microsoft.O365.Security.Native.ETW.dll (aka Lobsters).</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.O365.Security.ETW.Kernel" isDocumented="True" xmlns="">Microsoft.O365.Security.ETW.Kernel provides convenience wrapper objects for the commonly available kernel ETW traces.</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.O365.Security.ETW.Testing" isDocumented="True" xmlns="">Microsoft.O365.Security.ETW.Testing provides objects that can be used in testing Lobsters itself.</NamespaceSummaryItem></NamespaceSummaries>
<ApiFilter>
<Filter entryType="Namespace" fullName="Microsoft.O365.Security.ETW" isExposed="True" xmlns="">
<Filter entryType="Class" fullName="Microsoft.O365.Security.ETW.Predicate" filterName="Predicate" isExposed="True">
<Filter entryType="Method" fullName="Microsoft.O365.Security.ETW.Predicate.Test" filterName="Test" isExposed="False" />
</Filter>
</Filter>
<Filter entryType="Namespace" fullName="Microsoft.O365.Security.ETW.Testing" isExposed="False" xmlns="" /></ApiFilter>
</PropertyGroup>
<!-- There are no properties for these groups. AnyCPU needs to appear in order for Visual Studio to perform
the build. The others are optional common platform types that may appear. -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Win32' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Win32' ">
</PropertyGroup>
<!-- Import the SHFB build targets -->
<Import Project="$(SHFBROOT)\SandcastleHelpFileBuilder.targets" />
<!-- The pre-build and post-build event properties must appear *after* the targets file import in order to be
evaluated correctly. -->
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
</PropertyGroup>
</Project>
@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugSigning|x64">
<Configuration>DebugSigning</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseSigning|x64">
<Configuration>ReleaseSigning</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{ED4E6027-541F-440A-A5EE-15DBB7B89423}</ProjectGuid>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>ETWLib</RootNamespace>
<ProjectName>Microsoft.O365.Security.Native.ETW</ProjectName>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">.\</SolutionDir>
<RestorePackages>true</RestorePackages>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\net462\</OutDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>true</CLRSupport>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>true</CLRSupport>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PlatformToolset>v143</PlatformToolset>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CLRSupport>true</CLRSupport>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CLRSupport>true</CLRSupport>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<EmbedManifest>false</EmbedManifest>
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LinkIncremental>true</LinkIncremental>
<LinkKeyFile>
</LinkKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'">
<EmbedManifest>false</EmbedManifest>
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LinkIncremental>true</LinkIncremental>
<LinkKeyFile>$(SolutionDir)..\35MSSharedLib1024.snk</LinkKeyFile>
<LinkDelaySign>true</LinkDelaySign>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
<LinkKeyFile>
</LinkKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<IncludePath>$(SolutionDir);$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
<LinkKeyFile>$(SolutionDir)..\35MSSharedLib1024.snk</LinkKeyFile>
<LinkDelaySign>true</LinkDelaySign>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>TYPEASSERT;_DEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'">
<ClCompile>
<PreprocessorDefinitions>TYPEASSERT;_DEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>NDEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<ClCompile>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>NDEBUG;UNICODE;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\inc;$(ProjectDir)..\krabs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>if not exist $(ProjectDir)..\35MSSharedLib1024.snk sn.exe -k $(ProjectDir)..\35MSSharedLib1024.snk</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Verify snk file is generated</Message>
</PreBuildEvent>
<PostBuildEvent>
<Message>sign</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp" />
<ClCompile Include="ETWLib.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Conversions.hpp" />
<ClInclude Include="Errors.hpp" />
<ClInclude Include="EventRecordError.hpp" />
<ClInclude Include="EventRecordMetadata.hpp" />
<ClInclude Include="EventTraceProperties.hpp" />
<ClInclude Include="Filtering\AnsiString.hpp" />
<ClInclude Include="Filtering\CountedString.hpp" />
<ClInclude Include="Filtering\EventFilter.hpp" />
<ClInclude Include="Filtering\Fluent.hpp" />
<ClInclude Include="Filtering\Predicate.hpp" />
<ClInclude Include="Filtering\UnicodeString.hpp" />
<ClInclude Include="Guid.hpp" />
<ClInclude Include="IEventRecordError.hpp" />
<ClInclude Include="IEventRecordMetadata.hpp" />
<ClInclude Include="IEventRecord.hpp" />
<ClInclude Include="ITrace.hpp" />
<ClInclude Include="KernelProvider.hpp" />
<ClInclude Include="KernelTrace.hpp" />
<ClInclude Include="Kernel\KernelProviders.hpp" />
<ClInclude Include="NativePtr.hpp" />
<ClInclude Include="Property.hpp" />
<ClInclude Include="Provider.hpp" />
<ClInclude Include="EventRecord.hpp" />
<ClInclude Include="RawProvider.hpp" />
<ClInclude Include="Testing\EventHeader.hpp" />
<ClInclude Include="Testing\RecordBuilder.hpp" />
<ClInclude Include="Testing\SynthRecord.hpp" />
<ClInclude Include="Testing\Proxy.hpp" />
<ClInclude Include="TraceStats.hpp" />
<ClInclude Include="UserTrace.hpp" />
</ItemGroup>
<ItemGroup>
<None Include=".nuget\NuGet.Config" />
<None Include=".nuget\NuGet.exe" />
<None Include=".nuget\NuGet.targets" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="ETWLib.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AssemblyInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{496956b8-4005-4ae3-ac9b-11eab32cb721}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{7b471d7e-6f69-45e0-a76e-e5fd3cb6d15a}</UniqueIdentifier>
</Filter>
<Filter Include=".nuget">
<UniqueIdentifier>{8c66e43c-83e0-4965-b71d-1409f807ac51}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Filtering">
<UniqueIdentifier>{ce3bf1a4-eb35-4f47-b17b-0dbc511e8b0a}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Kernel">
<UniqueIdentifier>{61685433-8806-4bc1-9e4c-60ce5ab1669a}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\User">
<UniqueIdentifier>{c2fc8bab-b190-4850-a4fe-9863d5a00d89}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Testing">
<UniqueIdentifier>{d2144890-b387-409f-9e5b-805abc28ee9b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Errors.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NativePtr.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Filtering\EventFilter.hpp">
<Filter>Header Files\Filtering</Filter>
</ClInclude>
<ClInclude Include="Filtering\Fluent.hpp">
<Filter>Header Files\Filtering</Filter>
</ClInclude>
<ClInclude Include="Filtering\Predicate.hpp">
<Filter>Header Files\Filtering</Filter>
</ClInclude>
<ClInclude Include="KernelProvider.hpp">
<Filter>Header Files\Kernel</Filter>
</ClInclude>
<ClInclude Include="KernelTrace.hpp">
<Filter>Header Files\Kernel</Filter>
</ClInclude>
<ClInclude Include="UserTrace.hpp">
<Filter>Header Files\User</Filter>
</ClInclude>
<ClInclude Include="Kernel\KernelProviders.hpp">
<Filter>Header Files\Kernel</Filter>
</ClInclude>
<ClInclude Include="Testing\SynthRecord.hpp">
<Filter>Header Files\Testing</Filter>
</ClInclude>
<ClInclude Include="Property.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Testing\RecordBuilder.hpp">
<Filter>Header Files\Testing</Filter>
</ClInclude>
<ClInclude Include="Provider.hpp">
<Filter>Header Files\User</Filter>
</ClInclude>
<ClInclude Include="Testing\Proxy.hpp">
<Filter>Header Files\Testing</Filter>
</ClInclude>
<ClInclude Include="Testing\EventHeader.hpp">
<Filter>Header Files\Testing</Filter>
</ClInclude>
<ClInclude Include="IEventRecord.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventRecord.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Filtering\CountedString.hpp">
<Filter>Header Files\Filtering</Filter>
</ClInclude>
<ClInclude Include="Guid.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Filtering\AnsiString.hpp">
<Filter>Header Files\Filtering</Filter>
</ClInclude>
<ClInclude Include="Filtering\UnicodeString.hpp">
<Filter>Header Files\Filtering</Filter>
</ClInclude>
<ClInclude Include="IEventRecordMetadata.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventRecordMetadata.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventRecordError.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RawProvider.hpp">
<Filter>Header Files\User</Filter>
</ClInclude>
<ClInclude Include="TraceStats.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ITrace.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Conversions.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventTraceProperties.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IEventRecordError.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include=".nuget\NuGet.Config">
<Filter>.nuget</Filter>
</None>
<None Include=".nuget\NuGet.exe">
<Filter>.nuget</Filter>
</None>
<None Include=".nuget\NuGet.targets">
<Filter>.nuget</Filter>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,163 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Really basic RAII wrapper for native pointers in managed classes.
// Think unique_ptr but can be a managed class member.
//
// NOTE: pointers are allocated with 'new'
#pragma once
#pragma warning(push)
#pragma warning(disable: 4634) // DocXml comment warnings in native C++
#include <msclr/lock.h>
using namespace System;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Wraps an unmanaged ptr in a managed type. This allows unmanaged types
/// to be members of managed types. The semantics of this work like
/// std::unique_ptr.
/// </summary>
template <typename T>
ref class NativePtr
{
// the wrapped native pointer
T* ptr;
// hide copy and assignment to prevent the pointer from
// getting handed to another instance, which would cause double free
NativePtr(NativePtr<T>%);
NativePtr<T>% operator=(NativePtr<T>%);
public:
/// <summary>
/// Construct an empty (null) NativePtr.
/// </summary>
NativePtr()
: ptr(nullptr) { }
/// <summary>
/// Construct a NativePtr that assumes ownership of the specified pointer.
/// </summary>
NativePtr(T* p)
: ptr(p) { }
/// <summary>
/// Construct a NativePtr by forwarding the specified arguments to the
/// templated class' constructor. This DOES NOT work for ctors that
/// take 0 parameters (the empty constructor will be called instead).
/// In that case use NativePtr(new T()) to select the pointer ctor.
/// </summary>
template <typename... Args>
NativePtr(Args&&... args)
: ptr(new T(std::forward<Args>(args)...)) { }
/// <summary>
/// Destructor
/// </summary>
~NativePtr()
{
FreeMemory();
}
/// <summary>
/// Finalizer
/// </summary>
!NativePtr()
{
FreeMemory();
}
/// <summary>
/// Gets the pointer to the wrapped resource.
/// </summary>
T* Get()
{
return ptr;
}
/// <summary>
/// Relinquishes control of the internal pointer without doing any
/// memory management.
/// </summary>
T* Release()
{
T* oldPtr = ptr;
ptr = nullptr;
return oldPtr;
}
/// <summary>
/// Swaps ownership of the wrapped pointers.
/// </summary>
void Swap(NativePtr<T>% other)
{
T* p = other.ptr;
other.ptr = ptr;
ptr = p;
}
/// <summary>
/// Release the currently held resource and takes ownership of the
/// specified resource if the specified resource != current.
/// </summary>
void Reset(T* newPtr)
{
if (ptr != newPtr)
{
FreeMemory();
ptr = newPtr;
}
}
/// <summary>
/// Access the wrapped pointer.
/// </summary>
T* operator->()
{
return Get();
}
/// <summary>
/// Dereference wrapped pointer
/// </summary>
static T& operator*(NativePtr<T>% instance)
{
return *(instance.Get());
}
/// <summary>
/// Cast to bool (for conditionals). Returns true if the wrapped
/// pointer is not null.
/// </summary>
static operator bool(NativePtr<T>% instance)
{
return instance.ptr != nullptr;
}
private:
/// <summary>
/// Releases the memory held by this smart pointer, if any.
/// </summary>
void FreeMemory()
{
// call delete in a locked section to prevent possible double
// free if Dispose is called multiple times on different threads
msclr::lock l(this);
if (nullptr != ptr)
{
delete ptr;
ptr = nullptr;
}
}
};
} } } }
#pragma warning(pop)
@@ -0,0 +1,191 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "NativePtr.hpp"
#include <cassert>
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
using namespace System::Collections::Generic;
/// <summary>
/// Represents a single property in an EventRecord.
/// </summary>
/// <remarks>
/// Noticeably absent from this property is the ability to ask what its
/// value is.The reason for this is that this property instance is
/// intended to work with synth_records, which don't always have data to
/// correspond with properties.This class *cannot* return a value because
/// there isn't always a value to return.
/// </remarks>
public ref class Property {
public:
/// <summary>
/// Represents a property on an EventRecord.
/// </summary>
/// <param name="name">the property's name</param>
/// <param name="type">the property's type</param>
/// <param name="outType">the property's out type</param>
/// <remarks>
/// See <see href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa964763(v=vs.85).aspx"/>
/// for more information about property types. In particular, the TDH_INTYPE_* values.
/// </remarks>
Property(String ^name, unsigned int type, unsigned int outType);
/// <summary>Returns the name of this property.</summary>
/// <returns>the name of this property</returns>
property String ^Name {
String ^get() {
return gcnew String(property_->name().c_str());
}
}
/// <summary>Returns the type of this property.</summary>
/// <returns>the type of this property</returns>
property int Type {
int get() {
return property_->type();
}
}
/// <summary>Returns the out type of this property.</summary>
/// <returns>the out type of this property</returns>
property int OutType {
int get() {
return property_->out_type();
}
}
private:
NativePtr<krabs::property> property_;
};
/// <summary>
/// Iterates the properties in an event schema.
/// </summary>
public ref class PropertyEnumerator : public IEnumerator<Property^> {
internal:
PropertyEnumerator(const krabs::schema& schema)
: iterator_(schema)
, vecIterator_()
, vecIteratorEnd_()
{
Reset();
}
~PropertyEnumerator() { }
/// <summary>
/// Advance the enumerator by one element.
/// </summary>
/// <returns>true if more elements to enumerate, false if at the end</returns>
virtual bool MoveNext() = IEnumerator<Property^>::MoveNext {
// C#'s enumerators expect the enumeration to point to a vacuous
// space *before* the first element when they are Reset. Reset is
// immediately followed by a call to MoveNext that points us to the
// actual first element. C++ iterators don't work this way, so we
// need to align them by lazily initializing the underlying C++
// iterator.
if (!vecIterator_) {
vecIterator_.Swap(NativePtr<std::vector<krabs::property>::iterator>(iterator_->begin()));
if (iters_match(vecIterator_, vecIteratorEnd_)) {
return false;
}
return true;
}
if (iters_match(vecIterator_, vecIteratorEnd_)) {
return false;
}
std::advance(*vecIterator_.Get(), 1);
if (iters_match(vecIterator_, vecIteratorEnd_)) {
return false;
}
return true;
}
/// <summary>Return the current element in the enumeration</summary>
/// <returns>the current element in the enumeration as a <see cref="O365::Security::ETW::Property"/></returns>
property Property^ Current {
virtual Property ^get() = IEnumerator<Property^>::Current::get {
return gcnew Property(gcnew String((*vecIterator_.Get())->name().c_str()), (*vecIterator_.Get())->type(), (*vecIterator_.Get())->out_type());
}
};
/// <summary>Return the current element in the enumeration</summary>
/// <returns>the current element in the enumeration as a <see cref="System::Object"/></returns>
property Object ^Current2 {
virtual Object ^get() = System::Collections::IEnumerator::Current::get {
return gcnew Property(gcnew String((*vecIterator_.Get())->name().c_str()), (*vecIterator_.Get())->type(), (*vecIterator_.Get())->out_type());
}
}
/// <summary>Reset the enumeration</summary>
virtual void Reset() = IEnumerator<Property^>::Reset {
vecIterator_.Reset(nullptr);
vecIteratorEnd_.Swap(NativePtr<std::vector<krabs::property>::iterator>(iterator_->end()));
}
private:
template <typename T>
bool iters_match(T %one, T %two)
{
return (*one.Get() == *two.Get());
}
internal:
NativePtr<krabs::property_iterator> iterator_;
NativePtr<std::vector<krabs::property>::iterator> vecIterator_;
NativePtr<std::vector<krabs::property>::iterator> vecIteratorEnd_;
};
/// <summary>
/// IEnumerable implementation for property enumeration.
/// </summary>
public ref class PropertyEnumerable : public IEnumerable<Property^> {
internal:
PropertyEnumerable(const krabs::schema& schema)
: schema_(&schema)
{}
public:
/// <summary>
/// Implementation of generic IEnumerable::GetEnumerator
/// </summary>
/// <returns>an IEnumerator of <see cref="O365::Security::ETW::Property"/></returns>
virtual IEnumerator<Property^> ^GetEnumerator() {
return gcnew PropertyEnumerator(*schema_);
}
/// <summary>
/// Implementation of non-generic IEnumerable::GetEnumerator
/// </summary>
/// <returns>an IEnumerator of object that can be cast to IEnumerator of
/// <see cref="O365::Security::ETW::Property"/>
/// </returns>
virtual System::Collections::IEnumerator ^GetEnumerator2() = System::Collections::IEnumerable::GetEnumerator {
return gcnew PropertyEnumerator(*schema_);
}
internal:
const krabs::schema* schema_;
};
// Implementation
// ------------------------------------------------------------------------
inline Property::Property(String ^name, unsigned int type, unsigned int outType)
: property_(msclr::interop::marshal_as<std::wstring>(name), (_TDH_IN_TYPE)type, (_TDH_OUT_TYPE)outType)
{
}
} /* namespace ETW */ } /* namespace Security */ } /* namespace O365 */ } /* namespace Microsoft */
@@ -0,0 +1,283 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "EventRecord.hpp"
#include "EventRecordMetadata.hpp"
#include "Guid.hpp"
#include "NativePtr.hpp"
#include "Filtering/EventFilter.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
ref class UserTrace;
// Flags as documented here:
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd392306(v=vs.85).aspx
public enum class TraceFlags
{
// User SID for the event is included in the ExtendedData field
IncludeUserSid = 0x00000001,
// Terminal Session ID for the event is included in the ExtendedData field
IncludeTerminalSessionId = 0x00000002,
// Stack trace for the event is included in the ExtendedData field
IncludeStackTrace = 0x00000004,
// Filters out all events that do not have a non-zero keyword specified.
IgnoreKeyword0 = 0x00000010,
// Indicates that EnableTraceEx2 should enable a provider group rather
// than an individual provider. See https://msdn.microsoft.com/en-us/library/windows/desktop/mt772485(v=vs.85).aspx
EnableProviderGroup = 0x00000020,
// Include the Process Start Key in the extended data.
// The Process Start Key is a sequence number that identifies the process.
// While the Process ID may be reused within a session, the Process Start Key
// is guaranteed uniqueness in the current boot session.
IncludeProcessStartKey = 0x00000080,
// Include the Event Key in the extended data.
// The Event Key is a unique identifier for the event instance that will be
// constant across multiple trace sessions listening to this event.
// It can be used to correlate simultaneous trace sessions.
IncludeProcessEventKey = 0x00000100,
// Filters out all events that are either marked as an InPrivate event
// or come from a process that is marked as InPrivate.
// InPrivate implies that the event or process contains some data that would be
// considered private or personal. It is up to the process or event to designate
// itself as InPrivate for this to work.
ExcludeInPrivateEventKey = 0x00000200,
// Receive events from processes running inside Windows containers
EnableSilosEventKey = 0x00000400,
// The container ID is included in the ExtendedData field of events
// emitted from processes running inside Windows containers
SourceContainerTrackingEventKey = 0x00000800,
};
/// <summary>
/// Represents a user trace provider and its configuration.
/// </summary>
/// <remarks>
/// The easiest way to identify providers that you can enable
/// is to use the Message Analyzer tool: <see href="https://blogs.technet.microsoft.com/messageanalyzer/"/>
/// </remarks>
public ref class Provider {
public:
/// <summary>
/// Specifies a reasonable default to catch all the events with a
/// bitmask with all bits set.
/// </summary>
static const ULONGLONG AllBitsSet = (ULONGLONG)-1;
/// <summary>
/// Constructs a Provider that is identified by its GUID.
/// </summary>
/// <param name="id">the Guid of the provider to construct</param>
/// <example>
/// var provider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
/// </example>
Provider(System::Guid id);
/// <summary>
/// Constructs a Provider that is identified by the provider name.
/// </summary>
/// <param name="providerName">the name of the provider to construct</param>
/// <example>
/// var provider = new Provider("Microsoft-Windows-PowerShell");
/// </example>
Provider(String^ providerName);
/// <summary>
/// Destructs a Provider.
/// </summary>
~Provider();
/// <summary>
/// Represents the "any" value on the provider's options, where
/// "any" is typically used to request notification if any of the
/// matching event types fire.
/// </summary>
property ULONGLONG Any {
void set(ULONGLONG value) {
provider_->any(value);
}
}
/// <summary>
/// Represents the "all" value on the provider's options, where
/// "all" is typically used to request notification if all of the
/// keyword types are matched.
/// </summary>
property ULONGLONG All {
void set(ULONGLONG value) {
provider_->all(value);
}
}
/// <summary>
/// Represents the "level" value on the provider's options, where
/// "level" determines events in what categories are
/// enabled for notification.
/// </summary>
property UCHAR Level {
void set(UCHAR value) {
provider_->level(value);
}
}
/// <summary>
/// Represents the "EnabledProperty" value on the provider's options.
/// Values are documented here:
/// https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-enable_trace_parameters
/// </summary>
property TraceFlags TraceFlags {
ETW::TraceFlags get() {
return static_cast<ETW::TraceFlags>(provider_->trace_flags());
}
void set(O365::Security::ETW::TraceFlags value) {
provider_->trace_flags((ULONG)value);
}
}
/// <summary>
/// Requests that the provider log its state information. See:
/// https://docs.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-enabletraceex2
/// </summary>
/// <example>
/// var provider = new Provider("Microsoft-Windows-Kernel-Process");
/// provider.Any = 0x10; // WINEVENT_KEYWORD_PROCESS
/// provider.EnableRundownEvents();
/// </example>
void EnableRundownEvents() {
provider_->enable_rundown_events();
}
/// <summary>
/// Adds a new EventFilter to the provider.
/// </summary>
/// <param name="filter">the <see cref="O365::Security::ETW::EventFilter"/> to add</param>
void AddFilter(O365::Security::ETW::EventFilter ^filter) {
provider_->add_filter(filter);
}
/// <summary>
/// An event that is invoked when an ETW event is fired in this
/// provider.
/// </summary>
event IEventRecordDelegate^ OnEvent;
/// <summary>
/// An event that is invoked when an ETW event is received
/// but an error occurs handling the record.
/// </summary>
event EventRecordErrorDelegate^ OnError;
internal:
void EventNotification(const EVENT_RECORD &, const krabs::trace_context &);
void ErrorNotification(const EVENT_RECORD&, const std::string&);
internal:
delegate void EventReceivedNativeHookDelegate(const EVENT_RECORD &, const krabs::trace_context &);
delegate void ErrorReceivedNativeHookDelegate(const EVENT_RECORD &, const std::string &);
NativePtr<krabs::provider<>> provider_;
EventReceivedNativeHookDelegate^ eventReceivedDelegate_;
ErrorReceivedNativeHookDelegate^ errorReceivedDelegate_;
GCHandle eventReceivedDelegateHookHandle_;
GCHandle errorReceivedDelegateHookHandle_;
GCHandle eventReceivedDelegateHandle_;
GCHandle errorReceivedDelegateHandle_;
void RegisterCallbacks();
};
// Implementation
// ------------------------------------------------------------------------
inline Provider::Provider(System::Guid id)
: provider_(ConvertGuid(id))
{
RegisterCallbacks();
}
inline Provider::Provider(String^ providerName)
: provider_(msclr::interop::marshal_as<std::wstring>(providerName))
{
RegisterCallbacks();
}
inline Provider::~Provider()
{
if (eventReceivedDelegateHandle_.IsAllocated)
{
eventReceivedDelegateHandle_.Free();
}
if (eventReceivedDelegateHookHandle_.IsAllocated)
{
eventReceivedDelegateHookHandle_.Free();
}
if (errorReceivedDelegateHandle_.IsAllocated)
{
errorReceivedDelegateHandle_.Free();
}
if (errorReceivedDelegateHookHandle_.IsAllocated)
{
errorReceivedDelegateHookHandle_.Free();
}
}
inline void Provider::RegisterCallbacks()
{
eventReceivedDelegate_ = gcnew EventReceivedNativeHookDelegate(this, &Provider::EventNotification);
eventReceivedDelegateHandle_ = GCHandle::Alloc(eventReceivedDelegate_);
auto bridgedEventDelegate = Marshal::GetFunctionPointerForDelegate(eventReceivedDelegate_);
eventReceivedDelegateHookHandle_ = GCHandle::Alloc(bridgedEventDelegate);
provider_->add_on_event_callback((krabs::c_provider_callback)bridgedEventDelegate.ToPointer());
errorReceivedDelegate_ = gcnew ErrorReceivedNativeHookDelegate(this, &Provider::ErrorNotification);
errorReceivedDelegateHandle_ = GCHandle::Alloc(errorReceivedDelegate_);
auto bridgedErrorDelegate = Marshal::GetFunctionPointerForDelegate(errorReceivedDelegate_);
errorReceivedDelegateHookHandle_ = GCHandle::Alloc(bridgedErrorDelegate);
provider_->add_on_error_callback((krabs::c_provider_error_callback)bridgedErrorDelegate.ToPointer());
}
inline void Provider::EventNotification(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
{
try
{
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
OnEvent(gcnew EventRecord(record, schema, parser));
}
catch (const krabs::could_not_find_schema& ex)
{
ErrorNotification(record, ex.what());
}
}
inline void Provider::ErrorNotification(const EVENT_RECORD& record, const std::string& error_message)
{
auto msg = gcnew String(error_message.c_str());
auto metadata = gcnew EventRecordMetadata(record);
OnError(gcnew EventRecordError(msg, metadata));
}
} } } }
@@ -0,0 +1,38 @@
Overview
========
ETWLib is a C# library that simplifies interacting with ETW. It allows for any number of traces and providers to be enabled and for client code to register for event notifications from these traces.
ETWLib also provides code to simplify parsing generic event data into strongly typed data types.
Guided Example
==============
ETW has the concept of a trace, where a trace essentially represents a stream of events that can be listened to. It distinguishes between kernel and user traces, where the source of events in a kernel trace comes from the Windows kernel. User trace event sources can be any regular application that is ETW-aware.
ETWLib maintains the differentiation between user and kernel traces (kernel traces are not yet implemented) because their APIs are slightly different.
A `UserTrace` can be named an arbitrary name or a name can be generated for you.
UserTrace trace = new UserTrace(); // unnamed trace
UserTrace namedTrace = new UserTrace("Muffins McGoo");
ETWLib represents different sources of ETW events with the concept of a `Provider`. Providers are identified by a GUID, as specified by ETW itself. Providers each have a pair of properties that represent bitflags named `Any` and `All` that are used to do event filtering. If an event meets any of the flags in the `Any` property, registered event callbacks are called. If an event meets all of the bits in the `All` property, registered event callbacks are likewise called.
**NOTE:** The semantics of the `Any` and `All` flag are left to the discretion of the ETW provider. Many providers ignore the `All` flag if the `Any` flag is not set, for example.
void MyCallbackFunction(EventRecord)
{}
Provider powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
powershellProvider.Any = 0x10;
powershellProvider.OnEvent += MyCallbackFunction;
Providers must be enabled for specific traces in order to have any effect on the event tracing system:
namedTrace.Enable(powershellProvider);
Once all the providers have been enabled for a trace, the trace must be started. The `UserTrace::start()` method will block while listening for events, so if a program is supposed to do other interesting things while listening for ETW events, the start method needs to called on another thread.
var t = Task.Run(() => namedTrace.Start());
@@ -0,0 +1,170 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "EventRecord.hpp"
#include "EventRecordMetadata.hpp"
#include "Guid.hpp"
#include "NativePtr.hpp"
#include "Filtering/EventFilter.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Delegate called when a new ETW <see cref="O365::Security::ETW::EventRecordMetadata"/> is received.
/// </summary>
public delegate void IEventRecordMetadataDelegate(
O365::Security::ETW::IEventRecordMetadata^ record);
ref class UserTrace;
/// <summary>
/// Represents a raw user trace provider and its configuration.
/// This provider emits IEventRecordMetadata instead of IEventRecord
/// so it can be used to access events without a registered schema.
/// </summary>
/// <seealso cref="O365::Security::ETW::Provider"/>
public ref class RawProvider {
public:
/// <summary>
/// Specifies a reasonable default to catch all the events with a
/// bitmask with all bits set.
/// </summary>
static const ULONGLONG AllBitsSet = (ULONGLONG)-1;
/// <summary>
/// Constructs a RawProvider that is identified by its GUID.
/// </summary>
/// <param name="id">the Guid of the provider to enable</param>
/// <seealso cref="O365::Security::ETW::Provider"/>
RawProvider(System::Guid id);
/// <summary>
/// Constructs a RawProvider that is identified by the provider name.
/// </summary>
/// <param name="providerName">the friendly name of the provider to enable</param>
/// <seealso cref="O365::Security::ETW::Provider"/>
RawProvider(String^ providerName);
/// <summary>
/// Destructs a RawProvider.
/// </summary>
~RawProvider();
/// <summary>
/// Represents the "any" value on the provider's options, where
/// "any" is typically used to request notification if any of the
/// matching event types fire.
/// </summary>
property ULONGLONG Any {
void set(ULONGLONG value) {
provider_->any(value);
}
}
/// <summary>
/// Represents the "all" value on the provider's options, where
/// "all" is typically used to request notification if all of the
/// keyword types are matched.
/// </summary>
property ULONGLONG All {
void set(ULONGLONG value) {
provider_->all(value);
}
}
/// <summary>
/// Represents the "level" value on the provider's options, where
/// "level" determines events in what categories are
/// enabled for notification.
/// </summary>
property UCHAR Level {
void set(UCHAR value) {
provider_->level(value);
}
}
/// <summary>
/// Represents the "EnabledProperty" value on the provider's options.
/// Values are documented here:
/// https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-enable_trace_parameters
/// </summary>
property TraceFlags TraceFlags {
ETW::TraceFlags get() {
return static_cast<ETW::TraceFlags>(provider_->trace_flags());
}
void set(O365::Security::ETW::TraceFlags value) {
provider_->trace_flags((ULONG)value);
}
}
/// <summary>
/// An event that is invoked when an ETW event is fired in this
/// provider.
/// </summary>
event IEventRecordMetadataDelegate^ OnEvent;
internal:
void EventNotification(const EVENT_RECORD &);
internal:
delegate void NativeHookDelegate(const EVENT_RECORD &);
NativeHookDelegate ^del_;
NativePtr<krabs::provider<>> provider_;
GCHandle delegateHookHandle_;
GCHandle delegateHandle_;
void SetUpProvider();
};
// Implementation
// ------------------------------------------------------------------------
inline RawProvider::RawProvider(System::Guid id)
: provider_(ConvertGuid(id))
{
SetUpProvider();
}
inline RawProvider::RawProvider(String^ providerName)
: provider_(msclr::interop::marshal_as<std::wstring>(providerName))
{
SetUpProvider();
}
inline void RawProvider::SetUpProvider()
{
del_ = gcnew NativeHookDelegate(this, &RawProvider::EventNotification);
delegateHandle_ = GCHandle::Alloc(del_);
auto bridged = Marshal::GetFunctionPointerForDelegate(del_);
delegateHookHandle_ = GCHandle::Alloc(bridged);
provider_->add_on_event_callback((krabs::c_provider_callback)bridged.ToPointer());
}
inline RawProvider::~RawProvider()
{
if (delegateHandle_.IsAllocated)
{
delegateHandle_.Free();
}
if (delegateHookHandle_.IsAllocated)
{
delegateHookHandle_.Free();
}
}
inline void RawProvider::EventNotification(const EVENT_RECORD &record)
{
OnEvent(gcnew EventRecordMetadata(record));
}
} } } }
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft { namespace O365 { namespace Security { namespace ETW { namespace Testing {
public enum class EventHeaderFlags : uint16_t
{
EXTENDED_INFO = 0x0001,
PRIVATE_SESSION = 0x0002,
STRING_ONLY = 0x0004,
TRACE_MESSAGE = 0x0008,
NO_CPUTIME = 0x0010,
HEADER_32_BIT = 0x0020,
HEADER_64_BIT = 0x0040,
CLASSIC_HEADER = 0x0100,
PROCESSOR_INDEX = 0x0200
};
/// <summary>
/// Provides access to the EVENT_HEADER element of a synthetic
/// event record.
/// </summary>
public ref class EventHeader {
public:
EventHeader(EVENT_HEADER *header);
/// <summary>
/// Provides access to the Flags field of the EventHeader.
/// </summary>
property unsigned short Flags {
unsigned short get() {
return header_->Flags;
}
void set(unsigned short val) {
header_->Flags = val;
}
}
internal:
EVENT_HEADER *header_;
};
// Implementation
// ------------------------------------------------------------------------
inline EventHeader::EventHeader(EVENT_HEADER *header)
: header_(header)
{ }
} /* namespace Testing */ } /* namespace ETW */ } /* namespace Security */ } /* namespace O365 */ } /* namespace Microsoft */
@@ -0,0 +1,88 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include "../UserTrace.hpp"
#include "../KernelTrace.hpp"
#include "SynthRecord.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW { namespace Testing {
/// <summary>
/// Serves as a stand-in for the trace class for testing purposes. It acts
/// as a liason for the actual trace instance and allows for forced event
/// testing.
/// </summary>
public ref class Proxy {
public:
/// <summary>
/// Constructs a proxy for the given user trace.
/// </summary>
Proxy(UserTrace ^trace);
/// <summary>
/// Constructs a proxy for the given kernel trace.
/// </summary>
Proxy(KernelTrace ^trace);
/// <summary>
/// Constructs a proxy for an event filter.
/// </summary>
Proxy(EventFilter ^filter);
/// <summary>
/// Pushes an event through the proxied trace instance.
/// </summary>
void PushEvent(SynthRecord ^record);
internal:
UserTrace ^userTrace_;
KernelTrace ^kernelTrace_;
EventFilter ^filter_;
};
// Implementation
// ------------------------------------------------------------------------
inline Proxy::Proxy(UserTrace ^trace)
: userTrace_(trace)
, kernelTrace_(nullptr)
, filter_(nullptr)
{}
inline Proxy::Proxy(KernelTrace ^trace)
: userTrace_(nullptr)
, kernelTrace_(trace)
, filter_(nullptr)
{}
inline Proxy::Proxy(EventFilter ^filter)
: userTrace_(nullptr)
, kernelTrace_(nullptr)
, filter_(filter)
{}
inline void Proxy::PushEvent(SynthRecord ^record)
{
auto rec = record->record_.Get();
if (userTrace_) {
krabs::testing::trace_proxy<krabs::user_trace> proxy(*userTrace_->trace_.Get());
proxy.push_event(*rec);
}
if (kernelTrace_) {
krabs::testing::trace_proxy<krabs::kernel_trace> proxy(*kernelTrace_->trace_.Get());
proxy.push_event(*rec);
}
if (filter_) {
krabs::testing::event_filter_proxy proxy(*filter_->filter_.Get());
proxy.push_event(*rec);
}
}
} /* namespace Testing */ } /* namespace ETW */ } /* namespace Security */ } /* namespace O365 */ } /* namespace Microsoft */
@@ -0,0 +1,188 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "../Guid.hpp"
#include "../NativePtr.hpp"
#include "SynthRecord.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW { namespace Testing {
/// <summary>
/// Enables creation of synthetic events in order to test client code.
/// </summary>
/// <remarks>
// This beast of a class enables the creation of EVENT_RECORD events
// for testing. The class accepts a collection of keyed pairs that are
// then packed into the event according to the schema on the local
// machine. Because a lot of this is Dark Arts kind of stuff, there
// really isn't a guarantee that this code works perfectly. Please
// file bugs.
/// </remarks>
public ref class RecordBuilder {
public:
RecordBuilder(System::Guid guid, int id, int version, int opcode);
RecordBuilder(System::Guid guid, int id, int version);
/// <summary>
/// Packs the event properties into an EVENT_RECORD
/// </summary>
SynthRecord^ Pack();
/// <summary>
/// Packs the event properties into an EVENT_RECORD, but doesn't throw
/// when the properties are not completely filled (i.g., when not all
/// properties are supplied)
/// </summary>
SynthRecord^ PackIncomplete();
/// <summary>
/// Provides access to the EventHeader that will be packed into the
/// faked record.
/// </summary>
property EventHeader^ Header {
EventHeader^ get() {
return gcnew EventHeader(&builder_->header());
}
}
/// <summary>
/// Adds a property with an ANSI string to the record.
/// </summary>
void AddAnsiString(System::String^ name, System::String^ value);
/// <summary>
/// Adds a property with a unicode string to the record.
/// </summary>
void AddUnicodeString(System::String^ name, System::String^ value);
generic <typename T>
void AddValue(System::String^ name, T value);
/// <summary>
/// Adds a container ID extended data item
/// </summary>
void AddContainerId(System::Guid container_id);
internal:
NativePtr<krabs::testing::record_builder> builder_;
template <typename T>
void AddValueInternal(System::String^ name, T value);
};
// Implementation
// ------------------------------------------------------------------------
inline RecordBuilder::RecordBuilder(System::Guid guid, int id, int version, int opcode)
: builder_(ConvertGuid(guid), id, version, opcode)
{
}
inline RecordBuilder::RecordBuilder(System::Guid guid, int id, int version)
: RecordBuilder(guid, id, version, 0)
{
}
inline SynthRecord^ RecordBuilder::Pack()
{
try
{
// SynthRecord owns the memory management of nativeRecord
auto nativeRecord = new krabs::testing::synth_record(builder_->pack());
SynthRecord^ managed = gcnew SynthRecord(nativeRecord);
return managed;
}
catch (const krabs::could_not_find_schema& ex)
{
auto msg = gcnew String(ex.what());
throw gcnew CouldNotFindSchema(msg);
}
catch (const std::invalid_argument& ex)
{
auto msg = gcnew String(ex.what());
throw gcnew ArgumentException(msg);
}
catch (const std::domain_error& ex)
{
auto msg = gcnew String(ex.what());
throw gcnew ArgumentException(msg);
}
}
inline SynthRecord^ RecordBuilder::PackIncomplete()
{
try
{
// SynthRecord owns the memory management of nativeRecord
auto nativeRecord = new krabs::testing::synth_record(builder_->pack_incomplete());
SynthRecord^ managed = gcnew SynthRecord(nativeRecord);
return managed;
}
catch (const krabs::could_not_find_schema& ex)
{
auto msg = gcnew String(ex.what());
throw gcnew CouldNotFindSchema(msg);
}
catch (const std::invalid_argument& ex)
{
auto msg = gcnew String(ex.what());
throw gcnew ArgumentException(msg);
}
}
inline void RecordBuilder::AddAnsiString(System::String^ name, System::String^ value)
{
AddValueInternal(name, msclr::interop::marshal_as<std::string>(value));
}
inline void RecordBuilder::AddUnicodeString(System::String^ name, System::String^ value)
{
AddValueInternal(name, msclr::interop::marshal_as<std::wstring>(value));
}
generic <typename T>
inline void RecordBuilder::AddValue(System::String^ name, T value)
{
if (T::typeid == Int16::typeid)
AddValueInternal(name, (Int16)value);
else if (T::typeid == UInt16::typeid)
AddValueInternal(name, (UInt16)value);
else if (T::typeid == Int32::typeid)
AddValueInternal(name, (Int32)value);
else if (T::typeid == UInt32::typeid)
AddValueInternal(name, (UInt32)value);
else if (T::typeid == Int64::typeid)
AddValueInternal(name, (Int64)value);
else if (T::typeid == UInt64::typeid)
AddValueInternal(name, (UInt64)value);
else
{
auto msg = System::String::Format("Add value does not support type {0}", T::typeid);
throw gcnew ArgumentException(msg);
}
}
template <typename T>
void RecordBuilder::AddValueInternal(System::String^ name, T value)
{
auto propName = msclr::interop::marshal_as<std::wstring>(name);
builder_->add_properties()(propName, value);
}
inline void RecordBuilder::AddContainerId(System::Guid container_id)
{
builder_->add_container_id_extended_data(ConvertGuid(container_id));
}
} /* namespace Testing */ } /* namespace ETW */ } /* namespace Security */ } /* namespace O365 */ } /* namespace Microsoft */
@@ -0,0 +1,114 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
#include "../Guid.hpp"
namespace Microsoft { namespace O365 { namespace Security { namespace ETW { namespace Testing {
/// <summary>
/// Represents a property that is faked -- one that is built by hand for
/// the purpose of testing event reaction code.
/// </summary>
public ref class SynthRecord {
internal:
/// <summary>
/// Constructs a synthetic property, given a partially filled EventRecord
/// and a packed sequence of bytes that represent the event's user data.
/// </summary>
/// <remarks>
/// Use a RecordBuilder to get an instance of this.
/// </remarks>
SynthRecord(krabs::testing::synth_record *record);
public:
/// <summary>
/// Direct access to the underlying EVENT_RECORD's ProviderId
/// </summary>
property Guid ProviderId {
Guid get() {
return ConvertGuid(Underlying().EventHeader.ProviderId);
}
void set(Guid value) {
Underlying().EventHeader.ProviderId = ConvertGuid(value);
}
}
/// <summary>
/// Direct access to the underlying EVENT_RECORD's Id
/// </summary>
property uint16_t Id {
uint16_t get() {
return Underlying().EventHeader.EventDescriptor.Id;
}
void set(uint16_t value) {
Underlying().EventHeader.EventDescriptor.Id = value;
}
}
/// <summary>
/// Direct access to the underlying EVENT_RECORD's Version
/// </summary>
property uint8_t Version {
uint8_t get() {
return Underlying().EventHeader.EventDescriptor.Version;
}
void set(uint8_t value) {
Underlying().EventHeader.EventDescriptor.Version = value;
}
}
/// <summary>
/// Direct access to the underlying EVENT_RECORD's Opcode
/// </summary>
property uint8_t Opcode {
uint8_t get() {
return Underlying().EventHeader.EventDescriptor.Opcode;
}
void set(uint8_t value) {
Underlying().EventHeader.EventDescriptor.Opcode = value;
}
}
/// <summary>
/// Direct access to the underlying EVENT_RECORD's Flags
/// </summary>
property uint16_t Flags {
uint16_t get() {
return Underlying().EventHeader.Flags;
}
void set(uint16_t value) {
Underlying().EventHeader.Flags = value;
}
}
private:
/// <summary>
/// Direct access to the underlying EVENT_RECORD so it can
/// be tampered with for unit testing.
/// </summary>
EVENT_RECORD& Underlying()
{
return const_cast<EVENT_RECORD&>(reinterpret_cast<const EVENT_RECORD&>(*record_));
}
internal:
NativePtr<krabs::testing::synth_record> record_;
};
// Implementation
// ------------------------------------------------------------------------
inline SynthRecord::SynthRecord(krabs::testing::synth_record *record)
: record_(record)
{ }
} /* namespace Testing */ } /* namespace ETW */ } /* namespace Security */ } /* namespace O365 */ } /* namespace Microsoft */
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <krabs.hpp>
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Selected statistics about an ETW trace
/// </summary>
public value class TraceStats
{
public:
/// <summary>count of trace buffers</summary>
initonly uint32_t BuffersCount;
/// <summary>count of free buffers</summary>
initonly uint32_t BuffersFree;
/// <summary>count of buffers written</summary>
initonly uint32_t BuffersWritten;
/// <summary>count of buffers lost</summary>
initonly uint32_t BuffersLost;
/// <summary>count of total events</summary>
initonly uint64_t EventsTotal;
/// <summary>count of events handled</summary>
initonly uint64_t EventsHandled;
/// <summary>count of events lost</summary>
initonly uint32_t EventsLost;
internal:
TraceStats(const krabs::trace_stats& stats)
: BuffersCount(stats.buffersCount)
, BuffersFree(stats.buffersFree)
, BuffersWritten(stats.buffersWritten)
, BuffersLost(stats.buffersLost)
, EventsTotal(stats.eventsTotal)
, EventsHandled(stats.eventsHandled)
, EventsLost(stats.eventsLost)
{ }
};
} } } }
@@ -0,0 +1,224 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
#include <krabs.hpp>
#include "ITrace.hpp"
#include "NativePtr.hpp"
#include "Provider.hpp"
#include "RawProvider.hpp"
#include "Errors.hpp"
#include "TraceStats.hpp"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Microsoft { namespace O365 { namespace Security { namespace ETW {
/// <summary>
/// Represents an owned user trace.
/// </summary>
public ref class UserTrace : public IUserTrace, public IDisposable {
public:
/// <summary>
/// Constructs a user trace session with a generated name.
/// </summary>
/// <example>
/// var UserTrace trace = new UserTrace();
/// </example>
UserTrace();
/// <summary>
/// Stops the user trace when disposed.
/// </summary>
~UserTrace();
/// <summary>
/// Constructs a named user trace session, where the name can be
/// any arbitrary, unique string.
/// </summary>
/// <param name="name">the name to assign to the UserTrace object</param>
/// <example>
/// var trace = new UserTrace("Purdy kitty");
/// </example>
UserTrace(String^ name);
/// <summary>
/// Enables a provider for the given user trace.
/// </summary>
/// <param name="provider">the <see cref="O365::Security::ETW::Provider"/> to enable on the trace</param>
/// <example>
/// UserTrace trace = new UserTrace();
/// System.Guid powershell = System.Guid.Parse("{...}")
/// Provider provider = new Provider(powershell);
/// trace.Enable(provider);
/// </example>
virtual void Enable(O365::Security::ETW::Provider ^provider);
/// <summary>
/// Enables a raw provider for the given user trace.
/// </summary>
/// <param name="provider">the <see cref="O365::Security::ETW::RawProvider"/> to enable on the trace</param>
/// <example>
/// UserTrace trace = new UserTrace();
/// System.Guid powershell = System.Guid.Parse("{...}")
/// Provider provider = new RawProvider(powershell);
/// trace.Enable(provider);
/// </example>
virtual void Enable(O365::Security::ETW::RawProvider ^provider);
/// <summary>
/// Sets the trace properties for a session.
/// Must be called before Open()/Start().
/// See https://docs.microsoft.com/en-us/windows/win32/etw/event-trace-properties
/// for important details and restrictions.
///
/// Configurable properties are ->
/// - BufferSize. In KB. The maximum buffer size is 1024 KB.
/// - MinimumBuffers. Minimum number of buffers is two per processor* .
/// - MaximumBuffers.
/// - FlushTimer. How often, in seconds, the trace buffers are forcibly flushed.
/// - LogFileMode. EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING simulates a *single* sequential processor.
/// </summary>
/// <param name="properties">the <see cref="O365::Security::ETW::EventTraceProperties"/> to set on the trace</param>
/// <example>
/// var trace = new UserTrace();
/// var properties = new EventTraceProperties
/// {
/// BufferSize = 256,
/// LogFileMode = (uint)LogFileModeFlags.FLAG_EVENT_TRACE_REAL_TIME_MODE
/// };
/// trace.SetTraceProperties(properties);
/// // ...
/// trace.Start();
/// </example>
virtual void SetTraceProperties(EventTraceProperties ^properties);
/// <summary>
/// Opens a trace session.
/// </summary>
/// <example>
/// var trace = new UserTrace();
/// // ...
/// trace.Open();
/// // ...
/// trace.Start();
/// </example>
/// <remarks>
/// This is an optional call before Start() if you need the trace
/// registered with the ETW subsystem before you start processing events.
/// </remarks>
virtual void Open();
/// <summary>
/// Starts listening for events from the enabled providers.
/// </summary>
/// <example>
/// UserTrace trace = new UserTrace();
/// // ...
/// trace.Start();
/// </example>
/// <remarks>
/// This function is a blocking call. Whichever thread calls Start() is effectively
/// donating itself to the ETW subsystem as the processing thread for events.
///
/// A side effect of this is that it is expected that Stop() will be called on
/// a different thread.
/// </remarks>
virtual void Start();
/// <summary>
/// Stops listening for events.
/// </summary>
/// <example>
/// UserTrace trace = new UserTrace();
/// // ...
/// trace.Start();
/// trace.Stop();
/// </example>
virtual void Stop();
/// <summary>
/// Get stats about events handled by this trace
/// </summary>
/// <returns>the <see cref="O365::Security::ETW::TraceStats"/> for the current trace object</returns>
virtual TraceStats QueryStats();
internal:
bool disposed_ = false;
O365::Security::ETW::NativePtr<krabs::user_trace> trace_;
};
// Implementation
// ------------------------------------------------------------------------
inline UserTrace::UserTrace()
: trace_(new krabs::user_trace())
{
}
inline UserTrace::~UserTrace()
{
if (disposed_) {
return;
}
Stop();
disposed_ = true;
}
inline UserTrace::UserTrace(String ^name)
: trace_()
{
std::wstring nativeName = msclr::interop::marshal_as<std::wstring>(name);
trace_.Swap(O365::Security::ETW::NativePtr<krabs::user_trace>(nativeName));
}
inline void UserTrace::Enable(O365::Security::ETW::Provider ^provider)
{
return trace_->enable(*provider->provider_);
}
inline void UserTrace::Enable(O365::Security::ETW::RawProvider ^provider)
{
return trace_->enable(*provider->provider_);
}
inline void UserTrace::SetTraceProperties(EventTraceProperties ^properties)
{
EVENT_TRACE_PROPERTIES _properties;
_properties.BufferSize = properties->BufferSize;
_properties.MinimumBuffers = properties->MinimumBuffers;
_properties.MaximumBuffers = properties->MaximumBuffers;
_properties.LogFileMode = properties->LogFileMode;
_properties.FlushTimer = properties->FlushTimer;
ExecuteAndConvertExceptions(return trace_->set_trace_properties(&_properties));
}
inline void UserTrace::Open()
{
ExecuteAndConvertExceptions((void)trace_->open());
}
inline void UserTrace::Start()
{
ExecuteAndConvertExceptions(return trace_->start());
}
inline void UserTrace::Stop()
{
ExecuteAndConvertExceptions(return trace_->stop());
}
inline TraceStats UserTrace::QueryStats()
{
ExecuteAndConvertExceptions(return TraceStats(trace_->query_stats()));
}
} } } }
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>Microsoft.O365.Security.Native.ETW.Debug</id>
<version>4.3.2</version>
<title>Microsoft.O365.Security.Native.ETW Debug - managed wrappers for krabsetw</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<license type="expression">MIT</license>
<projectUrl>https://github.com/Microsoft/krabsetw</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Microsoft.O365.Security.Native.ETW Debug is a managed wrapper around the krabsetw ETW library. This is the Debug build.</description>
<summary>Microsoft.O365.Security.Native.ETW Debug is a managed wrapper around the krabsetw ETW library. This is the Debug build.</summary>
<releaseNotes>
Version 4.3.2:
- Add support for ETL file sources
</releaseNotes>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<language />
<tags>ETW krabs managed cppcli</tags>
<dependencies>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net6.0" />
</dependencies>
</metadata>
<files>
<file src="krabs\x64\DebugSigning\net462\Microsoft.O365.Security.Native.ETW.dll" target="lib\net462\Microsoft.O365.Security.Native.ETW.dll" />
<file src="krabs\x64\DebugSigning\net462\Microsoft.O365.Security.Native.ETW.pdb" target="lib\net462\Microsoft.O365.Security.Native.ETW.pdb" />
<file src="krabs\x64\DebugSigning\net462\Microsoft.O365.Security.Native.ETW.xml" target="lib\net462\Microsoft.O365.Security.Native.ETW.xml" />
<file src="krabs\x64\DebugSigning\net6.0\Microsoft.O365.Security.Native.ETW.dll" target="lib\net6.0\Microsoft.O365.Security.Native.ETW.dll" />
<file src="krabs\x64\DebugSigning\net6.0\Microsoft.O365.Security.Native.ETW.pdb" target="lib\net6.0\Microsoft.O365.Security.Native.ETW.pdb" />
<file src="krabs\x64\DebugSigning\net6.0\Microsoft.O365.Security.Native.ETW.xml" target="lib\net6.0\Microsoft.O365.Security.Native.ETW.xml" />
<file src="krabs\x64\DebugSigning\net6.0\Ijwhost.dll" target="runtimes\win-x64\native\Ijwhost.dll" />
</files>
</package>
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>Microsoft.O365.Security.Native.ETW</id>
<version>4.3.2</version>
<title>Microsoft.O365.Security.Native.ETW - managed wrappers for krabsetw</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<license type="expression">MIT</license>
<projectUrl>https://github.com/Microsoft/krabsetw</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Microsoft.O365.Security.Native.ETW is a managed wrapper around the krabsetw ETW library.</description>
<summary>Microsoft.O365.Security.Native.ETW is a managed wrapper around the krabsetw ETW library.</summary>
<releaseNotes>
Version 4.3.2:
- Add support for ETL file sources
</releaseNotes>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<language />
<tags>ETW krabs managed cppcli</tags>
<dependencies>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net6.0" />
</dependencies>
</metadata>
<files>
<file src="krabs\x64\ReleaseSigning\net462\Microsoft.O365.Security.Native.ETW.dll" target="lib\net462\Microsoft.O365.Security.Native.ETW.dll" />
<file src="krabs\x64\ReleaseSigning\net462\Microsoft.O365.Security.Native.ETW.pdb" target="lib\net462\Microsoft.O365.Security.Native.ETW.pdb" />
<file src="krabs\x64\ReleaseSigning\net462\Microsoft.O365.Security.Native.ETW.xml" target="lib\net462\Microsoft.O365.Security.Native.ETW.xml" />
<file src="krabs\x64\ReleaseSigning\net6.0\Microsoft.O365.Security.Native.ETW.dll" target="lib\net6.0\Microsoft.O365.Security.Native.ETW.dll" />
<file src="krabs\x64\ReleaseSigning\net6.0\Microsoft.O365.Security.Native.ETW.pdb" target="lib\net6.0\Microsoft.O365.Security.Native.ETW.pdb" />
<file src="krabs\x64\ReleaseSigning\net6.0\Microsoft.O365.Security.Native.ETW.xml" target="lib\net6.0\Microsoft.O365.Security.Native.ETW.xml" />
<file src="krabs\x64\ReleaseSigning\net6.0\Ijwhost.dll" target="runtimes\win-x64\native\Ijwhost.dll" />
</files>
</package>
+49
View File
@@ -0,0 +1,49 @@
Overview
========
**krabsetw** is a C++ library that simplifies interacting with ETW. It allows for any number of traces and providers to be enabled and for client code to register for event notifications from these traces.
**krabsetw** also provides code to simplify parsing generic event data into strongly typed data types.
**Microsoft.O365.Security.Native.ETW** is a C++ CLI (.NET) wrapper around **krabsetw**. It provides the same functionality as **krabsetw** to .NET applications and is used in production by the Office 365 Security team. It's affectionately referred to as **Lobsters**.
Examples & Documentation
========
* An [ETW Primer](docs/EtwPrimer.md).
* Simple examples can be found in the `examples` folder.
* Please refer to [KrabsExample.md](docs/KrabsExample.md) and [LobstersExample.md](docs/LobstersExample.md) for detailed examples.
* SampleKrabsCSharpExe is a non-trivial example demonstrating how to manage the trace objects.
* [Using Message Analyzer to find new ETW event sources.](docs/UsingMessageAnalyzerToFindETWSources.md)
Important Notes
==============
* `krabsetw` and `Microsoft.O365.Security.Native.ETW` only support x64. No effort has been made to support x86.
* `krabsetw` and `Microsoft.O365.Security.Native.ETW` are only supported on Windows 7 or Windows 2008R2 machines and above.
* Throwing exceptions in the event handler callback or krabsetw or Microsoft.O365.Security.Native.ETW will cause the trace to stop processing events.
* The call to "start" on the trace object is blocking so thread management may be necessary.
* The Visual Studio solution is krabs\krabs.sln.
* When building a native code binary using the `krabsetw` package, please refer to the [compilation readme](krabs/README.md) for notes about the `TYPEASSERT` and `NDEBUG` compilation flags.
NuGet Packages
==============
NuGet packages are available both for the krabsetw C++ headers and the Microsoft.O365.Security.Native.ETW .NET library:
* https://www.nuget.org/packages/Microsoft.O365.Security.Native.ETW/
* https://www.nuget.org/packages/Microsoft.O365.Security.Native.ETW.Debug/ (for development - provides type asserts)
* https://www.nuget.org/packages/Microsoft.O365.Security.Krabsetw/
For verifying the .NET binaries, you can use the following command:
`sn -T Microsoft.O365.Security.Native.ETW.dll`
The expected output is:
```
Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.0
Copyright (c) Microsoft Corporation. All rights reserved.
Public key token is 31bf3856ad364e35
```
Community & Contact
==============
Please feel free to file issues through GitHub for bugs and feature requests and we'll respond to them as quickly as we're able.
+41
View File
@@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [[email protected]](mailto:[email protected]). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
</configuration>
@@ -0,0 +1,72 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows the event faking functionality lobster offers. This is useful
// for generating fake events that can be used to test client code.
using System;
using Microsoft.O365.Security.ETW;
using Testing = Microsoft.O365.Security.ETW.Testing;
namespace ManagedExamples
{
public static class FakingEvents001
{
public static void Start()
{
// The usual suspects for setting up the trace...
var trace = new Microsoft.O365.Security.ETW.UserTrace("My Named Trace");
var powershellGuid = Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
var powershellProvider = new Microsoft.O365.Security.ETW.Provider(powershellGuid);
powershellProvider.Any = Provider.AllBitsSet;
powershellProvider.OnEvent += (record) =>
{
Console.WriteLine("Event properties:");
foreach (Property prop in record.Properties)
{
Console.WriteLine("\t" + prop.Name);
}
};
trace.Enable(powershellProvider);
// Normally, we'd call trace.Start() to begin listening, but we
// want to test our code without actually starting a trace and
// listening for an event. We kick up a proxy for the user trace
// to offer us this functionality.
var proxy = new Testing.Proxy(trace);
// In order to push an event through the trace, we need to
// manufacture an event. We can use a RecordBuilder to do this.
var builder = new Testing.RecordBuilder(powershellGuid, 7937, 1);
// For some events, there may be flags that need to be set to
// arcane values. Forcing event schema lookup like this without a
// real event is a little shady anyway, so this is only marginally
// supported by doing something like the following:
// builder.Header.Flags = 102938123908 // some magic number
//
// The magic numbers are often derived by looking at a real event
// in a debugger and setting the Flags to the appropriate values.
// There's nothing that we can really do to make this easier, so
// sorry. :(
// We can add some properties to the builder.
builder.AddUnicodeString("ContextInfo", "Some silly test value here");
builder.AddUnicodeString("Data", "Some other data here");
// We need to pack the property into a record. There are two
// functions that allow this -- Pack and PackIncomplete. Pack
// validates that we've filled all the properties in the schema for
// the event we're composing. PackIncomplete allows us to only fill
// some events and fills with default values the ones we didn't
// bother with.
var packed = builder.PackIncomplete();
// Now that we've got an event, we can push it through the proxy.
proxy.PushEvent(packed);
}
}
}
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to quickly load up a kernel trace that prints out
// a notice whenever a binary image (executable or DLL) is loaded.
using System;
using Microsoft.O365.Security.ETW;
using Kernel = Microsoft.O365.Security.ETW.Kernel;
namespace ManagedExamples
{
public static class KernelTrace001
{
public static void Start()
{
// Kernel traces use the KernelTrace class, which looks and acts
// a lot like the UserTrace class. A strange quirk about kernel
// ETW traces is that prior to Win8, the trace was required to
// have a specific name. On machines where this is the case, this
// name we provide is ignored and the required one is used.
var trace = new KernelTrace("My trace name");
// Lobster provides a bunch of convenience providers for kernel
// traces. The set of providers that are allowed by kernel traces
// is hardcoded by Windows, and Lobster provides simple objects to
// represent these. If other providers were enabled without an
// update to Lobster, the same thing could be achieved with:
// var provider = new KernelProvider(SOME_FLAGS_VALUE, SOME_GUID);
var processProvider = new Kernel.ProcessProvider();
// Kernel providers accept callbacks and event filters, as user
// providers do.
processProvider.OnEvent += (record) =>
{
// We consult against the opcode for kernel providers.
// The opcodes are documented here:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364083(v=vs.85).aspx
if (record.Opcode == 0x01)
{
var image = record.GetAnsiString("ImageFileName", "Unknown");
var pid = record.GetUInt32("ProcessId", 0);
Console.WriteLine($"{image} started with PID {pid}");
}
};
// From here, a KernelTrace is indistinguishable from a UserTrace
// in how it's used.
trace.Enable(processProvider);
// Another quirk here is that kernel traces can only be done by
// administrators. :( :( :(
trace.Start();
}
}
}
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to enable less documented kernel events.
using System;
using Microsoft.O365.Security.ETW;
using Kernel = Microsoft.O365.Security.ETW.Kernel;
namespace ManagedExamples
{
public static class KernelTrace002
{
public static void Start()
{
var trace = new KernelTrace("KernelTrace002");
// Some kernel providers can't be enabled via EnableFlags and you need to call
// TraceSetInformation with an extended PERFINFO_GROUPMASK instead.
// e.g. https://docs.microsoft.com/en-us/windows/win32/etw/obtrace
// Lobster has convenience providers for some of these, but otherwise the same
// thing could be done with:
// var provider = new KernelProvider(SOME_GUID, SOME_MASK_VALUE);
var objectManagerProvider = new Kernel.ObjectManagerProvider();
objectManagerProvider.OnEvent += (record) =>
{
if (record.Opcode == 33)
{
var name = record.GetUnicodeString("ObjectName", string.Empty);
if (name.EndsWith(".dll"))
Console.WriteLine($"Handle closed for object with name {name}");
}
};
trace.Enable(objectManagerProvider);
// You can also set a default callback to handle any events that don't
// have a corresponding provider registered.
// This is helpful if you're not yet sure which provider GUID is required for a
// given EnableFlags or PERFINFO_GROUPMASK. In particualar, the PERFINFO_GROUPMASKs
// aren't documented by Microsoft so it's useful to have a way to receive those events.
// So we enable them with any placeholder guid for now. For example -
uint PERF_REG_HIVE = 0x41000000; // from perfinfo_groupmask.hpp
var hiveProvider = new KernelProvider(Guid.Empty, PERF_REG_HIVE);
// In this case, the correct provider GUID (unsurprisingly) turns out to be krabs::guids::registry :-)
// Though the HiveInit/HiveLink/HiveDirty/Counters events enabled aren't documented.
//
// You'll also likely receive the EventTrace_Header and any HWConfig events here.
// * https://docs.microsoft.com/en-us/windows/win32/etw/eventtrace-header
// * https://docs.microsoft.com/en-us/windows/win32/etw/hwconfig
trace.SetDefaultEventCallback((record) =>
{
Console.WriteLine($"{record.ProviderId} provider={record.ProviderName} task_name={record.TaskName} opcode={record.Opcode} opcode_name={record.OpcodeName}");
});
trace.Enable(hiveProvider);
trace.Start();
}
}
}
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{32E71DD0-D11A-44DE-8CA8-572995AF2373}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ManagedExamples</RootNamespace>
<AssemblyName>ManagedExamples</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugSigning|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\DebugSigning\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseSigning|AnyCPU'">
<OutputPath>bin\ReleaseSigning\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FakingEvents001.cs" />
<Compile Include="KernelTrace001.cs" />
<Compile Include="KernelTrace002.cs" />
<Compile Include="Program.cs" />
<Compile Include="UserTrace001.cs" />
<Compile Include="UserTrace004.cs" />
<Compile Include="UserTrace003.cs" />
<Compile Include="UserTrace002.cs" />
<Compile Include="UserTrace005.cs" />
<Compile Include="UserTrace006_Rundown.cs" />
<Compile Include="UserTrace007_StackTrace.cs" />
<Compile Include="WppTrace001.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Microsoft.O365.Security.Native.ETW\Microsoft.O365.Security.Native.ETW.vcxproj">
<Project>{ed4e6027-541f-440a-a5ee-15dbb7b89423}</Project>
<Name>O365.Security.Native.ETW</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace ManagedExamples
{
class Program
{
static void Main(string[] args)
{
// Comment in/out the particular example you'd like to run.
KernelTrace001.Start();
//KernelTrace002.Start();
//UserTrace001.Start();
//UserTrace002.Start();
//UserTrace003.Start();
//UserTrace004.Start();
//UserTrace005.Start();
//UserTrace006_Rundown.Start();
//UserTrace007_StackTrace.Start();
//FakingEvents001.Start();
//WppTrace001.Start();
}
}
}
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a UserTrace to extract powershell command
// invocations.
using System;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace001
{
public static void Start()
{
// UserTrace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows.
var trace = new UserTrace();
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
// UserTrace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
powershellProvider.Any = Provider.AllBitsSet;
// Providers should be wired up to functions that are called when
// events from that provider are fired.
powershellProvider.OnEvent += (record) =>
{
// Records have general properties that are applicable to every ETW
// record regardless of schema. They give us general information.
Console.WriteLine("Event " + record.Id + " (" + record.Name + ") received.");
if (record.Id == 7937)
{
// We need to call the specific method to parse the type we expect.
// If we don't want to deal with the possibility of failure, we can
// provide a default if parsing fails.
var context = record.GetUnicodeString("ContextInfo", "None.");
Console.WriteLine("Context: " + context);
}
};
// The UserTrace needs to know about the provider that we've set up.
trace.Enable(powershellProvider);
// Begin listening for events. This call blocks, so if you want to do other things
// while this runs, you'll need to call this on another thread.
trace.Start();
}
}
}
@@ -0,0 +1,77 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace to extract powershell command
// invocations. It demonstrates provider-level filtering to make event handling
// code a little simpler.
using System;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace002
{
public static void Start()
{
// UserTrace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
var trace = new UserTrace("Silly Gooby");
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
// UserTrace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
powershellProvider.Any = Provider.AllBitsSet;
// In user_trace_001.cs, we manually filter events by checking the information
// in our callback functions. In this example, we're going to use a provider
// filter to do this for us.
// We instantiate an EventFilter first. An EventFilter is created with a predicate --
// literally just a function that does some check on an EventRecord and returns a boolean
// (true when the even should be passed on to callbacks, false otherwise).
// EventFilters are more than just convenient -- Lobster provides combinators for
// expressing simple but powerful filters that actually execute in the underlying C++
// krabs library. This means that events can be filtered before ever running in the
// CLR (saving us a ton of cost in spinning up objects on event firing).
// The combinators cannot express everything a filter must do, so for complicated
// filters, it's recommended to write the filters in a managed C++/CLI project and
// use those to keep the perf benefits. The filters that Lobster provides are on
// the Filter object (and can be combined with &&, ||, !)
var filter = new EventFilter(Filter.EventIdIs(7937));
// EventFilters have attached callbacks, just like a regular provider.
filter.OnEvent += (record) =>
{
System.Diagnostics.Debug.Assert(record.Id == 7937);
Console.WriteLine("Event 7937 received");
};
filter.OnError += (error) =>
{
Console.WriteLine($"Filter error: {error.Record.Id} {error.Message}");
};
powershellProvider.OnError += (error) =>
{
Console.WriteLine($"Provider error: {error.Record.Id} {error.Message}");
};
// EventFilters are attached to providers. Events that are attached to the filter
// will only be called when the filter allows the event through. Any events attached
// to the provider directly will be called for all events that are fired by the ETW
// producer.
powershellProvider.AddFilter(filter);
trace.Enable(powershellProvider);
trace.Start();
}
}
}
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace to extract powershell command
// invocations. It uses event ID filtering built in to ETW for improved performance.
using System;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace003
{
public static void Start()
{
// UserTrace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
var trace = new UserTrace();
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
// UserTrace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
powershellProvider.Any = Provider.AllBitsSet;
// In UserTrace002.cs, we use predicate-based filtering to only emit events
// for a specific event id.
//
// Alternatively, we can use ETW-based filtering which is even more performant.
var filter = new EventFilter(7937);
// EventFilters have attached callbacks, just like a regular provider.
filter.OnEvent += (record) =>
{
System.Diagnostics.Debug.Assert(record.Id == 7937);
Console.WriteLine("Event 7937 received");
};
// EventFilters are attached to providers. Events that are attached to the filter
// will only be called when the filter allows the event through. Any events attached
// to the provider directly will be called for all events that are fired by the ETW
// producer.
powershellProvider.AddFilter(filter);
trace.Enable(powershellProvider);
trace.Start();
}
}
}
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace to extract powershell command
// invocations. It combines predicate-based and ETW-native filtering.
using System;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace004
{
public static void Start()
{
// UserTrace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
var trace = new UserTrace();
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
// UserTrace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
powershellProvider.Any = Provider.AllBitsSet;
// In UserTrace003.cs, we use ETW-based filtering to select a specific event ID.
//
// We can combine ETW-based filtering with predicate filters to filter on specific
// event properties without impacting performance.
var filter = new EventFilter(7937, UnicodeString.Contains("ContextInfo", "Write-Host"));
// EventFilters have attached callbacks, just like a regular provider.
filter.OnEvent += (record) =>
{
System.Diagnostics.Debug.Assert(record.Id == 7937);
Console.WriteLine(record.GetUnicodeString("ContextInfo"));
};
// EventFilters are attached to providers. Events that are attached to the filter
// will only be called when the filter allows the event through. Any events attached
// to the provider directly will be called for all events that are fired by the ETW
// producer.
powershellProvider.AddFilter(filter);
trace.Enable(powershellProvider);
trace.Start();
}
}
}
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a UserTrace to the monitor Microsoft-Windows-Security-Auditing events
// that populate the Security EventLog.
// This is a special case due to additional security on this provider.
using System;
using System.Security.Principal;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace005
{
public static void Start()
{
// While Adminstrator is sufficent to view the Security EventLog,
// SYSTEM is required for the Microsoft-Windows-Security-Auditing provider.
if (!WindowsIdentity.GetCurrent().IsSystem)
{
Console.WriteLine("Microsoft-Windows-Security-Auditing can only be traced by SYSTEM");
return;
}
// Further, only one trace session is allowed for this provider.
// This session is created by the OS and is called 'EventLog-Security'.
// We can't Stop this session, but we can Open a handle to it.
var trace = new UserTrace("EventLog-Security");
var provider = new Provider("Microsoft-Windows-Security-Auditing");
// We also can't modify the flags of the trace session.
// This will silently fail.
provider.Any = Provider.AllBitsSet;
// But we can receive events - but only those configured by the audit policy.
// e.g. to enable event 4703 run -> auditpol /set /subcategory:"Token Right Adjusted Events"
provider.OnEvent += (record) =>
{
Console.WriteLine($"Event {record.Id}({record.Name}) received.");
if (record.Id == 4703) // "A user right was adjusted."
{
var enabledPrivilegeList = record.GetUnicodeString("EnabledPrivilegeList", "");
var disabledPrivilegeList = record.GetUnicodeString("DisabledPrivilegeList", "");
Console.WriteLine($"\tEnabledPrivilegeList={enabledPrivilegeList}");
Console.WriteLine($"\tDisabledPrivilegeList={disabledPrivilegeList}");
}
};
trace.Enable(provider);
trace.Start();
}
}
}
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example demonstrates rundown events that capture system state.
using System;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace006_Rundown
{
public static void Start()
{
var trace = new UserTrace("UserTrace006_Rundown");
// Rundown events are not true real-time tracing events. Instead they describe the state of the system.
// Usually these are just extra events in the provider. For example, Microsoft-Windows-Kernel-Process
// has ProcessRundown events as well as ProcessStart events.
var provider = new Provider("Microsoft-Windows-Kernel-Process");
provider.Any = 0x10; // WINEVENT_KEYWORD_PROCESS
// ...but the rundown events often cannot be enabled by keyword alone.
// The trace needs to be sent EVENT_CONTROL_CODE_CAPTURE_STATE.
// This is what EnableRundownEvents() does.
provider.EnableRundownEvents();
// real-time process start events
var processFilter = new EventFilter(Filter.EventIdIs(1)); // ProcessStart
processFilter.OnEvent += ProcessEventHandler;
provider.AddFilter(processFilter);
// process rundown events - i.e. running processes
var processRundownFilter = new EventFilter(Filter.EventIdIs(15)); // ProcessRundown
processRundownFilter.OnEvent += ProcessEventHandler;
provider.AddFilter(processRundownFilter);
trace.Enable(provider);
trace.Start();
}
private static void ProcessEventHandler(IEventRecord record)
{
var pid = record.GetUInt32("ProcessID");
var imageName = record.GetUnicodeString("ImageName");
Console.WriteLine($"{record.TaskName} pid={pid} ImageName={imageName}");
}
}
}
@@ -0,0 +1,339 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example demonstrates collecting stack traces as part of events.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using Microsoft.O365.Security.ETW;
using Microsoft.Win32.SafeHandles;
namespace ManagedExamples
{
public static class UserTrace007_StackTrace
{
public static void Start()
{
if (!(new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)))
{
Console.WriteLine("Microsoft-Windows-Kernel-* providers can only be traced by Administrators");
return;
}
var trace = new UserTrace("UserTrace007_StackTrace");
var provider = new Provider("Microsoft-Windows-Kernel-Audit-API-Calls");
provider.TraceFlags |= TraceFlags.IncludeStackTrace;
var processFilter = new EventFilter(Filter.EventIdIs(5)); // PsOpenProcess
processFilter.OnEvent += (record) =>
{
var processId = record.ProcessId;
var targetProcessId = record.GetUInt32("TargetProcessId");
if (processId == targetProcessId)
return; // ignore OpenProcess(*, self)
var desiredAccess = record.GetUInt32("DesiredAccess");
if (desiredAccess == (uint)ProcessAccessRights.QUERY_LIMITED_INFORMATION)
return; // ignore OpenProcess(QUERY_LIMITED_INFORMATION, *)
if (0 != record.GetUInt32("ReturnCode"))
return; // ignore failures
var callStack = record.GetStackTrace()
.Select(a => a.ToUInt64())
.Where(a => a < 0xFFFF000000000000) // skip kernel addresses (for now)
.Select(a => MemoryMap.GetClosestSymbol(processId, a));
Console.WriteLine($"{MemoryMap.GetProcessName(processId)} -> ntoskrnl!PsOpenProcess({ToString(desiredAccess)}, {MemoryMap.GetProcessName(targetProcessId)})\n" +
$"\t[{String.Join(",", callStack)}]");
};
provider.AddFilter(processFilter);
////////////////////////////////////////////////////////////////////////////////
// Microsoft-Windows-Kernel-Process
// These events are used to enrich our call stacks
var processProvider = new Provider("Microsoft-Windows-Kernel-Process")
{
Any = 0x10 | 0x40 // WINEVENT_KEYWORD_PROCESS | WINEVENT_KEYWORD_IMAGE
};
// Event 5 - ImageLoad
var imageLoadFilter = new EventFilter(Filter.EventIdIs(5));
imageLoadFilter.OnEvent += (record) => {
var processID = record.GetUInt32("ProcessID");
var imageBase = BitConverter.ToUInt64(record.GetBinary("ImageBase"), 0); // C# support for Pointer type in krabs?
var imageSize = BitConverter.ToUInt64(record.GetBinary("ImageSize"), 0);
var imageName = Path.GetFileNameWithoutExtension(record.GetUnicodeString("ImageName"));
MemoryMap.AddModule(processID, imageBase, imageSize, imageName);
};
// Event 2 - ProcessStop
var processStopFilter = new EventFilter(Filter.EventIdIs(2));
processStopFilter.OnEvent += (record) => {
MemoryMap.RemoveProcess(record.ProcessId);
};
processProvider.AddFilter(imageLoadFilter);
processProvider.AddFilter(processStopFilter);
trace.Enable(processProvider);
MemoryMap.Initialise();
trace.Enable(provider);
trace.Start();
}
enum ProcessAccessRights : uint
{
TERMINATE = 0x1,
CREATE_THREAD = 0x2,
SET_SESSIONID = 0x4,
VM_OPERATION = 0x8,
VM_READ = 0x10,
VM_WRITE = 0x20,
DUP_HANDLE = 0x40,
CREATE_PROCESS = 0x80,
SET_QUOTA = 0x100,
SET_INFORMATION = 0x200,
QUERY_INFORMATION = 0x400,
SUSPEND_RESUME = 0x800,
QUERY_LIMITED_INFORMATION = 0x1000,
DELETE = 0x10000,
READ_CONTROL = 0x20000,
WRITE_DAC = 0x40000,
WRITE_OWNER = 0x80000,
SYNCHRONIZE = 0x100000
}
internal static string ToString(uint desiredAccess)
{
if (desiredAccess == 0x1FFFFF)
return "ALL_ACCESS";
if (desiredAccess == 0x1F0FFF)
return "ALL_ACCESS(XP)";
var rights = new List<string>();
foreach (uint right in Enum.GetValues(typeof(ProcessAccessRights)))
{
if ((desiredAccess & right) == right)
rights.Add(Enum.GetName(typeof(ProcessAccessRights), right));
}
return string.Join("|", rights);
}
}
/// ETW call stacks are simply a list of return addresses. These can be enriched with module or symbol information after the fact.
/// You could open a handle to the process and request module or symbol information in the usual fashion.
/// However, the process may have stopped.
/// Instead, this class maintains a map of all shared modules and additionally resolves symbols in its own address space.
/// It assumes normal system behaviour - the presence of security software or malware may invalidate this.
/// It also assumes a 64KB allocation granularity.
public class MemoryMap
{
// A cache of process names
private static readonly Dictionary<UInt64, string> _ProcessNameMap = new Dictionary<UInt64, string>();
// A map of the 64KB regions allocated to shared DLLs
private static readonly Dictionary<UInt64, string> _SharedDllMap = new Dictionary<UInt64, string>();
// A per-process map of the 64KB regions allocated to other loaded images.
// Typically the executable (though this can be shared in special cases) and any DLLs unable to be loaded at the preferred shared address.
// For example, a trampoline for an inline hook may have been manually allocated in the shared range.
private static readonly Dictionary<uint, Dictionary<UInt64, string>> _LocalImageMap = new Dictionary<uint, Dictionary<UInt64, string>>();
// GetCurrentProcess()
private static readonly SafeProcessHandle CurrentProcess = new SafeProcessHandle(new IntPtr(-1), false);
// The kernel preferentially uses these two ranges to load DLLs at shared addresses
// Note - this is not 100% accurate as the WoW64 range only applies to WoW64 processes
internal static bool IsInSystemImageRange(UInt64 address)
{
return ((address >= 0x7FF800000000) && (address < 0x7FFFFFFF0000)) || // x64 range
((address >= 0x50000000) && (address < 0x78000000)); // WoW64 range
}
public static void Initialise()
{
// intialise symbols in the current process
SymSetOptions(0x800006); // SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_UNDNAME
if (!SymInitialize(CurrentProcess, null, true))
{
throw new ApplicationException($"SymInitialize(CurrentProcess) failed - error=0x{(uint)Marshal.GetLastWin32Error():x}");
}
// enumerate loaded modules to pre-populate our maps
foreach (Process process in Process.GetProcesses())
{
uint pid = (uint)process.Id;
try
{
var imageBase = Convert.ToUInt64(process.MainModule.BaseAddress.ToInt64());
var imageSize = Convert.ToUInt64(process.MainModule.ModuleMemorySize);
var imageName = Path.GetFileNameWithoutExtension(process.MainModule.ModuleName);
_ProcessNameMap[pid] = process.ProcessName;
if (!_LocalImageMap.ContainsKey(pid))
{
_LocalImageMap[pid] = new Dictionary<UInt64, string>();
}
for (var va = imageBase; va < imageBase + imageSize; va += 64 * 1024)
{
_LocalImageMap[pid][va] = imageName;
}
foreach (ProcessModule module in process.Modules)
{
imageBase = Convert.ToUInt64(module.BaseAddress.ToInt64());
imageSize = Convert.ToUInt64(module.ModuleMemorySize);
imageName = Path.GetFileNameWithoutExtension(module.ModuleName);
if (IsInSystemImageRange(imageBase))
{
for (var va = imageBase; va < imageBase + imageSize; va += 64 * 1024)
{
_SharedDllMap[va] = imageName;
}
}
else
{
for (var va = imageBase; va < imageBase + imageSize; va += 64 * 1024)
{
_LocalImageMap[pid][va] = imageName;
}
}
}
}
catch (Win32Exception) { } // insufficient privilege
catch (InvalidOperationException) { } // process has stopped
}
}
public static void AddModule(uint pid, UInt64 imageBase, UInt64 imageSize, string imageName)
{
if (IsInSystemImageRange(imageBase))
{
for (var va = imageBase; va < imageBase + imageSize; va += 64 * 1024)
{
_SharedDllMap[va] = imageName;
}
}
else
{
// This method of identifying the executable name is not robust :-)
if (imageName.EndsWith(".exe"))
{
_ProcessNameMap[pid] = imageName;
}
if (!_LocalImageMap.ContainsKey(pid))
{
_LocalImageMap[pid] = new Dictionary<UInt64, string>();
}
for (var va = imageBase; va < imageBase + imageSize; va += 64 * 1024)
{
_LocalImageMap[pid][va] = imageName;
}
}
}
public static void RemoveProcess(uint pid)
{
_LocalImageMap.Remove(pid);
_ProcessNameMap.Remove(pid);
}
public static string GetProcessName(uint pid)
{
return _ProcessNameMap.ContainsKey(pid) ? _ProcessNameMap[pid] : $"pid:{pid}";
}
public static string GetModuleName(uint pid, UInt64 address)
{
address &= ~0xFFFFul; // align to default allocation granularity (64K)
if (IsInSystemImageRange(address) && _SharedDllMap.ContainsKey(address))
return _SharedDllMap[address];
if (_LocalImageMap.ContainsKey(pid) && _LocalImageMap[pid].ContainsKey(address))
return _LocalImageMap[pid][address];
// This could be a module loaded before we started, or a call from private memory such as JIT or shellcode.
return IsInSystemImageRange(address) ? "[Image]" : "[Private]";
}
public static string GetClosestSymbol(uint pid, UInt64 address)
{
var symbolInfo = new SYMBOL_INFO
{
SizeOfStruct = SIZE_OF_SYMBOL_INFO,
MaxNameLen = MAX_SYMBOL_LENGTH
};
if (!SymFromAddr(CurrentProcess, address, out _, ref symbolInfo))
{
return GetModuleName(pid, address);
}
if (symbolInfo.NameLen > MAX_SYMBOL_LENGTH)
throw new ApplicationException($"SymFromAddr() buffer too small");
return $"{GetModuleName(pid, address)}!{symbolInfo.Name.Split('<')[0]}"; // strip decorations
}
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions
[DllImport("Dbghelp.dll")]
public static extern int SymSetOptions(
int SymOptions);
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize
[DllImport("Dbghelp.dll", SetLastError = true)]
public static extern bool SymInitialize(
SafeProcessHandle hProcess,
StringBuilder UserSearchPath,
bool fInvadeProcess);
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/ns-dbghelp-symbol_info
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SYMBOL_INFO
{
public UInt32 SizeOfStruct;
public UInt32 TypeIndex;
public UInt64 Reserved;
public UInt64 Reserved2;
public UInt32 Index;
public UInt32 Size;
public UInt64 ModBase;
public UInt32 Flags;
public UInt64 Value;
public UInt64 Address;
public UInt32 Register;
public UInt32 Scope;
public UInt32 Tag;
public UInt32 NameLen;
public UInt32 MaxNameLen;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] // hardcoded for convenience - not robust
public string Name;
}
private static readonly UInt32 MAX_SYMBOL_LENGTH = 128;
private static readonly UInt32 SIZE_OF_SYMBOL_INFO = (uint)(Marshal.SizeOf(new SYMBOL_INFO()) - MAX_SYMBOL_LENGTH);
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symfromaddr
[DllImport("Dbghelp.dll", SetLastError = true)]
public static extern bool SymFromAddr(
SafeProcessHandle hProcess,
UInt64 Address,
out UInt64 Displacement,
ref SYMBOL_INFO Symbol);
}
}
@@ -0,0 +1,154 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a UserTrace to monitor WPP providers.
// This is a special case due to slight differences in the event format,
// and the lack of schema information.
using System;
using System.Runtime.InteropServices;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class WppTrace001
{
public static void Start()
{
var trace = new UserTrace("WPP_OLE32");
// WPP providers are basically legacy providers without a registered MOF.
// They are intended for (internal) debugging purposes only.
// Note - WPP software tracing has been superceded by TraceLogging.
//
// Instead of a manifest or MOF, a separate trace message format (TMF)
// file is required to interpret the WPP event data.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/trace-message-format-file
//
// In some cases, the TMF is included in the PDB.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/tracepdb
//
// Otherwise, you can attempt to reconstruct the TMF by hand.
// https://posts.specterops.io/data-source-analysis-and-dynamic-windows-re-using-wpp-and-tracelogging-e465f8b653f7
//
// Luckily, WPP tracing is usually added using Microsoft's convenience macros.
// And, when you have symbols available, WPP metadata is then fairly straightfoward to extract.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/adding-wpp-software-tracing-to-a-windows-driver
// Each WPP trace provider defines a control GUID that uniquely identifies that provider.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/control-guid
//
// The WPP macros generate control GUID globals named "WPP_ThisDir_CTLGUID_<name>"
//
// For example, this control GUID is in the symbols for combase.dll
// WPP_ThisDir_CTLGUID_OLE32 = bda92ae8-9f11-4d49-ba1d-a4c2abca692e
var ole32WppProvider = new Provider(Guid.Parse("{bda92ae8-9f11-4d49-ba1d-a4c2abca692e}"));
// In evntrace.h there are ten defined trace levels -
// TRACE_LEVEL_NONE 0 // Tracing is not on
// TRACE_LEVEL_CRITICAL 1 // Abnormal exit or termination
// TRACE_LEVEL_ERROR 2 // Severe errors that need logging
// TRACE_LEVEL_WARNING 3 // Warnings such as allocation failure
// TRACE_LEVEL_INFORMATION 4 // Includes non-error cases(e.g.,Entry-Exit)
// TRACE_LEVEL_VERBOSE 5 // Detailed traces from intermediate steps
// TRACE_LEVEL_RESERVED6 6
// TRACE_LEVEL_RESERVED7 7
// TRACE_LEVEL_RESERVED8 8
// TRACE_LEVEL_RESERVED9 9
//
// Microsoft WPP providers are known to use the reserved levels.
// Internally, these levels have names like CHATTY, GARRULOUS and LOQUACIOUS.
//
// Everything at or below the configured level will be traced.
// Technically 9 means trace everything, but the field is a UCHAR
// so 0xFF means definitely trace everything.
ole32WppProvider.Level = 0xFF; // 'TRACE_LEVEL_ALL'
// Flags is a user-defined bitmask field the developer can use to group
// related messages.
// Again, it is a UCHAR for WPP providers so 0xFF means trace everything.
ole32WppProvider.Any = 0xFF; // 'TRACE_FLAGS_ALL'
// We need to enable this provider in order for krabs to correctly enable the OLE32 WPP events.
trace.Enable(ole32WppProvider);
// But we can't add any callbacks directly to krabs WPP providers though. Without the TMF
// information, krabs cannot determine which provider the event belongs to.
//
// WPP providers, like MOF providers, return the message GUID in the ProviderId field.
// So firstly krabs checks if the message GUID matches a provider GUID.
// If you know the message GUIDs then you can create individual dummy providers for those.
//
// Secondly krabs queries TDH to see if it knows the provider GUID for the message GUID.
// https://docs.microsoft.com/en-us/windows/win32/etw/retrieving-event-data-using-tdh
// This works for registered MOF providers - but not for WPP providers. In this case, TDH returns
// an all zero GUID - so we can create a dummy provider for that and add our callbacks there instead.
// If you subscribe to multiple WPP providers, the events from *all* of them will be delivered to this dummy provider.
var allWppDummyProvider = new Provider(Guid.Empty);
allWppDummyProvider.OnEvent += (record) =>
{
// Here be dragons.
//
// krabs does not currently support TMF files for parsing WPP messages.
// Instead you need to manually parse the UserData.
//
// The WPP macros generate message GUID globals named "WPP_<guid>_Traceguids"
// They also generate logging staging functions named "WPP_SF_<format specifiers>"
//
// There seems to be a one-to-one mapping between message GUIDs and staging functions.
// WPP events are a slightly different format to the modern ETW events. In particular,
// they include this message GUID rather than the provider's control GUID.
//
// So message GUIDs would be a good candidate for filtering...
// ... but my experience is that they may change between builds.
// So I've subscribed to the zero GUID instead.
//
// Event ids seem more stable, but they are only unique per message GUID.
//
// In this case, combase.dll only has two logging staging functions.
// WPP_SF_S(...) - which tells us that the event contains a single unicode string.
// WPP_SF_ssdDsS(...) - which tells us that there are 3 ansi strings, a unicode string and dword.
//
// So we can brute force the format...
var message = $"Message:{record.ProviderId} Id:{record.Id} ";
var userData = record.UserData;
var string_1 = Marshal.PtrToStringAnsi(record.UserData);
if (string_1.Length != 1) // definitely an ansi string...
{
// WPP_SF_ssdDsS(...)
userData += string_1.Length + 1;
var string_2 = Marshal.PtrToStringAnsi(userData);
userData += string_2.Length + 1;
var int32_3 = Marshal.ReadInt32(userData);
userData += sizeof(Int32);
var uint32_4 = (UInt32)Marshal.ReadInt32(userData);
userData += sizeof(UInt32);
var string_5 = Marshal.PtrToStringAnsi(userData);
userData += string_5.Length + 1;
var string_6 = Marshal.PtrToStringUni(userData);
message += $"WPP_SF_ssdDsS({string_1}, {string_2}, {int32_3}, {uint32_4}, {string_5}, {string_6})";
}
else // probably a unicode string... (but possibly a single character ansi string)
{
// WPP_SF_S(...)
string_1 = Marshal.PtrToStringUni(record.UserData);
message += $"WPP_SF_S({string_1})";
}
// In this example we only print messages that contain COM class ids.
if (message.Contains(" clsid"))
Console.WriteLine(message);
};
trace.Enable(allWppDummyProvider);
// Side note - if you want to turn up the verbosity of your COM WPP diagnostic tracing, then enable
// OLE32 tracing via the registry following the instruction here -
// https://support.microsoft.com/en-us/help/926098/how-to-enable-com-and-com-diagnostic-tracing
//
// Alternatively call _ControlTracing (4) via combase's 18f70770-8e64-11cf-9af1-0020af6e72f4 RPC interface.
trace.Start();
}
}
}
@@ -0,0 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugSigning|x64">
<Configuration>DebugSigning</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseSigning|x64">
<Configuration>ReleaseSigning</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D31B1A4B-8282-4AED-99FC-9AA5974B9134}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>NativeExamples</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WINVER=0x0601;_WIN32_WINNT=0x601;TYPEASSERT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TreatWarningAsError>true</TreatWarningAsError>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugSigning|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WINVER=0x0601;_WIN32_WINNT=0x601;TYPEASSERT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TreatWarningAsError>true</TreatWarningAsError>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WINVER=0x0601;_WIN32_WINNT=0x601;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseSigning|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WINVER=0x0601;_WIN32_WINNT=0x601;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="kernel_trace_002.cpp" />
<ClCompile Include="kernel_trace_003_rundown.cpp" />
<ClCompile Include="user_trace_005.cpp" />
<ClCompile Include="kernel_and_user_trace_001.cpp" />
<ClCompile Include="kernel_trace_001.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="multiple_providers_001.cpp" />
<ClCompile Include="testing_001.cpp" />
<ClCompile Include="user_trace_001.cpp" />
<ClCompile Include="user_trace_002.cpp" />
<ClCompile Include="user_trace_003_no_predicates.cpp" />
<ClCompile Include="user_trace_004.cpp" />
<ClCompile Include="user_trace_006_predicate_vectors.cpp" />
<ClCompile Include="user_trace_007_rundown.cpp" />
<ClCompile Include="user_trace_008_stacktrace.cpp" />
<ClCompile Include="user_trace_009_from_file.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{ed21b70b-78a2-4617-a02f-9b654e2bd586}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="kernel_and_user_trace_001.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kernel_trace_001.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="multiple_providers_001.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="testing_001.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_001.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_002.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_003_no_predicates.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_004.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_005.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_006_predicate_vectors.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kernel_trace_002.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_007_rundown.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kernel_trace_003_rundown.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_008_stacktrace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="user_trace_009_from_file.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
struct kernel_and_user_trace_001
{
static void start();
};
struct kernel_trace_001
{
static void start();
};
struct kernel_trace_002
{
static void start();
};
struct kernel_trace_003_rundown
{
static void start();
};
struct multiple_providers_001
{
static void start();
};
struct testing_001
{
static void start();
};
struct user_trace_001
{
static void start();
};
struct user_trace_002
{
static void start();
};
struct user_trace_003_no_predicates
{
static void start();
};
struct user_trace_004
{
static void start();
};
struct user_trace_005
{
static void start();
};
struct user_trace_006_predicate_vectors
{
static void start();
};
struct user_trace_007_rundown
{
static void start();
};
struct user_trace_008_stacktrace
{
static void start();
};
struct user_trace_009_from_file
{
static void start();
};
@@ -0,0 +1,108 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace and a kernel_trace in the same program.
#include <iostream>
#include <thread>
#include <condition_variable>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
static void setup_ps_provider(krabs::provider<>& provider);
static void setup_image_load_provider(krabs::kernel::image_load_provider& provider);
void kernel_and_user_trace_001::start()
{
// user_trace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. You can have multiple ETW traces in a given
// program but each trace object will consume one thread.
krabs::user_trace user;
krabs::kernel_trace kernel;
// A trace can have any number of providers, which are identified by GUID or
// a specific trace name.
//
// The GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil or Microsoft Message Analyzer).
krabs::provider<> ps_provider(krabs::guid(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
krabs::kernel::image_load_provider image_load_provider;
setup_ps_provider(ps_provider);
setup_image_load_provider(image_load_provider);
// The user_trace needs to know about the provider that we've set up.
// You can assign multiple providers to a single trace.
user.enable(ps_provider);
kernel.enable(image_load_provider);
// Begin listening for events. This call blocks, so if you want to do other things
// while this runs, you'll need to call this on another thread.
//
// Additionally, if multiple threads are enabling providers with a single trace object,
// you'll need to synchronize the call to start. Because 'start' is a blocking call,
// it will prevent any other thread from enabling additional providers.
std::thread user_thread([&user]() { user.start(); });
std::thread kernel_thread([&kernel]() { kernel.start(); });
// Let the traces process for 30 seconds.
std::cout << "starting traces..." << std::endl;
Sleep(10000);
std::cout << "stopping traces..." << std::endl;
user.stop();
kernel.stop();
user_thread.join();
kernel_thread.join();
}
void setup_ps_provider(krabs::provider<>& provider)
{
// user_trace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
provider.any(0xf0010000000003ff);
// providers should be wired up with functions (or functors) that are called when
// events from that provider are fired.
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
// Once an event is received, if we want krabs to help us analyze it, we need
// to snap in a schema to ask it for information.
krabs::schema schema(record, trace_context.schema_locator);
// We then have the ability to ask a few questions of the event.
std::wcout << L"Event " << schema.event_id();
std::wcout << L"(" << schema.event_name() << L") received." << std::endl;
if (schema.event_id() == 7937) {
// The event we're interested in has a field that contains a bunch of
// info about what it's doing. We can snap in a parser to help us get
// the property information out.
krabs::parser parser(schema);
// We have to explicitly name the type that we're parsing in a template
// argument.
// We could alternatively use try_parse if we didn't want an exception to
// be thrown in the case of failure.
std::wstring context = parser.parse<std::wstring>(L"ContextInfo");
std::wcout << L"\tContext: " << context << std::endl;
}
});
}
void setup_image_load_provider(krabs::kernel::image_load_provider& provider)
{
// Kernel providers accept all the typical callback mechanisms.
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
// Opcodes can be found on the kernel provider's documentation:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364068(v=vs.85).aspx
if (schema.event_opcode() == 10) {
krabs::parser parser(schema);
std::wstring filename = parser.parse<std::wstring>(L"FileName");
std::wcout << L"Loaded image from file " << filename << std::endl;
}
});
}
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to quickly load up a kernel trace that prints out
// a notice whenever a binary image (executable or DLL) is loaded.
#include <iostream>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void kernel_trace_001::start()
{
// Kernel traces use the kernel_trace class, which looks and acts a lot like the
// user_trace class.
krabs::kernel_trace trace(L"My magic trace");
// Krabs provides a bunch of convenience providers for kernel traces. The set of
// providers that are allowed by kernel traces is hardcoded by Windows ETW, and
// Krabs provides simple objects to represent these. If other providers were
// enabled without krabs being updated, the same thing could be done like so:
// krabs::kernel_provider provider(SOME_ULONG_FLAG_VALUE, SOME_GUID);
krabs::kernel::image_load_provider provider;
// Kernel providers accept all the typical callback mechanisms.
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
// To filter our events, we want to compare against the
// event opcode. For kernel traces, you can consult this page
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364083(v=vs.85).aspx
//
// The documentation specific to the image load provider is here:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364068(v=vs.85).aspx
if (schema.event_opcode() == 10) {
krabs::parser parser(schema);
std::wstring filename = parser.parse<std::wstring>(L"FileName");
std::wcout << L"Loaded image from file " << filename << std::endl;
}
});
// From here on out, a kernel_trace is indistinguishable from a user_trace in how
// it is used.
trace.enable(provider);
trace.start();
}
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to enable less documented kernel events.
#include <iostream>
#include "..\..\krabs\krabs.hpp"
#include "..\..\krabs\krabs\perfinfo_groupmask.hpp"
#include "examples.h"
void kernel_trace_002::start()
{
krabs::kernel_trace trace(L"kernel_trace_002");
// Some kernel providers can't be enabled via EnableFlags and you need to call
// TraceSetInformation with an extended PERFINFO_GROUPMASK instead.
// e.g. https://docs.microsoft.com/en-us/windows/win32/etw/obtrace
// Krabs has convenience providers for some of these, but otherwise the same
// thing could be done with:
// krabs::kernel_provider provider(SOME_GUID, SOME_ULONG_MASK_VALUE);
krabs::kernel::object_manager_provider ob_provider;
ob_provider.add_on_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
if (record.EventHeader.EventDescriptor.Opcode == 33) {
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
std::wstring name = parser.parse<std::wstring>(L"ObjectName");
if (name.length() >= 3 && name.compare(name.length() - 3, 3, L"dll") == 0)
std::wcout << L"Handle closed for object with name " << name << std::endl;
}
});
trace.enable(ob_provider);
// You can also set a default callback to handle any events that don't
// have a corresponding provider registered.
// This is helpful if you're not yet sure which provider GUID is required for a
// given EnableFlags or PERFINFO_GROUPMASK. In particualar, the PERFINFO_GROUPMASKs
// aren't documented by Microsoft so it's useful to have a way to receive those events.
// So we enable them with any placeholder guid for now. For example -
krabs::kernel_provider hive_provider(GUID_NULL, PERF_REG_HIVE);
// In this case, the correct provider GUID (unsurprisingly) turns out to be krabs::guids::registry :-)
// Though the HiveInit/HiveLink/HiveDirty/Counters events enabled by this aren't documented.
//
// You'll also likely receive the EventTrace_Header and any HWConfig events here.
// * https://docs.microsoft.com/en-us/windows/win32/etw/eventtrace-header
// * https://docs.microsoft.com/en-us/windows/win32/etw/hwconfig
trace.set_default_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
std::wcout << std::to_wstring(record.EventHeader.ProviderId);
std::wcout << L" provider=" << schema.provider_name();
std::wcout << L" event_name=" << schema.event_name();
std::wcout << L" task_name=" << schema.task_name();
std::wcout << L" opcode=" << schema.event_opcode();
std::wcout << L" opcode_name=" << schema.opcode_name();
std::wcout << std::endl;
});
trace.enable(hive_provider);
trace.start();
}
@@ -0,0 +1,115 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to collect kernel rundown events that capture system state.
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
#include <evntrace.h>
#include <iostream>
#include <thread>
#define PRINT_LIMIT 3 // only print a few events for brevity
void process_rundown_callback(const EVENT_RECORD& record, const krabs::trace_context& trace_context);
void file_rundown_callback(const EVENT_RECORD& record, const krabs::trace_context& trace_context);
void hwconfig_callback(const EVENT_RECORD& record, const krabs::trace_context& trace_context);
void kernel_trace_003_rundown::start()
{
krabs::kernel_trace trace(L"kernel_trace_003_rundown");
// The kernel provider has a number of events that report system state.
// Process rundown events - i.e. running processes
// https://docs.microsoft.com/en-us/windows/win32/etw/process
// If the EVENT_TRACE_FLAG_PROCESS is enabled -
// By default, the process provider emits DCStart rundown events at the *start* of the trace.
// By default, the process provider emits DCEnd rundown events at the *end* of the trace.
krabs::kernel::process_provider process_provider;
process_provider.add_on_event_callback(process_rundown_callback);
trace.enable(process_provider);
// File rundown events - i.e. open files
// https://docs.microsoft.com/en-us/windows/win32/etw/fileio
// If the EVENT_TRACE_FLAG_DISK_FILE_IO is enabled -
// By default, the process provider emits file rundown events at the *end* of the trace.
krabs::kernel::disk_file_io_provider fileio_provider;
fileio_provider.add_on_event_callback(file_rundown_callback);
trace.enable(fileio_provider);
// Hardware configuration events
// https://docs.microsoft.com/en-us/windows/win32/etw/hwconfig
// By default, kernel traces emit these events at the *end* of the trace.
// No EnableFlags are required.
krabs::kernel_provider hwconfig_provider(0, krabs::guids::event_trace_config);
hwconfig_provider.add_on_event_callback(hwconfig_callback);
trace.enable(hwconfig_provider);
// We will start and stop a trace to also trigger events that are only emitted at the *end* of a trace.
std::cout << " - starting trace" << std::endl;
std::thread thread([&trace]() { trace.start(); });
// We will wait for all start events to be processed.
// By default ETW buffers are flush when full, or every second otherwise
Sleep(1500);
std::cout << std::endl << " - stopping trace" << std::endl;
trace.stop();
thread.join();
}
void process_rundown_callback(const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
static int process_dcstart_count = 0;
static int process_dcstop_count = 0;
if (record.EventHeader.EventDescriptor.Opcode == 3 || record.EventHeader.EventDescriptor.Opcode == 4) {
krabs::schema schema(record, trace_context.schema_locator);
if ((record.EventHeader.EventDescriptor.Opcode == 3 && process_dcstart_count++ < PRINT_LIMIT) ||
(record.EventHeader.EventDescriptor.Opcode == 4 && process_dcstop_count++ < PRINT_LIMIT)) {
std::wcout << schema.task_name() << L"_" << schema.opcode_name();
std::wcout << L" (" << schema.event_opcode() << L") ";
krabs::parser parser(schema);
std::uint32_t pid = parser.parse<std::uint32_t>(L"ProcessId");
std::wcout << L" ProcessId=" << pid;
std::string imagefilename = parser.parse<std::string>(L"ImageFileName");
std::cout << " ImageFileName=" << imagefilename;
std::wcout << std::endl;
}
if (process_dcstart_count == PRINT_LIMIT || process_dcstop_count == PRINT_LIMIT)
std::wcout << schema.task_name() << L"_" << schema.opcode_name() << L"..." << std::endl;
}
}
void file_rundown_callback(const EVENT_RECORD & record, const krabs::trace_context & trace_context) {
static int file_rundown_count = 0;
if (record.EventHeader.EventDescriptor.Opcode == 36) { // FileRundown
krabs::schema schema(record, trace_context.schema_locator);
if (file_rundown_count++ < PRINT_LIMIT) {
std::wcout << schema.task_name() << L"_" << schema.opcode_name();
std::wcout << L" (" << schema.event_opcode() << L") ";
krabs::parser parser(schema);
std::wstring filename = parser.parse<std::wstring>(L"FileName");
std::wcout << L" FileName=" << filename;
std::wcout << std::endl;
}
if (file_rundown_count == PRINT_LIMIT)
std::wcout << schema.task_name() << L"_" << schema.opcode_name() << L"..." << std::endl;
}
}
void hwconfig_callback(const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
// only return some events for brevity
if (record.EventHeader.EventDescriptor.Opcode == 10 || // CPU
record.EventHeader.EventDescriptor.Opcode == 25 || // Platform
record.EventHeader.EventDescriptor.Opcode == 33 || // DeviceFamily
record.EventHeader.EventDescriptor.Opcode == 37) { // Boot Config Info
krabs::schema schema(record, trace_context.schema_locator);
std::wcout << L"task_name=" << schema.task_name();
std::wcout << L" opcode=" << schema.event_opcode();
std::wcout << L" opcode_name=" << schema.opcode_name();
std::wcout << std::endl;
}
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "examples.h"
int main(void)
{
// Comment in/out the particular example you'd like to run.
kernel_and_user_trace_001::start();
//kernel_trace_001::start();
//kernel_trace_002::start();
//kernel_trace_003_rundown::start();
//multiple_providers_001::start();
//testing_001::start();
//user_trace_001::start();
//user_trace_002::start();
//user_trace_003_no_predicates::start();
//user_trace_004::start();
//user_trace_005::start();
//user_trace_006_predicate_vectors::start();
//user_trace_007_rundown::start();
//user_trace_008_stacktrace::start();
//user_trace_009_from_file::start();
}
@@ -0,0 +1,118 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace with multiple providers.
#include <iostream>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
static void setup_ps_provider(krabs::provider<>& provider);
static void setup_wininet_provider(krabs::provider<>& provider);
void multiple_providers_001::start()
{
// user_trace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows.
krabs::user_trace trace;
// A trace can have any number of providers, which are identified by GUID or
// a specific trace name.
//
// The GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil or Microsoft Message Analyzer).
krabs::provider<> ps_provider(krabs::guid(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
krabs::provider<> wininet_provider(L"Microsoft-Windows-WinINet");
setup_ps_provider(ps_provider);
setup_wininet_provider(wininet_provider);
// The user_trace needs to know about the provider that we've set up.
// You can assign multiple providers to a single trace.
trace.enable(ps_provider);
trace.enable(wininet_provider);
// Begin listening for events. This call blocks, so if you want to do other things
// while this runs, you'll need to call this on another thread.
//
// Additionally, if multiple threads are enabling providers with a single trace object,
// you'll need to synchronize the call to start. Because 'start' is a blocking call,
// it will prevent any other thread from enabling additional providers.
trace.start();
}
void setup_ps_provider(krabs::provider<>& provider)
{
// user_trace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
provider.any(0xf0010000000003ff);
// providers should be wired up with functions (or functors) that are called when
// events from that provider are fired.
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
// Once an event is received, if we want krabs to help us analyze it, we need
// to snap in a schema to ask it for information.
krabs::schema schema(record, trace_context.schema_locator);
// We then have the ability to ask a few questions of the event.
std::wcout << L"Event " << schema.event_id();
std::wcout << L"(" << schema.event_name() << L") received." << std::endl;
if (schema.event_id() == 7937) {
// The event we're interested in has a field that contains a bunch of
// info about what it's doing. We can snap in a parser to help us get
// the property information out.
krabs::parser parser(schema);
// We have to explicitly name the type that we're parsing in a template
// argument.
// We could alternatively use try_parse if we didn't want an exception to
// be thrown in the case of failure.
std::wstring context = parser.parse<std::wstring>(L"ContextInfo");
std::wcout << L"\tContext: " << context << std::endl;
}
});
}
void setup_wininet_provider(krabs::provider<>& provider)
{
// user_trace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
provider.all(0x4000000000000000);
// providers should be wired up with functions (or functors) that are called when
// events from that provider are fired.
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
// Once an event is received, if we want krabs to help us analyze it, we need
// to snap in a schema to ask it for information.
krabs::schema schema(record, trace_context.schema_locator);
// We then have the ability to ask a few questions of the event.
std::wcout << L"Event " << schema.event_id();
std::wcout << L"(" << schema.event_name() << L") received." << std::endl;
// We'll filter on only cached and new WinINet requests/responses.
if (schema.event_id() == 1057) {
// The event we're interested in has a field that contains a bunch of
// info about what it's doing. We can snap in a parser to help us get
// the property information out.
krabs::parser parser(schema);
// We have to explicitly name the type that we're parsing in a template
// argument.
// We could alternatively use try_parse if we didn't want an exception to
// be thrown in the case of failure.
auto url = parser.parse<std::string>(L"URL");
auto request_headers = parser.parse<std::string>(L"RequestHeaders");
auto response_headers = parser.parse<std::string>(L"ResponseHeaders");
std::cout << "\tURL: " << url << std::endl;
std::cout << "\t\tRequest Headers: " << request_headers << std::endl;
std::cout << "\t\tResponse Headers: " << response_headers << std::endl;
}
});
}
Binary file not shown.
@@ -0,0 +1,63 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows the event faking functionality krabs offers. This is useful
// for generating fake events that can be used to test client code.
#include <iostream>
#include <cassert>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void testing_001::start()
{
krabs::user_trace trace(L"My Named Trace");
krabs::guid powershell(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
krabs::provider<> powershellProvider(powershell);
powershellProvider.any(0xf0010000000003ff);
powershellProvider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
std::wstring context = parser.parse<std::wstring>(L"ContextInfo");
std::wcout << L"Event called with context " << context << std::endl;
});
trace.enable(powershellProvider);
// Normally, one would call trace.start() to begin listening, but we want
// to test our code without actually starting a trace and listening for an
// event. We kick up a proxy for the user trace to offer us this functionality.
krabs::testing::user_trace_proxy proxy(trace);
// In order to push an event through the trace, we need to manufacture an
// event. We can use record_builder to do this.
krabs::testing::record_builder builder(powershell, krabs::id(7937), krabs::version(1));
// For some events, there may be flags that need to be set to some arcane values. Forcing
// event schema lookup like this without a real event is a little shady anyway, so this
// is only marginally supported by doing something like the following:
// builder.header().Flags = EVENT_HEADER_FLAG_CLASSIC_HEADER
// | EVENT_HEADER_FLAG_64_BIT_HEADER
// | EVENT_HEADER_FLAG_PROCESSOR_INDEX;
//
// These values are often derived by looking at a real event in a debugger and setting
// the Flags to the appropriate values.
// We can add our own property values to the builder.
builder.add_properties()
(L"ContextInfo", L"Some silly test values here")
(L"Data", L"Some other data here");
// We need to pack the property into an EVENT_RECORD structure. There are two functions
// that allow for this -- pack and pack_incomplete. pack validates that we've filled all
// the properties in the schema for the event we're composing. pack_incomplete allows for
// us to only fill some events and default-fills the ones we didn't bother with.
auto record = builder.pack_incomplete();
// Now that we've got an event, we can push it through the trace.
proxy.push_event(record);
}
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace to extract powershell command
// invocations.
#include <iostream>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_001::start()
{
// user_trace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows.
krabs::user_trace trace;
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
krabs::provider<> provider(krabs::guid(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
// user_trace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
provider.any(0xf0010000000003ff);
// providers should be wired up with functions (or functors) that are called when
// events from that provider are fired.
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
// Once an event is received, if we want krabs to help us analyze it, we need
// to snap in a schema to ask it for information.
krabs::schema schema(record, trace_context.schema_locator);
// We then have the ability to ask a few questions of the event.
std::wcout << L"Event " << schema.event_id();
std::wcout << L"(" << schema.event_name() << L") received." << std::endl;
if (schema.event_id() == 7937) {
// The event we're interested in has a field that contains a bunch of
// info about what it's doing. We can snap in a parser to help us get
// the property information out.
krabs::parser parser(schema);
// We have to explicitly name the type that we're parsing in a template
// argument.
// We could alternatively use try_parse if we didn't want an exception to
// be thrown in the case of failure.
std::wstring context = parser.parse<std::wstring>(L"ContextInfo");
std::wcout << L"\tContext: " << context << std::endl;
}
});
// the user_trace needs to know about the provider that we've set up.
trace.enable(provider);
// begin listening for events. This call blocks, so if you want to do other things
// while this runs, you'll need to call this on another thread.
trace.start();
}
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace to extract powershell command
// invocations. It demonstrates provider-level filtering to make event handling
// code a little simpler.
#include <iostream>
#include <cassert>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_002::start()
{
// user_trace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
krabs::user_trace trace(L"My Named Trace");
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
krabs::provider<> provider(krabs::guid(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
provider.any(0xf0010000000003ff);
// In user_trace_001.cpp, we manually filter events by checking the event information
// in our callback functions. In this example, we're going to use a provider filter
// to do this for us.
// We instantiate an event_filter first. An event_filter is created with a
// predicate -- literally just a function that does some check on an EVENT_RECORD
// and returns a boolean -- true when the event should be passed on to callbacks,
// and false otherwise.
// krabs provides a few simple predicates to use to make this a little easier for
// the standard cases. We'll use one of those to filter based on the event id.
krabs::event_filter filter(krabs::predicates::id_is(7937));
// event_filters can have attached callbacks, just like a regular provider.
filter.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
assert(schema.event_id() == 7937);
std::wcout << L"Event 7937 received!" << std::endl;
});
// event_filters are attached to providers. Events that are attached to a filter will
// only be called when the filter allows the event through. Any events attached to the
// provider directly will be called for all events that are fired by the ETW producer.
provider.add_filter(filter);
trace.enable(provider);
trace.start();
}
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Krabs supports provider filtering based on ETW API filtering features.
// This example listening for file delete event.
//
#include <iostream>
#include <cassert>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_003_no_predicates::start()
{
// user_trace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
krabs::user_trace trace(L"My Named Trace");
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
//listen for file events
krabs::provider<> provider(krabs::guid(L"{EDD08927-9CC4-4E65-B970-C2560FB5C289}"));
// In user_trace_001.cpp we manually filter events by checking the event information
// In user_trace_002.cpp we filter events using provider predicates
// In user_trace_003.cpp we filter with ETW filtering only without predicate
// In this example, we're going to use a provider filter based on ETW filtering features
// combined with predicate which does additional filtering
// We instantiate an event_filter first. An event_filter is created with a
// event id which will be forwarded as filter to etw tracing api
krabs::event_filter filter(11);
auto cb = [](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
assert(schema.event_id() == 11);
std::wcout << L"Event " + std::to_wstring(schema.event_id()) + L" received!" << std::endl;
};
filter.add_on_event_callback(cb);
// event_filters are attached to providers. Events that are attached to a filter will
// only be called when the filter allows the event through. Any events attached to the
// provider directly will be called for all events that are fired by the ETW producer.
provider.add_filter(filter);
trace.enable(provider);
trace.start();
}
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Krabs supports provider filtering based on ETW API filtering features.
// This example listening for file delete event together with predicate which we post
// process event id filter with other filtering
//
#include <iostream>
#include <cassert>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_004::start()
{
// user_trace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
krabs::user_trace trace(L"My Named Trace");
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
//listen for file events
krabs::provider<> provider(krabs::guid(L"{EDD08927-9CC4-4E65-B970-C2560FB5C289}"));
// In user_trace_001.cpp we manually filter events by checking the event information
// In user_trace_002.cpp we filter events using provider predicates
// In user_trace_003_no_predicates.cpp we filter with ETW filtering only without predicate
// In this example (user_trace_004), we're going to use both provider filter based on ETW filtering features
// and predicate which does additional filtering
// We instantiate an event_filter first. An event_filter is created with a
// event id which will be forwarded as filter to etw tracing api
// predicate filtering is taking in consideration only system process
krabs::event_filter filter(11, krabs::predicates::process_id_is(4));
auto cb = [](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
assert(schema.event_id() == 11);
assert(schema.process_id() == 4);
std::wcout << L"Event " +
std::to_wstring(schema.event_id()) +
L" received for pid " +
std::to_wstring(schema.process_id()) << std::endl;
};
filter.add_on_event_callback(cb);
// event_filters are attached to providers. Events that are attached to a filter will
// only be called when the filter allows the event through. Any events attached to the
// provider directly will be called for all events that are fired by the ETW producer.
provider.add_filter(filter);
trace.enable(provider);
trace.start();
}
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a UserTrace to the monitor Microsoft-Windows-Security-Auditing events
// that populate the Security EventLog.
// This is a special case due to additional security on this provider.
#include <iostream>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_005::start()
{
// While Adminstrator is sufficent to view the Security EventLog,
// SYSTEM is required for the Microsoft-Windows-Security-Auditing provider.
char user_name[128] = { 0 };
DWORD user_name_length = 128;
if (!GetUserNameA(user_name, &user_name_length) || !strcmp(user_name, "SYSTEM") == 0)
{
std::wcout << L"Microsoft-Windows-Security-Auditing can only be traced by SYSTEM" << std::endl;
return;
}
// Further, only one trace session is allowed for this provider.
// This session is created by the OS and is called 'EventLog-Security'.
// We can't stop() this session, but we can open() a handle to it.
krabs::user_trace trace(L"EventLog-Security");
krabs::provider<> provider(L"Microsoft-Windows-Security-Auditing");
// We also can't modify the flags of the trace session.
// This will silently fail.
provider.any((ULONGLONG)-1);
// But we can receive events - but only those configured by the audit policy.
// e.g. to enable event 4703 run -> auditpol /set /subcategory:"Token Right Adjusted Events"
provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
std::wcout << L"Event " << schema.event_id();
std::wcout << L"(" << schema.event_name() << L") received." << std::endl;
if (schema.event_id() == 4703) { // "A user right was adjusted."
krabs::parser parser(schema);
std::wstring enabled_privilege_list = parser.parse<std::wstring>(L"EnabledPrivilegeList");
std::wstring disabled_privilege_list = parser.parse<std::wstring>(L"DisabledPrivilegeList");
std::wcout << L"\tEnabledPrivilegeList=" << enabled_privilege_list << std::endl;
std::wcout << L"\tDisabledPrivilegeList=" << disabled_privilege_list << std::endl;
}
});
trace.enable(provider);
trace.start();
}
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use the any_of/all_of/none_of filter predicate vectors.
#include <iostream>
#include <cassert>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_006_predicate_vectors::start()
{
krabs::user_trace trace(L"My Named Trace");
// We will use the Process Trace
krabs::provider<> provider(L"Microsoft-Windows-Kernel-Process");
provider.any(0x10);
// We'll log events where one of the following is true
// - The Opcode is 1,
// - The Event ID is 2, or
// - The Version is 3
krabs::predicates::opcode_is opcode_is_1 = krabs::predicates::opcode_is(1);
krabs::predicates::id_is eventid_is_2 = krabs::predicates::id_is(2);
krabs::predicates::version_is version_is_3 = krabs::predicates::version_is(3);
krabs::event_filter filter(
krabs::predicates::any_of({
&opcode_is_1,
&eventid_is_2,
&version_is_3,
})
);
filter.add_on_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
assert(schema.event_id() == 1 || schema.event_id() == 2);
printf("Event ID: %d || Opcode: %d || Version %d\n", schema.event_id(), schema.event_opcode(), schema.event_version());
});
provider.add_filter(filter);
trace.enable(provider);
trace.start();
}
@@ -0,0 +1,87 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example demonstrates rundown events that capture system state.
#include <iostream>
#include "..\..\krabs\krabs.hpp"
#include "examples.h"
void user_trace_007_rundown::start()
{
krabs::user_trace trace(L"user_trace_007");
// Rundown events are not true real-time tracing events. Instead they describe the state
// of the system - either at the start or end of a trace.
// Usually these are just extra events in the provider. For example, Microsoft-Windows-Kernel-Process
// has ProcessRundown events as well as ProcessStart events.
krabs::provider<> process_provider(L"Microsoft-Windows-Kernel-Process");
process_provider.any(0x10); // WINEVENT_KEYWORD_PROCESS
// ...but the rundown events often cannot be enabled by keyword alone.
// The trace needs to be sent EVENT_CONTROL_CODE_CAPTURE_STATE.
// This is what enable_rundown_events() does.
process_provider.enable_rundown_events();
auto process_callback = [](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
uint32_t pid = parser.parse<uint32_t>(L"ProcessID");
std::wstring image_name = parser.parse<std::wstring>(L"ImageName");
std::wcout << schema.provider_name();
std::wcout << L" task_name=" << schema.task_name();
std::wcout << L" ProcessID=" << pid;
std::wcout << L" ImageName=" << image_name;
std::wcout << std::endl;
};
// real-time process start events
krabs::event_filter process_filter(krabs::predicates::id_is(1)); // ProcessStart
process_filter.add_on_event_callback(process_callback);
process_provider.add_filter(process_filter);
// process rundown events - i.e. running processes
krabs::event_filter process_rundown_filter(krabs::predicates::id_is(15)); // ProcessRundown
process_rundown_filter.add_on_event_callback(process_callback);
process_provider.add_filter(process_rundown_filter);
trace.enable(process_provider);
// Some providers don't follow this pattern and instead split this functionality
// into a seperate provider. For example, Microsoft-Windows-DotNETRuntime and
// Microsoft-Windows-DotNETRuntimeRundown.
krabs::provider<> dotnet_provider(L"Microsoft-Windows-DotNETRuntime");
krabs::provider<> dotnet_rundown_provider(L"Microsoft-Windows-DotNETRuntimeRundown");
auto assembly_callback = [](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
krabs::schema schema(record, trace_context.schema_locator);
krabs::parser parser(schema);
std::wstring assembly_name = parser.parse<std::wstring>(L"FullyQualifiedAssemblyName");
std::wcout << schema.provider_name();
std::wcout << L" opcode_name=" << schema.opcode_name();
std::wcout << L" ProcessId=" << record.EventHeader.ProcessId;
std::wcout << L" FullyQualifiedAssemblyName=" << assembly_name;
std::wcout << std::endl;
};
// real-time assembly load events
dotnet_provider.any(0x8); // LoaderKeyword
krabs::event_filter assembly_filter(krabs::predicates::id_is(154)); // LoaderAssemblyLoad
assembly_filter.add_on_event_callback(assembly_callback);
dotnet_provider.add_filter(assembly_filter);
trace.enable(dotnet_provider);
// assembly rundown events - i.e. loaded assemblies
// Note - use StartRundownKeyword / EndRundownKeyword to control whether the state is enumerated
// at the start or the end of the trace.
dotnet_rundown_provider.any(0x8 | // LoaderRundownKeyword
0x40); // StartRundownKeyword
krabs::event_filter assembly_rundown_filter(krabs::predicates::id_is(155)); // LoaderAssemblyDCStart
assembly_rundown_filter.add_on_event_callback(assembly_callback);
dotnet_rundown_provider.add_filter(assembly_rundown_filter);
trace.enable(dotnet_rundown_provider);
trace.start();
}

Some files were not shown because too many files have changed in this diff Show More