mirror of
https://github.com/hasherezade/hollows_hunter.git
synced 2026-10-12 02:15:21 +00:00
ETW
This commit is contained in:
@@ -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
@@ -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} )
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# hollows_hunter
|
||||

|
||||
|
||||
(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!
|
||||
|
||||
|
||||
[](https://ci.appveyor.com/project/hasherezade/hollows-hunter)
|
||||
[](https://app.codacy.com/gh/hasherezade/hollows_hunter/dashboard?branch=master)
|
||||
[](https://github.com/hasherezade/hollows_hunter/commits)
|
||||
|
||||
@@ -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
@@ -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
@@ -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 ¶ms)
|
||||
size_t HHScanReport::reportsToJSON(std::wstringstream &stream, size_t level, const t_hh_params ¶ms)
|
||||
{
|
||||
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 ¶ms)
|
||||
{
|
||||
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
@@ -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 ¶ms);
|
||||
size_t reportsToJSON(std::stringstream &stream, size_t level, const t_hh_params ¶ms);
|
||||
size_t reportsToJSON(std::wstringstream &stream, size_t level, const t_hh_params ¶ms);
|
||||
|
||||
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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
+205
@@ -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>
|
||||
Binary file not shown.
@@ -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));
|
||||
}
|
||||
|
||||
} } } }
|
||||
+85
@@ -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>
|
||||
+234
@@ -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>
|
||||
+137
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user