Full Code of thefLink/Hunt-Weird-Syscalls for AI

main 166a45203b85 cached
63 files
305.7 KB
78.0k tokens
382 symbols
1 requests
Download .txt
Showing preview only (326K chars total). Download the full file or copy to clipboard to get everything.
Repository: thefLink/Hunt-Weird-Syscalls
Branch: main
Commit: 166a45203b85
Files: 63
Total size: 305.7 KB

Directory structure:
gitextract_85lvkvnd/

├── Hunt-Weird-Syscalls/
│   ├── Detectors.cpp
│   ├── Detectors.h
│   ├── Helpers.cpp
│   ├── Helpers.h
│   ├── Hunt-Weird-Syscalls.sln
│   ├── Hunt-Weird-Syscalls.vcxproj
│   ├── Hunt-Weird-Syscalls.vcxproj.filters
│   ├── Hunt-Weird-Syscalls.vcxproj.user
│   ├── Main.cpp
│   ├── SetThreadContext_Direct/
│   │   ├── Main.c
│   │   ├── SetThreadContext_Direct.vcxproj
│   │   ├── SetThreadContext_Direct.vcxproj.filters
│   │   ├── SetThreadContext_Direct.vcxproj.user
│   │   ├── threadcontext_embedded.c
│   │   ├── threadcontext_embedded.h
│   │   └── threadcontext_embedded_-asm.x64.asm
│   └── SetThreadContext_Indirect/
│       ├── Main.c
│       ├── SetThreadContext_Indirect.vcxproj
│       ├── SetThreadContext_Indirect.vcxproj.filters
│       ├── SetThreadContext_Indirect.vcxproj.user
│       ├── threadcontext_jumper_randomized.c
│       ├── threadcontext_jumper_randomized.h
│       └── threadcontext_jumper_randomized_-asm.x64.asm
├── README.md
└── libs/
    └── krabs/
        ├── LICENSE
        ├── README.md
        ├── krabs/
        │   ├── client.hpp
        │   ├── collection_view.hpp
        │   ├── compiler_check.hpp
        │   ├── errors.hpp
        │   ├── etw.hpp
        │   ├── filtering/
        │   │   ├── comparers.hpp
        │   │   ├── event_filter.hpp
        │   │   ├── predicates.hpp
        │   │   └── view_adapters.hpp
        │   ├── guid.hpp
        │   ├── kernel_guids.hpp
        │   ├── kernel_providers.hpp
        │   ├── kt.hpp
        │   ├── parse_types.hpp
        │   ├── parser.hpp
        │   ├── perfinfo_groupmask.hpp
        │   ├── property.hpp
        │   ├── provider.hpp
        │   ├── schema.hpp
        │   ├── schema_locator.hpp
        │   ├── size_provider.hpp
        │   ├── tdh_helpers.hpp
        │   ├── testing/
        │   │   ├── event_filter_proxy.hpp
        │   │   ├── extended_data_builder.hpp
        │   │   ├── filler.hpp
        │   │   ├── proxy.hpp
        │   │   ├── record_builder.hpp
        │   │   ├── record_property_thunk.hpp
        │   │   └── synth_record.hpp
        │   ├── trace.hpp
        │   ├── trace_context.hpp
        │   ├── ut.hpp
        │   ├── version_helpers.hpp
        │   └── wstring_convert.hpp
        ├── krabs.hpp
        ├── krabs.runsettings
        └── krabs.sln

================================================
FILE CONTENTS
================================================

================================================
FILE: Hunt-Weird-Syscalls/Detectors.cpp
================================================
#include "Detectors.h"

namespace Detectors {

	std::vector<PCSTR> allowedSyscallmodules = { 
		"ntdll.dll", 
		"win32u.dll", 
		"wow64win.dll" 
	};

	PCSTR SyscallAllowOpenThread = "NtOpenThread";
	PCSTR SyscallAllowSetThreadContext = "NtSetContextThread";

	VOID DirectSyscall ( DWORD pid, HANDLE hProcess, std::vector<ULONG_PTR> stack ) {

		std::string lastModule;
		BOOL bSuccess = FALSE;

		bSuccess = Helpers::ModuleNameFromAddress ( hProcess, ( PVOID ) stack.front ( ), lastModule );
		if ( bSuccess == FALSE )
			return;

		for ( auto it = allowedSyscallmodules.begin ( ); it != allowedSyscallmodules.end ( ); ++it ) {
			if ( !_stricmp ( *it, lastModule.c_str ( ) ) )
				return;
		}

		printf ( "! Direct Syscall detected from process: %d\n", pid );
		printf ( "\t Syscall from: 0x%p (%s)\n", ( PVOID ) stack.front ( ), lastModule.c_str ( ) );

	}

	VOID InDirectSyscall ( DWORD pid, HANDLE hProcess, std::vector<ULONG_PTR> stack, PCSTR allowedSyscall ) {

		MEMORY_BASIC_INFORMATION mbi = { 0 };

		std::string lastModule;
		HMODULE hNtdll = NULL;

		BOOL bSuccess = FALSE;
		SIZE_T s = 0;
		ULONG_PTR offsetIs = 0, offsetExpected = 0;
		PVOID returnExpected = NULL;

		bSuccess = Helpers::ModuleNameFromAddress ( hProcess, ( PVOID ) stack.front ( ), lastModule );
		if ( bSuccess == FALSE )
			return;

		if ( _strcmpi ( lastModule.c_str ( ), "ntdll.dll"))
			return; // Currently only verifying ntdll.dll syscalls

		s = VirtualQueryEx ( hProcess, ( LPCVOID ) stack.front ( ), &mbi, sizeof ( MEMORY_BASIC_INFORMATION ) );
		if ( s == 0 )
			return;

		offsetIs = stack.front ( ) - ( ULONG_PTR ) mbi.BaseAddress;
		
		hNtdll = GetModuleHandleA ( "ntdll.dll" );

		returnExpected = GetProcAddress ( hNtdll, allowedSyscall);
		s = VirtualQuery ( returnExpected, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ) );
		if (s == 0) {
			return;
		}

		offsetExpected = ( ( PBYTE ) returnExpected - ( PBYTE ) mbi.BaseAddress );
		if ( offsetExpected < offsetIs && offsetIs <=  offsetExpected + 23 ) {
			return;
		}
		
		printf ( "! Indirect Syscall detected from process: %d\n", pid );
		printf ( "\t Syscall %s expected from: stub at 0x%p but was: 0x%llx\n", allowedSyscall, returnExpected, stack.front ( ) );

	}

}

================================================
FILE: Hunt-Weird-Syscalls/Detectors.h
================================================
#pragma once

#include "windows.h"
#include <vector>

#include "Helpers.h"

namespace Detectors {

	extern std::vector<PCSTR> SyscallsAllowOpenProcess;
	extern PCSTR SyscallAllowOpenThread;
	extern PCSTR SyscallAllowSetThreadContext;

	VOID DirectSyscall ( DWORD pid, HANDLE hProcess, std::vector<ULONG_PTR> stack );
	VOID InDirectSyscall ( DWORD pid, HANDLE hProcess, std::vector<ULONG_PTR> stack, PCSTR );

}

================================================
FILE: Hunt-Weird-Syscalls/Helpers.cpp
================================================
#include "Helpers.h"

namespace Helpers {

	BOOL ModuleNameFromAddress ( HANDLE hProcess, PVOID pAddr, std::string& moduleName ) {

		BOOL bSuccess = FALSE;
		SIZE_T s = 0;
		MEMORY_BASIC_INFORMATION mbi = { 0 };
		CHAR cmoduleName [ MAX_PATH ] = { 0 };

		s = VirtualQueryEx ( hProcess, ( LPCVOID ) pAddr, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ) );
		if ( s == 0 )
			goto Cleanup;

		bSuccess = K32GetModuleBaseNameA ( hProcess, ( HMODULE ) mbi.AllocationBase, ( LPSTR ) cmoduleName, MAX_PATH );
		if ( bSuccess == FALSE )
			goto Cleanup;

		moduleName = std::string ( cmoduleName );

		bSuccess = TRUE;

	Cleanup:

		return bSuccess;

	}

	VOID RemoveKernelAddrs ( std::vector<ULONG_PTR>& stack ) {

		auto it = stack.begin ( );
		while ( it != stack.end ( ) ) {

			ULONG_PTR addr = *it;
			if ( addr > 0xFFFF000000000000 ) {
				it = stack.erase ( it );
			}
			else {
				++it;
			}

		}

	}

	//https://github.com/outflanknl/Dumpert/blob/master/Dumpert/Outflank-Dumpert/Dumpert.c Is Elevated() was taken from here :).
	BOOL IsElevated ( VOID ) {
		BOOL fRet = FALSE;
		HANDLE hToken = NULL;
		if ( OpenProcessToken ( GetCurrentProcess ( ), TOKEN_QUERY, &hToken ) ) {
			TOKEN_ELEVATION Elevation = { 0 };
			DWORD cbSize = sizeof ( TOKEN_ELEVATION );
			if ( GetTokenInformation ( hToken, TokenElevation, &Elevation, sizeof ( Elevation ), &cbSize ) ) {
				fRet = Elevation.TokenIsElevated;
			}
		}
		if ( hToken ) {
			CloseHandle ( hToken );
		}
		return fRet;
	}


}

================================================
FILE: Hunt-Weird-Syscalls/Helpers.h
================================================
#pragma once
#include "windows.h"
#include "psapi.h"

#include <string>
#include <vector>

namespace Helpers {
	VOID RemoveKernelAddrs ( std::vector<ULONG_PTR>& );
	BOOL ModuleNameFromAddress ( HANDLE, PVOID, std::string& );
	BOOL IsElevated ( VOID );
}

================================================
FILE: Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32413.511
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hunt-Weird-Syscalls", "Hunt-Weird-Syscalls.vcxproj", "{B1446E95-C861-4AD9-8A49-D18B97C3108C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SetThreadContext_Direct", "SetThreadContext_Direct\SetThreadContext_Direct.vcxproj", "{C49CD6BF-0525-4270-BEF7-7DEC29630191}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SetThreadContext_Indirect", "SetThreadContext_Indirect\SetThreadContext_Indirect.vcxproj", "{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Debug|x64.ActiveCfg = Debug|x64
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Debug|x64.Build.0 = Debug|x64
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Debug|x86.ActiveCfg = Debug|Win32
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Debug|x86.Build.0 = Debug|Win32
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Release|x64.ActiveCfg = Release|x64
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Release|x64.Build.0 = Release|x64
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Release|x86.ActiveCfg = Release|Win32
		{B1446E95-C861-4AD9-8A49-D18B97C3108C}.Release|x86.Build.0 = Release|Win32
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Debug|x64.ActiveCfg = Debug|x64
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Debug|x64.Build.0 = Debug|x64
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Debug|x86.ActiveCfg = Debug|Win32
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Debug|x86.Build.0 = Debug|Win32
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Release|x64.ActiveCfg = Release|x64
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Release|x64.Build.0 = Release|x64
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Release|x86.ActiveCfg = Release|Win32
		{C49CD6BF-0525-4270-BEF7-7DEC29630191}.Release|x86.Build.0 = Release|Win32
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Debug|x64.ActiveCfg = Debug|x64
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Debug|x64.Build.0 = Debug|x64
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Debug|x86.ActiveCfg = Debug|Win32
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Debug|x86.Build.0 = Debug|Win32
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Release|x64.ActiveCfg = Release|x64
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Release|x64.Build.0 = Release|x64
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Release|x86.ActiveCfg = Release|Win32
		{77C9B594-A2E6-40AB-BA92-E23FC1EAE781}.Release|x86.Build.0 = Release|Win32
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {D52D4FC8-D03B-44EE-95E7-EEF1749CA236}
	EndGlobalSection
EndGlobal


================================================
FILE: Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</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">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{b1446e95-c861-4ad9-8a49-d18b97c3108c}</ProjectGuid>
    <RootNamespace>HuntWeirdSyscalls</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</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|Win32'">
    <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|Win32'">
    <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)'=='Debug|x64'">
    <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>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="Detectors.cpp" />
    <ClCompile Include="Helpers.cpp" />
    <ClCompile Include="Main.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="Detectors.h" />
    <ClInclude Include="Helpers.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.vcxproj.filters
================================================
<?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;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Main.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Helpers.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Detectors.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="Helpers.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="Detectors.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
</Project>

================================================
FILE: Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.vcxproj.user
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup />
</Project>

================================================
FILE: Hunt-Weird-Syscalls/Main.cpp
================================================
#include "../libs/krabs/krabs.hpp"

#include "Detectors.h"
#include "Helpers.h"

#define EVENTID_SETTHTREADCONTEXT 4
#define EVENTID_OPENTHREAD 6

VOID EnableAuditApiTracing ( krabs::user_trace& );
VOID OnObservableSyscall ( const EVENT_RECORD&, const krabs::trace_context& );

VOID EnableAuditApiTracing ( krabs::user_trace& userTrace ) {

	krabs::provider<>* providerApiTracing = new krabs::provider<> ( L"Microsoft-Windows-Kernel-Audit-API-Calls" );

	providerApiTracing->trace_flags ( providerApiTracing->trace_flags ( ) | EVENT_ENABLE_PROPERTY_STACK_TRACE );

	krabs::event_filter* filterOpenThread = new krabs::event_filter ( krabs::predicates::id_is ( EVENTID_OPENTHREAD ) ); // OpenThread
	krabs::event_filter* filterSetContextThread = new krabs::event_filter ( krabs::predicates::id_is ( EVENTID_SETTHTREADCONTEXT ) ); // OpenThread

	/* For now no distinction between events */
	filterOpenThread->add_on_event_callback ( OnObservableSyscall );
	filterSetContextThread->add_on_event_callback ( OnObservableSyscall );

	providerApiTracing->add_filter ( *filterSetContextThread );
	providerApiTracing->add_filter ( *filterOpenThread );

	userTrace.enable ( *providerApiTracing );

}

VOID OnObservableSyscall ( const EVENT_RECORD& record, const krabs::trace_context& trace_context ) {

	BOOL bSuccess = FALSE;
	HANDLE hProcess = NULL;
	DWORD pid = 0;

	krabs::schema schema ( record, trace_context.schema_locator );
	krabs::parser parser ( schema );
	std::vector<ULONG_PTR> stack;

	pid = record.EventHeader.ProcessId;
	stack = schema.stack_trace ( );

	if ( pid == GetCurrentProcessId ( ) )
		return;

	Helpers::RemoveKernelAddrs ( stack );
	if ( stack.size ( ) == 0 )
		return;

	hProcess = OpenProcess ( PROCESS_ALL_ACCESS, FALSE, pid );
	if ( hProcess == NULL )
		return;

	Detectors::DirectSyscall ( pid, hProcess, stack );

	if ( record.EventHeader.EventDescriptor.Id == EVENTID_OPENTHREAD )
		Detectors::InDirectSyscall ( pid, hProcess, stack, Detectors::SyscallAllowOpenThread);
	else if ( record.EventHeader.EventDescriptor.Id == EVENTID_SETTHTREADCONTEXT )
		Detectors::InDirectSyscall ( pid, hProcess, stack, Detectors::SyscallAllowSetThreadContext );

Cleanup:

	if ( hProcess )
		CloseHandle ( hProcess );

}

VOID Go ( krabs::user_trace* userTrace ) {
	userTrace->start ( );
}

int main ( int argc, char** argv ) {

	HANDLE traceThread = NULL;

	krabs::user_trace userTrace ( L"Hunt-Weird-Syscalls" );

	if ( !Helpers::IsElevated ( ) ) {
		printf ( "- Not elevated\n" );
		return 0;
	}

	printf ( "* Enabling trace, might take a bit ... \n" );

	EnableAuditApiTracing ( userTrace );
	traceThread = CreateThread ( NULL, 0, ( LPTHREAD_START_ROUTINE ) Go, &userTrace, 0, NULL );
	if ( traceThread == NULL )
		return 0; // o.0

	printf ( "* Started monitoring, press any key to exit ... \n" );

	getchar ( );
	printf ( "* exiting ... \n" );
	userTrace.stop ( );
	WaitForSingleObject ( traceThread, INFINITE );

	return 0;

}

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/Main.c
================================================
#include "windows.h"
#include "threadcontext_embedded.h"

int main(int argc, char** argv) {

	NtSetContextThread(-1, NULL);

	getchar();

	return 0;
}

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/SetThreadContext_Direct.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</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">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{c49cd6bf-0525-4270-bef7-7dec29630191}</ProjectGuid>
    <RootNamespace>SetThreadContextDirect</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <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|Win32'">
    <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)'=='Debug|x64'">
    <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>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClInclude Include="threadcontext_embedded.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Main.c" />
    <ClCompile Include="threadcontext_embedded.c" />
  </ItemGroup>
  <ItemGroup>
    <MASM Include="threadcontext_embedded_-asm.x64.asm">
      <FileType>Document</FileType>
    </MASM>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
  </ImportGroup>
</Project>

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/SetThreadContext_Direct.vcxproj.filters
================================================
<?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;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="threadcontext_embedded.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="threadcontext_embedded.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Main.c">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <MASM Include="threadcontext_embedded_-asm.x64.asm">
      <Filter>Source Files</Filter>
    </MASM>
  </ItemGroup>
</Project>

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/SetThreadContext_Direct.vcxproj.user
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup />
</Project>

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded.c
================================================
#include "threadcontext_embedded.h"
#include <stdio.h>

//#define DEBUG

// JUMPER

#ifdef _M_IX86

EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
    return (PVOID)__readfsdword(0xC0);
}

__declspec(naked) BOOL local_is_wow64(void)
{
    __asm {
        mov eax, fs:[0xc0]
        test eax, eax
        jne wow64
        mov eax, 0
        ret
        wow64:
        mov eax, 1
        ret
    }
}


#endif

// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams

SW3_SYSCALL_LIST SW3_SyscallList;

// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif

DWORD SW3_HashSyscall(PCSTR FunctionName)
{
    DWORD i = 0;
    DWORD Hash = SW3_SEED;

    while (FunctionName[i])
    {
        WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
        Hash ^= PartialName + SW3_ROR8(Hash);
    }

    return Hash;
}

#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
    return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
    DWORD searchLimit = 512;
    PVOID SyscallAddress;

   #ifdef _WIN64
    // If the process is 64-bit on a 64-bit OS, we need to search for syscall
    BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
    ULONG distance_to_syscall = 0x12;
   #else
    // If the process is 32-bit on a 32-bit OS, we need to search for sysenter
    BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
    ULONG distance_to_syscall = 0x0f;
   #endif

  #ifdef _M_IX86
    // If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
    if (local_is_wow64())
    {
    #ifdef DEBUG
        printf("[+] Running 32-bit app on x64 (WOW64)\n");
    #endif
        return NULL;
    }
  #endif

    // we don't really care if there is a 'jmp' between
    // NtApiAddress and the 'syscall; ret' instructions
    SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);

    if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
    {
        // we can use the original code for this system call :)
        #if defined(DEBUG)
            printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
        #endif
        return SyscallAddress;
    }

    // the 'syscall; ret' intructions have not been found,
    // we will try to use one near it, similarly to HalosGate

    for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
    {
        // let's try with an Nt* API below our syscall
        SyscallAddress = SW3_RVA2VA(
            PVOID,
            NtApiAddress,
            distance_to_syscall + num_jumps * 0x20);
        if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
        {
        #if defined(DEBUG)
            printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
        #endif
            return SyscallAddress;
        }

        // let's try with an Nt* API above our syscall
        SyscallAddress = SW3_RVA2VA(
            PVOID,
            NtApiAddress,
            distance_to_syscall - num_jumps * 0x20);
        if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
        {
        #if defined(DEBUG)
            printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
        #endif
            return SyscallAddress;
        }
    }

#ifdef DEBUG
    printf("Syscall Opcodes not found!\n");
#endif

    return NULL;
}
#endif


BOOL SW3_PopulateSyscallList()
{
    // Return early if the list is already populated.
    if (SW3_SyscallList.Count) return TRUE;

    #ifdef _WIN64
    PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
    #else
    PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
    #endif
    PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
    PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
    PVOID DllBase = NULL;

    // Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
    // in the list, so it's safer to loop through the full list and find it.
    PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
    for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
    {
        DllBase = LdrEntry->DllBase;
        PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
        PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
        PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
        DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        if (VirtualAddress == 0) continue;

        ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);

        // If this is NTDLL.dll, exit loop.
        PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);

        if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
        if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
    }

    if (!ExportDirectory) return FALSE;

    DWORD NumberOfNames = ExportDirectory->NumberOfNames;
    PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
    PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
    PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);

    // Populate SW3_SyscallList with unsorted Zw* entries.
    DWORD i = 0;
    PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
    do
    {
        PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);

        // Is this a system call?
        if (*(USHORT*)FunctionName == 0x775a)
        {
            Entries[i].Hash = SW3_HashSyscall(FunctionName);
            Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
            Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));

            i++;
            if (i == SW3_MAX_ENTRIES) break;
        }
    } while (--NumberOfNames);

    // Save total number of system calls found.
    SW3_SyscallList.Count = i;

    // Sort the list by address in ascending order.
    for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
    {
        for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
        {
            if (Entries[j].Address > Entries[j + 1].Address)
            {
                // Swap entries.
                SW3_SYSCALL_ENTRY TempEntry;

                TempEntry.Hash = Entries[j].Hash;
                TempEntry.Address = Entries[j].Address;
                TempEntry.SyscallAddress = Entries[j].SyscallAddress;

                Entries[j].Hash = Entries[j + 1].Hash;
                Entries[j].Address = Entries[j + 1].Address;
                Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;

                Entries[j + 1].Hash = TempEntry.Hash;
                Entries[j + 1].Address = TempEntry.Address;
                Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
            }
        }
    }

    return TRUE;
}

EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
    // Ensure SW3_SyscallList is populated.
    if (!SW3_PopulateSyscallList()) return -1;

    for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
    {
        if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
        {
            return i;
        }
    }

    return -1;
}

EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
    // Ensure SW3_SyscallList is populated.
    if (!SW3_PopulateSyscallList()) return NULL;

    for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
    {
        if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
        {
            return SW3_SyscallList.Entries[i].SyscallAddress;
        }
    }

    return NULL;
}

EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
    // Ensure SW3_SyscallList is populated.
    if (!SW3_PopulateSyscallList()) return NULL;

    DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;

    while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
        // Spoofing the syscall return address
        index = ((DWORD) rand()) % SW3_SyscallList.Count;
    }
    return SW3_SyscallList.Entries[index].SyscallAddress;
}


================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded.h
================================================
#pragma once

// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams

#ifndef SW3_HEADER_H_
#define SW3_HEADER_H_

#include <windows.h>

#define SW3_SEED 0x3A397AC2
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 500
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)

// Typedefs are prefixed to avoid pollution.

typedef struct _SW3_SYSCALL_ENTRY
{
    DWORD Hash;
    DWORD Address;
	PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;

typedef struct _SW3_SYSCALL_LIST
{
    DWORD Count;
    SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;

typedef struct _SW3_PEB_LDR_DATA {
	BYTE Reserved1[8];
	PVOID Reserved2[3];
	LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;

typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
	PVOID Reserved1[2];
	LIST_ENTRY InMemoryOrderLinks;
	PVOID Reserved2[2];
	PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;

typedef struct _SW3_PEB {
	BYTE Reserved1[2];
	BYTE BeingDebugged;
	BYTE Reserved2[1];
	PVOID Reserved3[2];
	PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;

DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
EXTERN_C NTSTATUS NtSetContextThread(
	IN HANDLE ThreadHandle,
	IN PCONTEXT Context);

#endif


================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded_-asm.x64.asm
================================================
.code

EXTERN SW3_GetSyscallNumber: PROC

NtSetContextThread PROC
	mov [rsp +8], rcx          ; Save registers.
	mov [rsp+16], rdx
	mov [rsp+24], r8
	mov [rsp+32], r9
	sub rsp, 28h
	mov ecx, 0FA5F256Dh        ; Load function hash into ECX.
	call SW3_GetSyscallNumber              ; Resolve function hash into syscall number.
	add rsp, 28h
	mov rcx, [rsp+8]                      ; Restore registers.
	mov rdx, [rsp+16]
	mov r8, [rsp+24]
	mov r9, [rsp+32]
	mov r10, rcx
	syscall                    ; Invoke system call.
	ret
NtSetContextThread ENDP

end

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/Main.c
================================================
#include "windows.h"
#include "threadcontext_jumper_randomized.h"

int main(int argc, char** argv) {

	NtSetContextThread(-1, NULL);

	getchar();

	return 0;
}

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/SetThreadContext_Indirect.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</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">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{77c9b594-a2e6-40ab-ba92-e23fc1eae781}</ProjectGuid>
    <RootNamespace>SetThreadContextIndirect</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <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|Win32'">
    <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)'=='Debug|x64'">
    <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>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClInclude Include="threadcontext_jumper_randomized.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Main.c" />
    <ClCompile Include="threadcontext_jumper_randomized.c" />
  </ItemGroup>
  <ItemGroup>
    <MASM Include="threadcontext_jumper_randomized_-asm.x64.asm">
      <FileType>Document</FileType>
    </MASM>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
  </ImportGroup>
</Project>

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/SetThreadContext_Indirect.vcxproj.filters
================================================
<?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;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="threadcontext_jumper_randomized.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="threadcontext_jumper_randomized.c">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Main.c">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <MASM Include="threadcontext_jumper_randomized_-asm.x64.asm">
      <Filter>Source Files</Filter>
    </MASM>
  </ItemGroup>
</Project>

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/SetThreadContext_Indirect.vcxproj.user
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup />
</Project>

================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized.c
================================================
#include "threadcontext_jumper_randomized.h"
#include <stdio.h>

//#define DEBUG

#define JUMPER

#ifdef _M_IX86

EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
    return (PVOID)__readfsdword(0xC0);
}

__declspec(naked) BOOL local_is_wow64(void)
{
    __asm {
        mov eax, fs:[0xc0]
        test eax, eax
        jne wow64
        mov eax, 0
        ret
        wow64:
        mov eax, 1
        ret
    }
}


#endif

// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams

SW3_SYSCALL_LIST SW3_SyscallList;

// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif

DWORD SW3_HashSyscall(PCSTR FunctionName)
{
    DWORD i = 0;
    DWORD Hash = SW3_SEED;

    while (FunctionName[i])
    {
        WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
        Hash ^= PartialName + SW3_ROR8(Hash);
    }

    return Hash;
}

#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
    return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
    DWORD searchLimit = 512;
    PVOID SyscallAddress;

   #ifdef _WIN64
    // If the process is 64-bit on a 64-bit OS, we need to search for syscall
    BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
    ULONG distance_to_syscall = 0x12;
   #else
    // If the process is 32-bit on a 32-bit OS, we need to search for sysenter
    BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
    ULONG distance_to_syscall = 0x0f;
   #endif

  #ifdef _M_IX86
    // If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
    if (local_is_wow64())
    {
    #ifdef DEBUG
        printf("[+] Running 32-bit app on x64 (WOW64)\n");
    #endif
        return NULL;
    }
  #endif

    // we don't really care if there is a 'jmp' between
    // NtApiAddress and the 'syscall; ret' instructions
    SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);

    if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
    {
        // we can use the original code for this system call :)
        #if defined(DEBUG)
            printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
        #endif
        return SyscallAddress;
    }

    // the 'syscall; ret' intructions have not been found,
    // we will try to use one near it, similarly to HalosGate

    for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
    {
        // let's try with an Nt* API below our syscall
        SyscallAddress = SW3_RVA2VA(
            PVOID,
            NtApiAddress,
            distance_to_syscall + num_jumps * 0x20);
        if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
        {
        #if defined(DEBUG)
            printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
        #endif
            return SyscallAddress;
        }

        // let's try with an Nt* API above our syscall
        SyscallAddress = SW3_RVA2VA(
            PVOID,
            NtApiAddress,
            distance_to_syscall - num_jumps * 0x20);
        if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
        {
        #if defined(DEBUG)
            printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
        #endif
            return SyscallAddress;
        }
    }

#ifdef DEBUG
    printf("Syscall Opcodes not found!\n");
#endif

    return NULL;
}
#endif


BOOL SW3_PopulateSyscallList()
{
    // Return early if the list is already populated.
    if (SW3_SyscallList.Count) return TRUE;

    #ifdef _WIN64
    PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
    #else
    PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
    #endif
    PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
    PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
    PVOID DllBase = NULL;

    // Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
    // in the list, so it's safer to loop through the full list and find it.
    PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
    for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
    {
        DllBase = LdrEntry->DllBase;
        PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
        PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
        PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
        DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        if (VirtualAddress == 0) continue;

        ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);

        // If this is NTDLL.dll, exit loop.
        PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);

        if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
        if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
    }

    if (!ExportDirectory) return FALSE;

    DWORD NumberOfNames = ExportDirectory->NumberOfNames;
    PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
    PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
    PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);

    // Populate SW3_SyscallList with unsorted Zw* entries.
    DWORD i = 0;
    PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
    do
    {
        PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);

        // Is this a system call?
        if (*(USHORT*)FunctionName == 0x775a)
        {
            Entries[i].Hash = SW3_HashSyscall(FunctionName);
            Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
            Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));

            i++;
            if (i == SW3_MAX_ENTRIES) break;
        }
    } while (--NumberOfNames);

    // Save total number of system calls found.
    SW3_SyscallList.Count = i;

    // Sort the list by address in ascending order.
    for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
    {
        for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
        {
            if (Entries[j].Address > Entries[j + 1].Address)
            {
                // Swap entries.
                SW3_SYSCALL_ENTRY TempEntry;

                TempEntry.Hash = Entries[j].Hash;
                TempEntry.Address = Entries[j].Address;
                TempEntry.SyscallAddress = Entries[j].SyscallAddress;

                Entries[j].Hash = Entries[j + 1].Hash;
                Entries[j].Address = Entries[j + 1].Address;
                Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;

                Entries[j + 1].Hash = TempEntry.Hash;
                Entries[j + 1].Address = TempEntry.Address;
                Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
            }
        }
    }

    return TRUE;
}

EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
    // Ensure SW3_SyscallList is populated.
    if (!SW3_PopulateSyscallList()) return -1;

    for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
    {
        if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
        {
            return i;
        }
    }

    return -1;
}

EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
    // Ensure SW3_SyscallList is populated.
    if (!SW3_PopulateSyscallList()) return NULL;

    for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
    {
        if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
        {
            return SW3_SyscallList.Entries[i].SyscallAddress;
        }
    }

    return NULL;
}

EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
    // Ensure SW3_SyscallList is populated.
    if (!SW3_PopulateSyscallList()) return NULL;

    DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;

    while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
        // Spoofing the syscall return address
        index = ((DWORD) rand()) % SW3_SyscallList.Count;
    }
    return SW3_SyscallList.Entries[index].SyscallAddress;
}


================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized.h
================================================
#pragma once

// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams

#ifndef SW3_HEADER_H_
#define SW3_HEADER_H_

#include <windows.h>

#define SW3_SEED 0xE331CC7E
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 500
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)

// Typedefs are prefixed to avoid pollution.

typedef struct _SW3_SYSCALL_ENTRY
{
    DWORD Hash;
    DWORD Address;
	PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;

typedef struct _SW3_SYSCALL_LIST
{
    DWORD Count;
    SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;

typedef struct _SW3_PEB_LDR_DATA {
	BYTE Reserved1[8];
	PVOID Reserved2[3];
	LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;

typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
	PVOID Reserved1[2];
	LIST_ENTRY InMemoryOrderLinks;
	PVOID Reserved2[2];
	PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;

typedef struct _SW3_PEB {
	BYTE Reserved1[2];
	BYTE BeingDebugged;
	BYTE Reserved2[1];
	PVOID Reserved3[2];
	PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;

DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
EXTERN_C NTSTATUS NtSetContextThread(
	IN HANDLE ThreadHandle,
	IN PCONTEXT Context);

#endif


================================================
FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized_-asm.x64.asm
================================================
.code

EXTERN SW3_GetSyscallNumber: PROC

EXTERN SW3_GetRandomSyscallAddress: PROC

NtSetContextThread PROC
	mov [rsp +8], rcx          ; Save registers.
	mov [rsp+16], rdx
	mov [rsp+24], r8
	mov [rsp+32], r9
	sub rsp, 28h
	mov ecx, 0123E5E95h        ; Load function hash into ECX.
	call SW3_GetRandomSyscallAddress        ; Get a syscall offset from a different api.
	mov r15, rax                           ; Save the address of the syscall
	mov ecx, 0123E5E95h        ; Re-Load function hash into ECX (optional).
	call SW3_GetSyscallNumber              ; Resolve function hash into syscall number.
	add rsp, 28h
	mov rcx, [rsp+8]                      ; Restore registers.
	mov rdx, [rsp+16]
	mov r8, [rsp+24]
	mov r9, [rsp+32]
	mov r10, rcx
	jmp r15                                ; Jump to -> Invoke system call.
NtSetContextThread ENDP

end

================================================
FILE: README.md
================================================
# Hunt-Weird-Syscalls

This is a ETW based POC to monitor for abnormal syscalls.   

For now, the syscalls ``NtOpenThread`` and ``NtSetContextThread`` are monitored to identify IOCs indicating both **direct** and **indirect** syscalls.

## Description

This project uses ``ETW``, more precisely kernel based ETW providers, to monitor for IOCs.    
``ETW`` providers sitting in the kernel can effectively be leveraged, as the calltraces of emitted events contain the usermode address from where the syscall was conducted.    

This allows monitoring IOCs indicating direct and indirect syscalls, a technique often leveraged by threat actors:

1: A syscall was conducted from an untrusted module (=direct syscall)   
2: The used syscall stub in ntdll does not match the conducted syscall (=indirect syscall)

This project uses the Provider: ``Microsoft-Windows-Kernel-Audit-API-Calls`` to monitor for ``OpenThread`` and ``SetContextThread`` events triggered by the syscalls ``NtSetContextThread`` or ``NtOpenThread`` respectively.    
Calltraces are enabled, using the flag ``EVENT_ENABLE_PROPERTY_STACK_TRACE``.   

This is a POC, and only monitors two specific syscalls. It is of course possible to use other kernel based providers to enhance telemetry.    

## Tests

This project contains two sample programs using direct and indirect syscalls created using the amazing [SysWhispers3](https://github.com/klezVirus/SysWhispers3).
They were generated as follows:

```
python3 syswhispers.py -a x64 -m jumper_randomized --functions NtSetContextThread
python3 syswhispers.py -a x64 -m embedded --functions NtSetContextThread
```

Upon execution, abnormal syscalls should be identified:

![Identification of Abnormal Syscalls](/Screenshots/1.png?raw=true)

**Tested on ``10.0.19044``.**

## Credits

- [KrabsETW](https://github.com/microsoft/krabsetw) 
- [SysWhispers3](https://github.com/klezVirus/SysWhispers3)
- [etw provider docs by repnz](https://github.com/repnz/etw-providers-docs)
- [@OutflankNL](https://twitter.com/OutflankNL) for ``IsElevated()``
- [@trickster012](https://twitter.com/trickster012) for testing and support <3


================================================
FILE: libs/krabs/LICENSE
================================================
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.


================================================
FILE: libs/krabs/README.md
================================================
# Krabs Readme

Important Preprocessor Definitions:

* `UNICODE` - krabsetw expects the `UNICODE` preprocessor definition to be
  defined. The code will not successfully compile without this flag. There is
  no plan to support compilation without `UNICODE` being set.

* `NDEBUG` - Set this variable in release builds to disable runtime type
   assertions. You'll still get a runtime error if the size type you're
   requesting is not the same size as the property in the event schema.

* `TYPEASSERT` - Set this variable only in debug builds (not `NDEBUG`) to enable
   strict assertions. This means that if an explicit type check is not defined
   for a requested type, a `static_assert` is thrown and the code will not 
   compile until one is added. This is mainly used for krabs development to
   ensure that we don't miss asserts for types that are supported.


================================================
FILE: libs/krabs/krabs/client.hpp
================================================
// 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 "compiler_check.hpp"
#include "ut.hpp"
#include "kt.hpp"
#include "trace.hpp"

namespace krabs {

    /**
     * <summary>
     * Specialization of the base trace class for user traces.
     * </summary>
     */
    typedef krabs::trace<krabs::details::ut> user_trace;

    /**
     * <summary>
     * Specialization of the base trace class for kernel traces.
     * </summary>
     */
    typedef krabs::trace<krabs::details::kt> kernel_trace;
}


================================================
FILE: libs/krabs/krabs/collection_view.hpp
================================================
// 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 <string>

#include "compiler_check.hpp"

namespace krabs {

    /**
     * Wraps a range of a collection starting at the location
     * specified by the begin iterator and ending a the location
     * specified by the end iterator. The underlying items are
     * left in-place and should be considered const
     */
    template <typename T>
    struct collection_view
    {
    private:
        const T beg_;
        const T end_;

    public:
        /**
         * Construct a new view for the range specified by the
         * iterators 'begin' and 'end'
         */
        collection_view(const T begin, const T end)
            : beg_(begin)
            , end_(end)
        { }

        /**
         * Get the iterator for the beginning of the view range
         */
        const T begin() const
        {
            return beg_;
        }

        /**
         * Get the iterator for the end of the view range
         */
        const T end() const
        {
            return end_;
        }
    };

    /**
     * Create a view over the range specified by iterators 'begin' and 'end'
     */
    template <typename T>
    inline collection_view<T> view(const T& begin, const T& end)
    {
        return{ begin, end };
    }

    /**
     * Create a const_iterator view over the specified string
     */
    template <typename T>
    inline collection_view<typename std::basic_string<T>::const_iterator> view(const std::basic_string<T>& string)
    {
        return{ string.cbegin(), string.cend() };
    }

    /**
     * Create a const view over the range starting at 'begin' extending 'length' items
     */
    template <typename T>
    inline collection_view<const T*> view(const T* begin, size_t length)
    {
        return{ begin, begin + length };
    }

    /**
     * Create a const view over the specified array
     */
    template <typename T, size_t n>
    inline collection_view<const T*> view(const T(&arr)[n])
    {
        return{ arr, arr + n };
    }

} /* namespace krabs */

================================================
FILE: libs/krabs/krabs/compiler_check.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#pragma once

#if (_MSC_VER < 1900)
#error "krabsetw is only supported with Visual Studio 2015 and above (MSVC++ 14.0)"
#endif


================================================
FILE: libs/krabs/krabs/errors.hpp
================================================
// 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 <stdexcept>

#include "compiler_check.hpp"

namespace krabs {

    class trace_already_registered : public std::runtime_error {
    public:
        trace_already_registered()
            : std::runtime_error("The trace session has already been registered")
        {}
    };

    class invalid_parameter : public std::logic_error {
    public:
        invalid_parameter()
            : std::logic_error("Invalid parameter given")
        {}
    };

    class open_trace_failure : public std::runtime_error {
    public:
        open_trace_failure()
            : std::runtime_error("Failure to open trace")
        {}
    };

    class need_to_be_admin_failure : public std::runtime_error {
    public:
        need_to_be_admin_failure()
            : std::runtime_error("Need to be an admin")
        {}
    };

    class could_not_find_schema : public std::runtime_error {
    public:
        could_not_find_schema()
        : std::runtime_error("Could not find the schema")
        {}

        could_not_find_schema(const std::string& context)
            : std::runtime_error(std::string("Could not find the schema: ") + context)
        {}
    };

    class type_mismatch_assert : public std::runtime_error {
    public:
        type_mismatch_assert(
            const char* property,
            const char* actual,
            const char* requested)
            : std::runtime_error(std::string("Attempt to read property '") +
            property + "' type " + actual + " as " + requested)
        {}
    };

    class no_trace_sessions_remaining : public std::runtime_error {
    public:
        no_trace_sessions_remaining()
            : std::runtime_error("No more trace sessions available.")
        {}
    };

    class function_not_supported : public std::runtime_error {
    public:
        function_not_supported()
            : std::runtime_error("This function is not supported on this system.")
        {}
    };

    class unexpected_error : public std::runtime_error {
    public:
        unexpected_error(ULONG status)
            : std::runtime_error(std::string("An unexpected error occurred: status_code=") +
                std::to_string(status))
        {}

        unexpected_error(const std::string &context)
            : std::runtime_error(std::string("An unexpected error occurred: ") + context)
        {}
    };

    inline std::string get_status_and_record_context(ULONG status, const EVENT_RECORD& record)
    {
        std::stringstream message;
        message << "status_code="
            << status
            << " provider_id="
            << std::to_string(record.EventHeader.ProviderId)
            << " event_id="
            << record.EventHeader.EventDescriptor.Id;

        return message.str();
    }

    /**
     * <summary>Checks for common ETW API error codes.</summary>
     */
    inline void error_check_common_conditions(ULONG status)
    {
        if (status == ERROR_SUCCESS) {
            return;
        }

        switch (status) {
            case ERROR_ALREADY_EXISTS:
                throw krabs::trace_already_registered();
            case ERROR_INVALID_PARAMETER:
                throw krabs::invalid_parameter();
            case ERROR_ACCESS_DENIED:
                throw krabs::need_to_be_admin_failure();
            case ERROR_NOT_FOUND:
                throw krabs::could_not_find_schema();
            case ERROR_NO_SYSTEM_RESOURCES:
                throw krabs::no_trace_sessions_remaining();
            case ERROR_NOT_SUPPORTED:
                throw krabs::function_not_supported();
            default:
                throw krabs::unexpected_error(status);
        }
    }

    /**
     * <summary>Checks for common ETW API error codes and includes properties from the event record.</summary>
     */
    inline void error_check_common_conditions(ULONG status, const EVENT_RECORD &record)
    {
        if (status == ERROR_SUCCESS) {
            return;
        }

        auto context = get_status_and_record_context(status, record);

        switch (status) {
        case ERROR_ALREADY_EXISTS:
            throw krabs::trace_already_registered();
        case ERROR_INVALID_PARAMETER:
            throw krabs::invalid_parameter();
        case ERROR_ACCESS_DENIED:
            throw krabs::need_to_be_admin_failure();
        case ERROR_NOT_FOUND:
            throw krabs::could_not_find_schema(context);
        case ERROR_NO_SYSTEM_RESOURCES:
            throw krabs::no_trace_sessions_remaining();
        case ERROR_NOT_SUPPORTED:
            throw krabs::function_not_supported();
        default:
            throw krabs::unexpected_error(context);
        }
    }
}


================================================
FILE: libs/krabs/krabs/etw.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

// Interface for ETW.

#pragma once

#define INITGUID

#include "compiler_check.hpp"
#include "trace.hpp"
#include "errors.hpp"

#include <cassert>
#include <map>

#include <evntrace.h>
#include <evntcons.h>

namespace krabs { namespace details {

    // The ETW API requires that we reserve enough memory behind
    // an EVENT_TRACE_PROPERTIES buffer in order to store an ETW trace name
    // and an optional ETW log file name. The easiest way to do this is to
    // use a struct to reserve this space -- the alternative is to malloc
    // the bytes at runtime (ew).
    class trace_info {
    public:
        EVENT_TRACE_PROPERTIES properties;
        wchar_t traceName[MAX_PATH];
        wchar_t logfileName[MAX_PATH];
    };

    /**
     * <summary>
     * Used to implement starting and stopping traces.
     * </summary>
     */
    template <typename T>
    class trace_manager {
    public:
        trace_manager(T &trace);

        /**
         * <summary>
         * Starts the ETW trace identified by the info in the trace type.
         * </summary>
         */
        void start();

        /**
         * <summary>
         * Stops the ETW trace identified by the info in the trace type.
         * </summary>
         */
        void stop();

        /**
        * <summary>
        * Opens the ETW trace identified by the info in the trace type.
        * </summary>
        */
        EVENT_TRACE_LOGFILE open();

        /**
        * <summary>
        * Starts processing the ETW trace identified by the info in the trace type.
        * open() needs to called for this to work first.
        * </summary>
        */
        void process();

        /**
         * <summary>
         * Queries the ETW trace identified by the info in the trace type.
         * </summary>
         */
        EVENT_TRACE_PROPERTIES query();

        /**
         * <summary>
         * Configures the ETW trace session settings.
         * See https://docs.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-tracesetinformation.
         * </summary>
         */
        void set_trace_information(
            TRACE_INFO_CLASS information_class,
            PVOID trace_information,
            ULONG information_length);

        /**
         * <summary>
         * Notifies the underlying trace of the buffers that were processed.
         * </summary>
         */
        void set_buffers_processed(size_t processed);

        /**
         * <summary>
         * Notifies the underlying trace that an event occurred.
         * </summary>
         */
        void on_event(const EVENT_RECORD &record);

    private:
        trace_info fill_trace_info();
        EVENT_TRACE_LOGFILE fill_logfile();
        void close_trace();
        void register_trace();
        EVENT_TRACE_PROPERTIES query_trace();
        void stop_trace();
        EVENT_TRACE_LOGFILE open_trace();
        void process_trace();
        void enable_providers();

    private:
        T &trace_;
    };

    // Implementation
    // ------------------------------------------------------------------------

    /**
     * <summary>
     *   Called by ETW when an event occurs, forwards calls to the
     *   appropriate instance.
     * </summary>
     * <remarks>
     *   A pointer to the instance is stored in the UserContext
     *   field of the EVENT_RECORD. This is set via the Context field of the
     *   EVENT_TRACE_LOGFILE structure.
     * </remarks>
     */
    template <typename T>
    static void __stdcall trace_callback_thunk(EVENT_RECORD *pRecord)
    {
        auto *pUserTrace = (T*)(pRecord->UserContext);
        trace_manager<T> trace(*pUserTrace);
        trace.on_event(*pRecord);
    }

    /**
     * <summary>
     *   Called by ETW after the events for each buffer are delivered, gives
     *   statistics like the number of buffers processed and the number of
     *   events dropped.
     * </summary>
     * <remarks>
     *   A pointer to the instance is stored in the UserContext
     *   field of the EVENT_RECORD. This is set via the Context field of the
     *   EVENT_TRACE_LOGFILE structure.
     * </remarks>
     */
    template <typename T>
    static ULONG __stdcall trace_buffer_callback(EVENT_TRACE_LOGFILE *pLogFile)
    {
        auto *pTrace = (T*)(pLogFile->Context);
        trace_manager<T> trace(*pTrace);

        // NOTE: EventsLost is not set on this type
        trace.set_buffers_processed(pLogFile->BuffersRead);
        return TRUE;
    }

    template <typename T>
    trace_manager<T>::trace_manager(T &trace)
    : trace_(trace)
    {}

    template <typename T>
    void trace_manager<T>::start()
    {
        if (trace_.sessionHandle_ == INVALID_PROCESSTRACE_HANDLE) {
            (void)open();
        }
        process_trace();
    }

    template <typename T>
    EVENT_TRACE_LOGFILE trace_manager<T>::open()
    {
        register_trace();
        enable_providers();
        return open_trace();
    }

    template <typename T>
    void trace_manager<T>::process()
    {
        process_trace();
    }

    template <typename T>
    EVENT_TRACE_PROPERTIES trace_manager<T>::query()
    {
        return query_trace();
    }

    template <typename T>
    void trace_manager<T>::set_trace_information(
        TRACE_INFO_CLASS information_class,
        PVOID trace_information,
        ULONG information_length)
    {
        ULONG status = TraceSetInformation(
            trace_.registrationHandle_, 
            information_class,
            trace_information,
            information_length);

        error_check_common_conditions(status);
    }

    template <typename T>
    void trace_manager<T>::stop()
    {
        stop_trace();
        close_trace();
    }

    template <typename T>
    void trace_manager<T>::set_buffers_processed(size_t processed)
    {
        trace_.buffersRead_ = processed;
    }

    template <typename T>
    void trace_manager<T>::on_event(const EVENT_RECORD &record)
    {
        trace_.on_event(record);
    }

    template <typename T>
    trace_info trace_manager<T>::fill_trace_info()
    {
        trace_info info = {};
        info.properties.Wnode.BufferSize    = sizeof(trace_info);
        info.properties.Wnode.Guid          = T::trace_type::get_trace_guid();
        info.properties.Wnode.Flags         = WNODE_FLAG_TRACED_GUID;
        info.properties.Wnode.ClientContext = 1; // QPC clock resolution
        info.properties.BufferSize          = trace_.properties_.BufferSize;
        info.properties.MinimumBuffers      = trace_.properties_.MinimumBuffers;
        info.properties.MaximumBuffers      = trace_.properties_.MaximumBuffers;
        info.properties.FlushTimer          = trace_.properties_.FlushTimer;

        if (trace_.properties_.LogFileMode)
            info.properties.LogFileMode     = trace_.properties_.LogFileMode;
        else
            info.properties.LogFileMode     = EVENT_TRACE_REAL_TIME_MODE
                                            | EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING;

        info.properties.LogFileMode         |= T::trace_type::augment_file_mode();
        info.properties.LoggerNameOffset    = offsetof(trace_info, logfileName);
        info.properties.EnableFlags         = T::trace_type::construct_enable_flags(trace_);
        assert(info.traceName[0] == '\0');
        assert(info.logfileName[0] == '\0');
        trace_.name_._Copy_s(info.traceName, ARRAYSIZE(info.traceName), trace_.name_.length());
        return info;
    }

    template <typename T>
    EVENT_TRACE_LOGFILE trace_manager<T>::fill_logfile()
    {
        EVENT_TRACE_LOGFILE file = {};

        if (!trace_.logFilename_.empty())
        {
            file.LogFileName      = const_cast<wchar_t*>(trace_.logFilename_.c_str());
            file.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
        }
        else
        {
            file.LoggerName       = const_cast<wchar_t*>(trace_.name_.c_str());
            file.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD |
                PROCESS_TRACE_MODE_REAL_TIME;
        }
        file.Context             = (void *)&trace_;
        file.EventRecordCallback = trace_callback_thunk<T>;
        file.BufferCallback      = trace_buffer_callback<T>;
        return file;
    }

    template <typename T>
    void trace_manager<T>::stop_trace()
    {
        trace_info info = fill_trace_info();
        ULONG status = ControlTrace(
            NULL,
            trace_.name_.c_str(),
            &info.properties,
            EVENT_TRACE_CONTROL_STOP);

        if (status != ERROR_WMI_INSTANCE_NOT_FOUND) {
            error_check_common_conditions(status);
        }
    }

    template <typename T>
    EVENT_TRACE_PROPERTIES trace_manager<T>::query_trace()
    {
        trace_info info = fill_trace_info();
        ULONG status = ControlTrace(
            NULL,
            trace_.name_.c_str(),
            &info.properties,
            EVENT_TRACE_CONTROL_QUERY);

        if (status != ERROR_WMI_INSTANCE_NOT_FOUND) {
            error_check_common_conditions(status);

            return info.properties;
        }

        return { };
    }

    template <typename T>
    void trace_manager<T>::register_trace()
    {
        trace_info info = fill_trace_info();

        ULONG status = StartTrace(&trace_.registrationHandle_,
                                  trace_.name_.c_str(),
                                  &info.properties);
        if (status == ERROR_ALREADY_EXISTS) {
            try {
                stop_trace();
                status = StartTrace(&trace_.registrationHandle_,
                    trace_.name_.c_str(),
                    &info.properties);
            }
            catch (need_to_be_admin_failure) {
                (void)open_trace();
                close_trace();
                // insufficient privilege to stop/configure
                // but if open/close didn't throw also
                // then we're okay to process events
                status = ERROR_SUCCESS;
                // we also invalidate the registrationHandle_
                // StartTrace() actually sets this to 0 on failure
                trace_.registrationHandle_ = INVALID_PROCESSTRACE_HANDLE;
            }
            catch (invalid_parameter) {
                // In some versions, the error code is 87 when using
                // SystemTraceControlGuid session. If open/close doesn't
                // throw, then we can continually processing events.
                (void)open_trace();
                close_trace();
                status = ERROR_SUCCESS;
                trace_.registrationHandle_ = INVALID_PROCESSTRACE_HANDLE;
            }
        }

        error_check_common_conditions(status);
    }

    template <typename T>
    EVENT_TRACE_LOGFILE trace_manager<T>::open_trace()
    {
        auto file = fill_logfile();
        trace_.sessionHandle_ = OpenTrace(&file);
        if (trace_.sessionHandle_ == INVALID_PROCESSTRACE_HANDLE) {
            throw open_trace_failure();
        }
        return file;
    }

    template <typename T>
    void trace_manager<T>::process_trace()
    {
        if (trace_.sessionHandle_ == INVALID_PROCESSTRACE_HANDLE) {
            throw open_trace_failure();
        }

        // Refactoring warning.
        // During the testing of the (slower) C++/CLI implementation it became evident that
        // EnableTraceEx2(EVENT_CONTROL_CODE_CAPTURE_STATE) must be called very shortly
        // before ProcessTrace() in order for the rundown events to be generated.
        T::trace_type::enable_rundown(trace_);

        ULONG status = ProcessTrace(&trace_.sessionHandle_, 1, NULL, NULL);
        error_check_common_conditions(status);
    }

    template <typename T>
    void trace_manager<T>::close_trace()
    {
        if (trace_.sessionHandle_ != INVALID_PROCESSTRACE_HANDLE) {
            ULONG status = CloseTrace(trace_.sessionHandle_);
            trace_.sessionHandle_ = INVALID_PROCESSTRACE_HANDLE;

            if (status != ERROR_CTX_CLOSE_PENDING) {
                error_check_common_conditions(status);
            }
        }
    }

    template <typename T>
    void trace_manager<T>::enable_providers()
    {
        T::trace_type::enable_providers(trace_);
    }
} /* namespace details */ } /* namespace krabs */


================================================
FILE: libs/krabs/krabs/filtering/comparers.hpp
================================================
// 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 <algorithm>

#include "../compiler_check.hpp"

namespace krabs { namespace predicates {

    namespace comparers {

        // Algorithms
        // --------------------------------------------------------------------

        /**
         * Iterator based equals
         */
        template <typename Comparer>
        struct equals
        {
            template <typename Iter1, typename Iter2>
            bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
            {
                return std::equal(first1, last1, first2, last2, Comparer());
            }
        };

        /**
         * Iterator based search
         */
        template <typename Comparer>
        struct contains
        {
            template <typename Iter1, typename Iter2>
            bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
            {
                // empty test range always contained, even when input range empty
                return first2 == last2
                    || std::search(first1, last1, first2, last2, Comparer()) != last1;
            }
        };

        /**
         * Iterator based starts_with
         */
        template <typename Comparer>
        struct starts_with
        {
            template <typename Iter1, typename Iter2>
            bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
            {
                const auto first_nonequal = std::mismatch(first1, last1, first2, last2, Comparer());
                return first_nonequal.second == last2;
            }
        };

        /**
        * Iterator based ends_with
        */
        template <typename Comparer>
        struct ends_with
        {
            template <typename Iter1, typename Iter2>
            bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
            {
                const auto dist1 = std::distance(first1, last1);
                const auto dist2 = std::distance(first2, last2);

                if (dist2 > dist1)
                    return false;

                const auto suffix_begin = std::next(first1, dist1 - dist2);
                return std::equal(suffix_begin, last1, first2, last2, Comparer());
            }
        };

        // Custom Comparison
        // --------------------------------------------------------------------

        template <typename T>
        struct iequal_to
        {
            bool operator()(const T& a, const T& b) const
            {
                static_assert(sizeof(T) == 0,
                    "iequal_to needs a specialized overload for type");
            }
        };

        /**
        * <summary>
        *   Binary predicate for comparing two wide characters case insensitively
        *   Does not handle all locales
        * </summary>
        */
        template <>
        struct iequal_to<wchar_t>
        {
            bool operator()(const wchar_t& a, const wchar_t& b) const
            {
                return towupper(a) == towupper(b);
            }
        };

        /**
        * <summary>
        *   Binary predicate for comparing two characters case insensitively
        *   Does not handle all locales
        * </summary>
        */
        template <>
        struct iequal_to<char>
        {
            bool operator()(const char& a, const char& b) const
            {
                return toupper(a) == toupper(b);
            }
        };

    } /* namespace comparers */

} /* namespace predicates */ } /* namespace krabs */

================================================
FILE: libs/krabs/krabs/filtering/event_filter.hpp
================================================
// 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 <evntcons.h>
#include <functional>
#include <deque>
#include <vector>

#include "../compiler_check.hpp"
#include "../trace_context.hpp"

namespace krabs { namespace testing {
    class event_filter_proxy;
} /* namespace testing */} /* namespace krabs */

namespace krabs { namespace details {
    template <typename T> class base_provider;
} /* namespace details */} /* namespace krabs */


namespace krabs {

    typedef void(*c_provider_callback)(const EVENT_RECORD &, const krabs::trace_context &);
    typedef void(*c_provider_error_callback)(const EVENT_RECORD&, const std::string&);
    typedef std::function<void(const EVENT_RECORD &, const krabs::trace_context &)> provider_event_callback;
    typedef std::function<void(const EVENT_RECORD&, const std::string&)> provider_error_callback;
    typedef std::function<bool(const EVENT_RECORD &, const krabs::trace_context &)> filter_predicate;

    template <typename T> class provider;

    /**
     * <summary>
     *   Use this to provide event filtering before an event bubbles to
     *   specific callbacks.
     * </summary>
     * <remarks>
     *   Each event_filter has a single predicate (which can do complicated
     *   checks and logic on the event). All callbacks registered under the
     *   filter are invoked only if the predicate returns true for a given
     *   event.
     * </remarks>
     */
    class event_filter {
    public:

        /**
         * <summary>
         *   Constructs an event_filter that applies the given predicate to all
         *   events.
         * </summary>
         */
        event_filter(filter_predicate predicate);

        /**
         * <summary>
         *   Constructs an event_filter that applies event id filtering by event_id
         *   which will be added to list of filtered event ids in ETW API.
         *   This way is more effective from performance point of view.
         *   Given optional predicate will be applied to ETW API filtered results
         * </summary>
         */
        event_filter(unsigned short event_id, filter_predicate predicate=nullptr);

        /**
         * <summary>
         *   Constructs an event_filter that applies event id filtering by event_id
         *   which will be added to list of filtered event ids in ETW API.
         *   This way is more effective from performance point of view.
         *   Given optional predicate will be applied to ETW API filtered results
         * </summary>
         */
        event_filter(std::vector<unsigned short> event_ids, filter_predicate predicate = nullptr);

        /**
         * <summary>
         * Adds a function to call when an event for this filter is fired.
         * </summary>
         */
        void add_on_event_callback(c_provider_callback callback);

        template <typename U>
        void add_on_event_callback(U &callback);

        template <typename U>
        void add_on_event_callback(const U &callback);

        /**
         * <summary>
         * Adds a function to call when an error occurs.
         * </summary>
         */
        void add_on_error_callback(c_provider_error_callback callback);

        template <typename U>
        void add_on_error_callback(U& callback);

        template <typename U>
        void add_on_error_callback(const U& callback);

        const std::vector<unsigned short>& provider_filter_event_ids() const
        {
            return provider_filter_event_ids_;
        }

    private:

        /**
         * <summary>
         *   Called when an event occurs, forwards to callbacks if the event
         *   satisfies the predicate.
         * </summary>
         */
        void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const;

        /**
         * <summary>
         *   Called when an error occurs, forwards to the error callback
         * </summary>
         */
        void on_error(const EVENT_RECORD& record, const std::string& error_message) const;

    private:
        std::deque<provider_event_callback> event_callbacks_;
        std::deque<provider_error_callback> error_callbacks_;
        filter_predicate predicate_{ nullptr };
        std::vector<unsigned short> provider_filter_event_ids_;

    private:
        template <typename T>
        friend class details::base_provider;

        friend class krabs::testing::event_filter_proxy;
    };

    // Implementation
    // ------------------------------------------------------------------------

    inline event_filter::event_filter(filter_predicate predicate)
    : predicate_(predicate)
    {}

    inline event_filter::event_filter(std::vector<unsigned short> event_ids, filter_predicate predicate/*=nullptr*/)
    : provider_filter_event_ids_{ event_ids },
      predicate_(predicate)
    {}

    inline event_filter::event_filter(unsigned short event_id, filter_predicate predicate/*=nullptr*/)
    : provider_filter_event_ids_{ event_id },
      predicate_(predicate)
    {}

    inline void event_filter::add_on_event_callback(c_provider_callback callback)
    {
        // C function pointers don't interact well with std::ref, so we
        // overload to take care of this scenario.
        event_callbacks_.push_back(callback);
    }

    template <typename U>
    void event_filter::add_on_event_callback(U &callback)
    {
        // std::function copies its argument -- because our callbacks list
        // is a list of std::function, this causes problems when a user
        // intended for their particular instance to be called.
        // std::ref lets us get around this and point to a specific instance
        // that they handed us.
        event_callbacks_.push_back(std::ref(callback));
    }

    template <typename U>
    void event_filter::add_on_event_callback(const U &callback)
    {
        // This is where temporaries bind to. Temporaries can't be wrapped in
        // a std::ref because they'll go away very quickly. We are forced to
        // actually copy these.
        event_callbacks_.push_back(callback);
    }

    inline void event_filter::add_on_error_callback(c_provider_error_callback callback)
    {
        // C function pointers don't interact well with std::ref, so we
        // overload to take care of this scenario.
        error_callbacks_.push_back(callback);
    }

    template <typename U>
    void event_filter::add_on_error_callback(U& callback)
    {
        // std::function copies its argument -- because our callbacks list
        // is a list of std::function, this causes problems when a user
        // intended for their particular instance to be called.
        // std::ref lets us get around this and point to a specific instance
        // that they handed us.
        error_callbacks_.push_back(std::ref(callback));
    }

    template <typename U>
    void event_filter::add_on_error_callback(const U& callback)
    {
        // This is where temporaries bind to. Temporaries can't be wrapped in
        // a std::ref because they'll go away very quickly. We are forced to
        // actually copy these.
        error_callbacks_.push_back(callback);
    }

    inline void event_filter::on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
    {
        if (event_callbacks_.empty()) {
            return;
        }

        try
        {
            if (predicate_ != nullptr && !predicate_(record, trace_context)) {
                return;
            }

            for (auto& callback : event_callbacks_) {
                callback(record, trace_context);
            }
        }
        catch (const krabs::could_not_find_schema& ex)
        {
            // this occurs when a predicate is applied to an event for which
            // no schema exists. instead of allowing the exception to halt
            // the entire trace, send a notification to the filter's error callback
            for (auto& error_callback : error_callbacks_) {
                error_callback(record, ex.what());
            }
        }
    }
} /* namespace krabs */


================================================
FILE: libs/krabs/krabs/filtering/predicates.hpp
================================================
// 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 <evntcons.h>
#include <functional>
#include <algorithm>
#include <string>

#include "../compiler_check.hpp"
#include "comparers.hpp"
#include "../trace_context.hpp"
#include "view_adapters.hpp"

using namespace krabs::predicates::adapters;
using namespace krabs::predicates::comparers;

namespace krabs { namespace predicates {

    namespace details {

        /**
         * <summary>
         *   The base predicate struct, use to create a vector or list of
         *   Arbitrary predicate types
         * </summary>
         */
        struct predicate_base
        {
            virtual bool operator()(const EVENT_RECORD&, const krabs::trace_context&) const = 0;
        };

        /**
         * <summary>
         *   Returns true for any event.
         * </summary>
         */
        struct any_event : predicate_base {
            bool operator()(const EVENT_RECORD &, const krabs::trace_context &) const
            {
                return true;
            }
        };

        /**
         * <summary>
         *   Returns false for any event.
         * </summary>
         */
        struct no_event : predicate_base {
            bool operator()(const EVENT_RECORD &, const krabs::trace_context &) const
            {
                return false;
            }
        };

        /**
         * <summary>
         *   Performs a logical AND on two filters.
         * </summary>
         */
        template <typename T1, typename T2>
        struct and_filter : predicate_base {
            and_filter(const T1 &t1, const T2 &t2)
                : t1_(t1)
                , t2_(t2)
            {}

            bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
            {
                return (t1_(record, trace_context) && t2_(record, trace_context));
            }

        private:
            const T1 t1_;
            const T2 t2_;
        };

        /**
         * <summary>
         *   Performs a logical OR on two filters.
         * </summary>
         */
        template <typename T1, typename T2>
        struct or_filter : predicate_base {
            or_filter(const T1 &t1, const T2 &t2)
                : t1_(t1)
                , t2_(t2)
            {}

            bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
            {
                return (t1_(record, trace_context) || t2_(record, trace_context));
            }

        private:
            const T1 t1_;
            const T2 t2_;
        };

        /**
         * <summary>
         *   Performs a logical NOT on a filter.
         * </summary>
         */
        template <typename T1>
        struct not_filter : predicate_base {
            not_filter(const T1 &t1)
                : t1_(t1)
            {}

            bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
            {
                return !t1_(record, trace_context);
            }

        private:
            const T1 t1_;
        };

        /**
        * <summary>
        *   Returns true if the event property matches the expected value.
        * </summary>
        */
        template <typename T>
        struct property_is : predicate_base {
            property_is(const std::wstring &property, const T &expected)
                : property_(property)
                , expected_(expected)
            {}

            bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
            {
                krabs::schema schema(record, trace_context.schema_locator);
                krabs::parser parser(schema);

                try {
                    return (expected_ == parser.parse<T>(property_));
                }
                catch (...) {
                    return false;
                }
            }

        private:
            const std::wstring property_;
            const T expected_;
        };

        /**
         * <summary>
         *   Gets a collection_view of a property using the specified adapter
         *   and executes the specified predicate against the view.
         *   This is used to provide type-specialization for properties
         *   that can be represented by the collection_view.
         * </summary>
         */
        template <typename T, typename Adapter, typename Predicate>
        struct property_view_predicate : details::predicate_base
        {
            property_view_predicate(
                const std::wstring &property,
                const T &expected,
                Adapter adapter,
                Predicate predicate)
                : property_(property)
                , expected_(expected)
                , adapter_(adapter)
                , predicate_(predicate)
            { }

            //bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
            bool operator()(const EVENT_RECORD& record, const krabs::trace_context& trace_context) const
            {
                krabs::schema schema(record, trace_context.schema_locator);
                krabs::parser parser(schema);

                try {
                    auto view = parser.view_of(property_, adapter_);
                    return predicate_(view.begin(), view.end(), expected_.begin(), expected_.end());
                }
                catch (...) {
                    return false;
                }
            }

        private:
            const std::wstring property_;
            const T expected_;
            Adapter adapter_;
            Predicate predicate_;
        };
    } /* namespace details */

    // Filter factory functions
    // ------------------------------------------------------------------------

    /**
     * <summary>
     *   A simple filter that accepts any event.
     * </summary>
     */
    static details::any_event any_event;

    /**
     * <summary>
     *   A simple filter that accepts no events.
     * </summary>
     */
    static details::no_event no_event;

    /**
     * <summary>
     *   Accepts an event if its ID matches the expected value.
     * </summary>
     */
    struct id_is : details::predicate_base {
        id_is(size_t expected)
        : expected_(USHORT(expected))
        {}

        bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
        {
            return (record.EventHeader.EventDescriptor.Id == expected_);
        }

    private:
        USHORT expected_;
    };

    /**
     * <summary>
     *   Accepts an event if its opcode matches the expected value.
     * </summary>
     */
    struct opcode_is : details::predicate_base {
        opcode_is(size_t expected)
        : expected_(USHORT(expected))
        {}

        bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
        {
            return (record.EventHeader.EventDescriptor.Opcode == expected_);
        }

    private:
        USHORT expected_;
    };

    /**
     * <summary>
     *   Accepts an event if any of the predicates in the vector matches
     * </summary>
     */
    struct any_of : details::predicate_base {
        any_of(std::vector<details::predicate_base*> list)
        : list_(list)
        {}

        bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
        {
            for (auto &item : list_) {
                if (item->operator()(record, trace_context)) {
                    return true;
                };
            }
            return false;
        }
    private:
        std::vector<details::predicate_base*> list_;
    };

    /**
     * <summary>
     *   Accepts an event if all of the predicates in the vector matches
     * </summary>
     */
    struct all_of : details::predicate_base {
        all_of(std::vector<details::predicate_base*> list)
            : list_(list)
        {}

        bool operator()(const EVENT_RECORD& record, const krabs::trace_context& trace_context) const
        {
            if (list_.empty()) {
                return false;
            }
            for (auto& item : list_) {
                if (!item->operator()(record, trace_context)) {
                    return false;
                };
            }
            return true;
        }
    private:
        std::vector<details::predicate_base*> list_;
    };

    /**
     * <summary>
     *   Accepts an event only if none of the predicates in the vector match
     * </summary>
     */
    struct none_of : details::predicate_base {
        none_of(std::vector<details::predicate_base*> list)
            : list_(list)
        {}

        bool operator()(const EVENT_RECORD& record, const krabs::trace_context& trace_context) const
        {
            for (auto& item : list_) {
                if (item->operator()(record, trace_context)) {
                    return false;
                };
            }
            return true;
        }
    private:
        std::vector<details::predicate_base*> list_;
    };

    /**
     * <summary>
     *   Accepts an event if its version matches the expected value.
     * </summary>
     */
    struct version_is : details::predicate_base {
        version_is(size_t expected)
        : expected_(USHORT(expected))
        {}

        bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
        {
            return (record.EventHeader.EventDescriptor.Version == expected_);
        }

    private:
        USHORT expected_;
    };

    /**
    * <summary>
    *   Accepts an event if its PID matches the expected value.
    * </summary>
    */
    struct process_id_is : details::predicate_base {
        process_id_is(size_t expected)
        : expected_(ULONG(expected))
        {}

        bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
        {
            return (record.EventHeader.ProcessId == expected_);
        }

    private:
        ULONG expected_;
    };

    /**
     * <summary>
     *   Accepts an event if the named property matches the expected value.
     * </summary>
     */
    template <typename T>
    details::property_is<T> property_is(
        const std::wstring &prop,
        const T &expected)
    {
        return details::property_is<T>(prop, expected);
    }

     /**
      * <summary>
      *   Explicit specialization for string arrays, because C++.
      * </summary>
      */
    inline details::property_is<std::wstring> property_is(
        const std::wstring &prop,
        const wchar_t *expected)
    {
        return details::property_is<std::wstring>(prop, std::wstring(expected));
    }

    inline details::property_is<std::string> property_is(
        const std::wstring &prop,
        const char *expected)
    {
        return details::property_is<std::string>(prop, std::string(expected));
    }

    // View-based filters
    // ------------------------------------------------------------------------

    /**
     * View based filters work on ranges of data in-place in the etw record.
     * By default, these expect a null terminated string property in the
     * record, but if an adapter is specified, any range of data can be
     * compared. The comparison functor must support taking two iterator
     * pairs that iterate the value_type specified by the adapter. Because
     * comparisons use iterators, it's possible to compare various flavors
     * of strings as well as arrays and binary data.
     */

    /**
     * Accepts events if property exactly matches the expected value
     */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = equals<std::equal_to<typename Adapter::value_type>>>
    details::property_view_predicate<T, Adapter, Comparer> property_equals(
        const std::wstring &prop,
        const T& expected)
    {
        return { prop, expected, Adapter(), Comparer() };
    }

    /**
     * Accepts events if property case insensitive matches the expected value
     */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = equals<iequal_to<typename Adapter::value_type>>>
    details::property_view_predicate<T, Adapter, Comparer> property_iequals(
        const std::wstring &prop,
        const T& expected)
    {
        return{ prop, expected, Adapter(), Comparer() };
    }

    /**
     * Accepts events if property contains expected value
     */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = contains<std::equal_to<typename Adapter::value_type>>>
    details::property_view_predicate<T, Adapter, Comparer> property_contains(
        const std::wstring &prop,
        const T& expected)
    {
        return {prop, expected, Adapter(), Comparer()};
    }

    /**
     * Accepts events if property case insensitive contains expected value
     */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = contains<iequal_to<typename Adapter::value_type>>>
    details::property_view_predicate<T, Adapter, Comparer> property_icontains(
        const std::wstring &prop,
        const T& expected)
    {
        return{ prop, expected, Adapter(), Comparer() };
    }

    /**
     * Accepts events if property starts with expected value
     */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = starts_with<std::equal_to<typename Adapter::value_type>>>
    details::property_view_predicate<T, Adapter, Comparer> property_starts_with(
        const std::wstring &prop,
        const T& expected)
    {
        return{ prop, expected, Adapter(), Comparer() };
    }

    /**
     * Accepts events if property case insensitive starts with expected value
     */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = starts_with<iequal_to<typename Adapter::value_type>>>
    details::property_view_predicate<T, Adapter, Comparer> property_istarts_with(
        const std::wstring &prop,
        const T& expected)
    {
        return{ prop, expected, Adapter(), Comparer() };
    }

    /**
    * Accepts events if property ends with expected value
    */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = ends_with<std::equal_to<typename Adapter::value_type>>>
        details::property_view_predicate<T, Adapter, Comparer> property_ends_with(
            const std::wstring &prop,
            const T& expected)
    {
        return{ prop, expected, Adapter(), Comparer() };
    }

    /**
    * Accepts events if property case insensitive ends with expected value
    */
    template <
        typename Adapter = adapters::generic_string<wchar_t>,
        typename T,
        typename Comparer = ends_with<iequal_to<typename Adapter::value_type>>>
        details::property_view_predicate<T, Adapter, Comparer> property_iends_with(
            const std::wstring &prop,
            const T& expected)
    {
        return{ prop, expected, Adapter(), Comparer() };
    }

    /**
     * <summary>
     *   Accepts an event if its two component filters both accept the event.
     * </summary>
     */
    template <typename T1, typename T2>
    details::and_filter<T1, T2> and_filter(const T1 &t1, const T2 &t2)
    {
        return details::and_filter<T1, T2>(t1, t2);
    }

    /**
     * <summary>
     *   Accepts an event if either of its two component filters accept the event.
     * </summary>
     */
    template <typename T1, typename T2>
    details::or_filter<T1, T2> or_filter(const T1 &t1, const T2 &t2)
    {
        return details::or_filter<T1, T2>(t1, t2);
    }

    /**
     * <summary>
     *   Negates the filter that is given to it.
     * </summary>
     */
    template <typename T1>
    details::not_filter<T1> not_filter(const T1 &t1)
    {
        return details::not_filter<T1>(t1);
    }

} /* namespace predicates */ } /* namespace krabs */


================================================
FILE: libs/krabs/krabs/filtering/view_adapters.hpp
================================================
// 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 <string>

#include "../compiler_check.hpp"
#include "../parser.hpp"

namespace krabs { namespace predicates {

    namespace adapters {

        /**
        * View adapter for counted_string strings
        */
        struct counted_string
        {
            using value_type = krabs::counted_string::value_type;
            using const_iterator = krabs::counted_string::const_iterator;

            collection_view<const_iterator> operator()(const property_info& propInfo) const
            {
                auto cs_ptr = reinterpret_cast<const krabs::counted_string*>(propInfo.pPropertyIndex_);
                return krabs::view(cs_ptr->string(), cs_ptr->length());
            }
        };
        
        /**
         * View adapter for fixed width and null-terminated strings
         */
        template <typename ElemT>
        struct generic_string
        {
            using value_type = ElemT;
            using const_iterator = const value_type*;

            collection_view<const_iterator> operator()(const property_info& propInfo) const
            {
                auto pString = reinterpret_cast<const value_type*>(propInfo.pPropertyIndex_);
                auto length = get_string_content_length(pString, propInfo.length_);

                return krabs::view(pString, length);
            }
        };

    } /* namespace adapters */

} /* namespace predicates */ } /* namespace krabs */

================================================
FILE: libs/krabs/krabs/guid.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#pragma once

#ifndef  WIN32_LEAN_AND_MEAN
#define  WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <objbase.h>

#include <new>
#include <memory>
#include <sstream>
#include <iomanip>
#include <cassert>

#include "compiler_check.hpp"

namespace krabs {

    /** <summary>
     * Represents a GUID, allowing simplified construction from a string or
     * Windows GUID structure.
     * </summary>
     */
    class guid {
    public:
        guid(GUID guid);
        guid(const std::wstring &guid);

        bool operator==(const guid &rhs) const;
        bool operator==(const GUID &rhs) const;

        bool operator<(const guid &rhs) const;
        bool operator<(const GUID &rhs) const;

        operator GUID() const;
        operator const GUID*() const;

        /** <summary>
          * Constructs a new random guid.
          * </summary>
          */
        static inline guid random_guid();

    private:
        GUID guid_;

        friend struct std::hash<guid>;
    };

    /** <summary>
      * Helper functions for parsing GUID's.
      * </summary>
      */
    class guid_parser {
        // Implementing in Krabs instead of Lobsters so that we can test it in unmanaged code.
    private:
        // Number of characters in the UUID's 8-4-4-4-12 string format.
        static const size_t UUID_STRING_LENGTH = 36;

        static const unsigned char DELIMITER = '-';

        // Expected character positions of runs of hex digits in 8-4-4-4-12 format, e.g.
        // 00000000-0000-0000-0000-000000000000
        // Names correspond to struct members of GUID.
        static const size_t STR_POSITION_DATA1 = 0;
        static const size_t STR_POSITION_DATA2 = 8 + 1;
        static const size_t STR_POSITION_DATA3 = STR_POSITION_DATA2 + 4 + 1;
        static const size_t STR_POSITION_DATA4_PART1 = STR_POSITION_DATA3 + 4 + 1;
        static const size_t STR_POSITION_DATA4_PART2 = STR_POSITION_DATA4_PART1 + 4 + 1;

    public:
        // str_input must have at least 2 valid chars in allocated buffer
        static bool hex_octet_to_byte(const char* str_input, unsigned char& byte_output);
        // str_input must have at least 2*sizeof(T) valid chars in allocated buffer
        template<typename T>
        static bool hex_string_to_number(const char* str_input, T& int_output);
        // str_input must have at least 2*byte_count valid chars in allocated buffer,
        // and byte_output must have at least byte_count bytes in allocated buffer
        static bool hex_string_to_bytes(const char* str_input, unsigned char* byte_output, size_t byte_count);
        
        /** <summary>
          * Parses GUID of "D" format. For example, the nil GUID would be "00000000-0000-0000-0000-000000000000".
          * See: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netframework-4.8
          *
          * (str) must have at least (length) valid characters for memory safety. A null terminator is not
          * required. Instead, (length) is used for the bounds check.
          *
          * Returns the parsed GUID. Throws a std::runtime_error if there is a bounds error or format error.
          *
          * This function is for performance, to help deal with container ID extended data, which has no null
          * terminator, which would force us to clone the data to append a null terminator in order to use
          * existing GUID parsing functions.
          * </summary>
          */
        static GUID parse_guid(const char* str, unsigned int length);
    };

    // Implementation
    // ------------------------------------------------------------------------

    inline guid::guid(GUID guid)
        : guid_(guid)
    {}

    inline guid::guid(const std::wstring &guid)
    {
        HRESULT hr = CLSIDFromString(guid.c_str(), &guid_);
        if (FAILED(hr)) {
#pragma warning(push)
#pragma warning(disable: 4244) // narrowing guid wchar_t to char for this error message
            std::string guidStr(guid.begin(), guid.end());
#pragma warning(pop)
            std::stringstream stream;
            stream << "Error in constructing guid from string (";
            stream << guidStr;
            stream << "), hr = 0x";
            stream << std::hex << hr;
            throw std::runtime_error(stream.str());
        }
    }

    inline bool guid::operator==(const guid &rhs) const
    {
        return (0 == memcmp(&guid_, &rhs.guid_, sizeof(GUID)));
    }

    inline bool guid::operator==(const GUID &rhs) const
    {
        return (0 == memcmp(&guid_, &rhs, sizeof(GUID)));
    }

    inline bool guid::operator<(const guid &rhs) const
    {
        return (memcmp(&guid_, &rhs.guid_, sizeof(guid_)) < 0);
    }

    inline bool guid::operator<(const GUID &rhs) const
    {
        return (memcmp(&guid_, &rhs, sizeof(guid_)) < 0);
    }

    inline guid::operator GUID() const
    {
        return guid_;
    }

    inline guid::operator const GUID*() const
    {
        return &guid_;
    }

    inline guid guid::random_guid()
    {
        GUID tmpGuid;
        CoCreateGuid(&tmpGuid);
        return guid(tmpGuid);
    }

    struct CoTaskMemDeleter {
        void operator()(wchar_t *mem) {
            CoTaskMemFree(mem);
        }
    };

    inline bool guid_parser::hex_octet_to_byte(const char* str_input, unsigned char& byte_output)
    {
        // Accepts chars '0' through '9' (0x30 to 0x39),
        // 'A' through 'F' (0x41 to 0x46)
        // 'a' through 'f' (0x61 to 0x66)

        // Narrow the value later, for safety checking.
        auto value = 0;
        // most significant digit in the octet
        auto msd = str_input[0];
        // least significant digit in the octet
        auto lsd = str_input[1];

        if (msd >= '0' && msd <= '9')
        {
            value |= ((int)msd & 0x0F) << 4;
        }
        else if ((msd >= 'A' && msd <= 'F') || (msd >= 'a' && msd <= 'f'))
        {
            value |= (((int)msd & 0x0F) + 9) << 4;
        }
        else
        {
            return false;
        }

        if (lsd >= '0' && lsd <= '9')
        {
            value |= ((int)lsd & 0x0F);
        }
        else if ((lsd >= 'A' && lsd <= 'F') || (lsd >= 'a' && lsd <= 'f'))
        {
            value |= (((int)lsd & 0x0F) + 9);
        }
        else
        {
            return false;
        }

        assert(value >= 0 && value <= UCHAR_MAX);
        byte_output = static_cast<unsigned char>(value);
        return true;
    }

    template<typename T>
    bool guid_parser::hex_string_to_number(const char* str_input, T& int_output)
    {
        auto byte_count = sizeof(T);
        T value = 0;
        unsigned char byte = 0;

        for (size_t i = 0; i < byte_count; i++)
        {
            if (!guid_parser::hex_octet_to_byte(str_input + i * 2, byte))
            {
                return false;
            }

            value = (value << 8) | static_cast<T>(byte);
        }

        int_output = value;
        return true;
    }

    inline bool guid_parser::hex_string_to_bytes(const char* str_input, unsigned char* byte_output, size_t byte_count)
    {
        for (size_t i = 0; i < byte_count; i++)
        {
            if (!hex_octet_to_byte(str_input + (i * 2), byte_output[i]))
            {
                return false;
            }
        }

        return true;
    }

    /** <summary>
      * Parses GUID of "D" format. For example, the nil GUID would be "00000000-0000-0000-0000-000000000000".
      * See: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netframework-4.8
      *
      * (str) must have at least (length) valid characters for memory safety. A null terminator is not
      * required. Instead, (length) is used for the bounds check.
      *
      * Returns the parsed GUID. Throws a std::runtime_error if there is a bounds error or format error.
      * 
      * This function is for performance, to help deal with container ID extended data, which has no null 
      * terminator, which would force us to clone the data to append a null terminator in order to use 
      * existing GUID parsing functions.
      * </summary>
      */
    inline GUID guid_parser::parse_guid(const char* str, unsigned int length)
    {
        if (length != UUID_STRING_LENGTH)
        {
            std::stringstream message;
            message << "Input data has incorrect length. Expected "
                << UUID_STRING_LENGTH
                << ", got "
                << length;
            throw std::runtime_error(message.str());
        }

        GUID guid = { 0 };

        // Check that hyphens are in expected places as a formatting issue.
        if (str[STR_POSITION_DATA2 - 1] != DELIMITER ||
            str[STR_POSITION_DATA3 - 1] != DELIMITER ||
            str[STR_POSITION_DATA4_PART1 - 1] != DELIMITER ||
            str[STR_POSITION_DATA4_PART2 - 1] != DELIMITER)
        {
            throw std::runtime_error("Missing a hyphen where one was expected.");
        }

        // Use from_hex_string for Data1, Data2, and Data3 because of endianness of the data
        // Use hex_string_to_bytes for Data4's array elements because it's byte by byte instead
        auto success = guid_parser::hex_string_to_number(str + STR_POSITION_DATA1, guid.Data1)
            && guid_parser::hex_string_to_number(str + STR_POSITION_DATA2, guid.Data2)
            && guid_parser::hex_string_to_number(str + STR_POSITION_DATA3, guid.Data3)
            && guid_parser::hex_string_to_bytes(str + STR_POSITION_DATA4_PART1, reinterpret_cast<unsigned char*>(&guid.Data4[0]), 2)
            && guid_parser::hex_string_to_bytes(str + STR_POSITION_DATA4_PART2, reinterpret_cast<unsigned char*>(&guid.Data4[2]), 6);

        if (!success)
        {
            throw std::runtime_error("GUID string contains non-hex digits where hex digits are expected.");
        }

        return guid;
    }
}

namespace std
{
    /*
    * Converts a krabs GUID to a wide string
    */
    inline std::wstring to_wstring(const krabs::guid& guid)
    {
        wchar_t* guidString;
        HRESULT hr = StringFromCLSID(guid, &guidString);

        if (FAILED(hr)) throw std::bad_alloc();

        std::unique_ptr<wchar_t, krabs::CoTaskMemDeleter> managed(guidString);

        return { managed.get() };
    }

    /*
    * Converts a Windows GUID to a C string
    */
    inline std::string to_string(const GUID& guid)
    {
        char guid_string[37]; // 32 hex chars + 4 hyphens + null terminator
        snprintf(
            guid_string, sizeof(guid_string),
            "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
            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]);
        return guid_string;
    }

    template<>
    struct std::hash<krabs::guid>
    {
        size_t operator()(const krabs::guid& guid) const
        {
            // This algorithm comes from .NET's reference source for Guid.GetHashCode()
            return guid.guid_.Data1 ^
                 ((guid.guid_.Data2    << 16) | guid.guid_.Data3   ) ^
                 ((guid.guid_.Data4[2] << 24) | guid.guid_.Data4[7]);
        }
    };
}


================================================
FILE: libs/krabs/krabs/kernel_guids.hpp
================================================
// 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 <guiddef.h>

#include "compiler_check.hpp"

namespace krabs { namespace guids {

DEFINE_GUID ( /* 45d8cccd-539f-4b72-a8b7-5c683142609a */
    alpc,
    0x45d8cccd,
    0x539f,
    0x4b72,
    0xa8, 0xb7, 0x5c, 0x68, 0x31, 0x42, 0x60, 0x9a
  );

DEFINE_GUID ( /* 13976d09-a327-438c-950b-7f03192815c7 */
    debug,
    0x13976d09,
    0xa327,
    0x438c,
    0x95, 0x0b, 0x7f, 0x03, 0x19, 0x28, 0x15, 0xc7
  );

DEFINE_GUID ( /* 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c */
    disk_io,
    0x3d6fa8d4,
    0xfe05,
    0x11d0,
    0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
  );

DEFINE_GUID ( /* 01853a65-418f-4f36-aefc-dc0f1d2fd235 */
    event_trace_config,
    0x01853a65,
    0x418f,
    0x4f36,
    0xae, 0xfc, 0xdc, 0x0f, 0x1d, 0x2f, 0xd2, 0x35
  );

DEFINE_GUID ( /* 90cbdc39-4a3e-11d1-84f4-0000f80464e3 */
    file_io,
    0x90cbdc39,
    0x4a3e,
    0x11d1,
    0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3
  );

DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */
    image_load,
    0x2cb15d1d,
    0x5fc1,
    0x11d2,
    0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18
  );

DEFINE_GUID ( /* 3d6fa8d3-fe05-11d0-9dda-00c04fd7ba7c */
    page_fault,
    0x3d6fa8d3,
    0xfe05,
    0x11d0,
    0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
  );

DEFINE_GUID ( /* ce1dbfb4-137e-4da6-87b0-3f59aa102cbc */
    perf_info,
    0xce1dbfb4,
    0x137e,
    0x4da6,
    0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc
  );

DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */
    process,
    0x3d6fa8d0,
    0xfe05,
    0x11d0,
    0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
  );

DEFINE_GUID ( /* AE53722E-C863-11d2-8659-00C04FA321A1 */
    registry,
    0xae53722e,
    0xc863,
    0x11d2,
    0x86, 0x59, 0x0, 0xc0, 0x4f, 0xa3, 0x21, 0xa1
  );

DEFINE_GUID ( /* d837ca92-12b9-44a5-ad6a-3a65b3578aa8 */
    split_io,
    0xd837ca92,
    0x12b9,
    0x44a5,
    0xad, 0x6a, 0x3a, 0x65, 0xb3, 0x57, 0x8a, 0xa8
  );

DEFINE_GUID ( /* 9a280ac0-c8e0-11d1-84e2-00c04fb998a2 */
    tcp_ip,
    0x9a280ac0,
    0xc8e0,
    0x11d1,
    0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2
  );

DEFINE_GUID ( /* 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c */
    thread,
    0x3d6fa8d1,
    0xfe05,
    0x11d0,
    0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
  );

DEFINE_GUID ( /* bf3a50c5-a9c9-4988-a005-2df0b7c80f80 */
    udp_ip,
    0xbf3a50c5,
    0xa9c9,
    0x4988,
    0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80
  );

DEFINE_GUID ( /* 9e814aad-3204-11d2-9a82-006008a86939 */
    system_trace,
    0x9e814aad,
    0x3204,
    0x11d2,
    0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39);

DEFINE_GUID( /* 89497f50-effe-4440-8cf2-ce6b1cdcaca7 */
    ob_trace,
    0x89497f50,
    0xeffe,
    0x4440,
    0x8c, 0xf2, 0xce, 0x6b, 0x1c, 0xdc, 0xac, 0xa7);

DEFINE_GUID( /* 0268a8b6-74fd-4302-9dd0-6e8f1795c0cf */
    pool_trace,
    0x0268a8b6,
    0x74fd,
    0x4302,
    0x9d, 0xd0, 0x6e, 0x8f, 0x17, 0x95, 0xc0, 0xcf);

DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */
    event_trace,
    0x68fdd900,
    0x4a3e,
    0x11d1,
    0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3);

DEFINE_GUID( /* 6a399ae0-4bc6-4de9-870b-3657f8947e7e */
    lost_event,
    0x6a399ae0,
    0x4bc6,
    0x4de9,
    0x87, 0x0b, 0x36, 0x57, 0xf8, 0x94, 0x7e, 0x7e);

DEFINE_GUID( /* 9aec974b-5b8e-4118-9b92-3186d8002ce5 */
    ums_event,
    0x9aec974b,
    0x5b8e,
    0x4118,
    0x9b, 0x92, 0x31, 0x86, 0xd8, 0x00, 0x2c, 0xe5);

DEFINE_GUID( /* def2fe46-7bd6-4b80-bd94-f57fe20d0ce3 */
    stack_walk,
    0xdef2fe46,
    0x7bd6,
    0x4b80,
    0xbd, 0x94, 0xf5, 0x7f, 0xe2, 0x0d, 0x0c, 0xe3);

DEFINE_GUID( /* e43445e0-0903-48c3-b878-ff0fccebdd04 */
    power,
    0xe43445e0,
    0x0903,
    0x48c3,
    0xb8, 0x78, 0xff, 0x0f, 0xcc, 0xeb, 0xdd, 0x04);

DEFINE_GUID( /* f8f10121-b617-4a56-868b-9df1b27fe32c */
    mmcss_trace,
    0xf8f10121,
    0xb617,
    0x4a56,
    0x86, 0x8b, 0x9d, 0xf1, 0xb2, 0x7f, 0xe3, 0x2c);

DEFINE_GUID( /* 3b9c9951-3480-4220-9377-9c8e5184f5cd */
    rundown,
    0x3b9c9951,
    0x3480,
    0x4220,
    0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd);

} /* namespace guids */ } /* namespace krabs */


================================================
FILE: libs/krabs/krabs/kernel_providers.hpp
================================================
// 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 "compiler_check.hpp"
#include "kernel_guids.hpp"
#include "perfinfo_groupmask.hpp"
#include "provider.hpp"

#define INITGUID
#include <Evntrace.h>

namespace krabs { namespace kernel {

#define CREATE_CONVENIENCE_KERNEL_PROVIDER(__name__, __value__, __guid__)     \
    struct __name__ : public krabs::kernel_provider                           \
    {                                                                         \
        __name__()                                                            \
        : krabs::kernel_provider(__value__, __guid__)                         \
        {}                                                                    \
    };

#define CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK(__name__, __guid__, __mask__) \
    struct __name__ : public krabs::kernel_provider                           \
    {                                                                         \
        __name__()                                                            \
        : krabs::kernel_provider(__guid__, __mask__)                          \
        {}                                                                    \
    };

    /**
     * <summary>A provider that enables ALPC events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        alpc_provider,
        EVENT_TRACE_FLAG_ALPC,
        krabs::guids::alpc);

     /**
      * <summary>A provider that enables context switch events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER(
         context_switch_provider,
         EVENT_TRACE_FLAG_CSWITCH,
         krabs::guids::thread);

    /**
     * <summary>A provider that enables debug print events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        debug_print_provider,
        EVENT_TRACE_FLAG_DBGPRINT,
        krabs::guids::debug);

    /**
     * <summary>A provider that enables file I/O name events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        disk_file_io_provider,
        EVENT_TRACE_FLAG_DISK_FILE_IO,
        krabs::guids::file_io);

    /**
     * <summary>A provider that enables disk I/O completion events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        disk_io_provider,
        EVENT_TRACE_FLAG_DISK_IO,
        krabs::guids::disk_io);

    /**
     * <summary>A provider that enables disk I/O start events.</summary>
    */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        disk_init_io_provider,
        EVENT_TRACE_FLAG_DISK_IO_INIT,
        krabs::guids::disk_io);

    /**
    * <summary>A provider that enables file I/O completion events.</summary>
    */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        file_io_provider,
        EVENT_TRACE_FLAG_FILE_IO,
        krabs::guids::file_io);

    /**
    * <summary>A provider that enables file I/O start events.</summary>
    */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        file_init_io_provider,
        EVENT_TRACE_FLAG_FILE_IO_INIT,
        krabs::guids::file_io);

    /**
     * <summary>A provider that enables thread dispatch events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        thread_dispatch_provider,
        EVENT_TRACE_FLAG_DISPATCHER,
        krabs::guids::thread);

     /**
      * <summary>A provider that enables device deferred procedure call events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER(
         dpc_provider,
         EVENT_TRACE_FLAG_DPC,
         krabs::guids::perf_info);

     /**
      * <summary>A provider that enables driver events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER(
         driver_provider,
         EVENT_TRACE_FLAG_DRIVER,
         krabs::guids::disk_io);

    /**
     * <summary>A provider that enables image load events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        image_load_provider,
        EVENT_TRACE_FLAG_IMAGE_LOAD,
        krabs::guids::image_load);

     /**
      * <summary>A provider that enables interrupt events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER(
         interrupt_provider,
         EVENT_TRACE_FLAG_INTERRUPT,
         krabs::guids::perf_info);

    /**
     * <summary>A provider that enables memory hard fault events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        memory_hard_fault_provider,
        EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS,
        krabs::guids::page_fault);

    /**
     * <summary>A provider that enables memory page fault events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        memory_page_fault_provider,
        EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS,
        krabs::guids::page_fault);

    /**
     * <summary>A provider that enables network tcp/ip events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        network_tcpip_provider,
        EVENT_TRACE_FLAG_NETWORK_TCPIP,
        krabs::guids::tcp_ip);

    /**
     * <summary>A provider that enables process events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        process_provider,
        EVENT_TRACE_FLAG_PROCESS,
        krabs::guids::process);

    /**
     * <summary>A provider that enables process counter events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        process_counter_provider,
        EVENT_TRACE_FLAG_PROCESS_COUNTERS,
        krabs::guids::process);

    /**
     * <summary>A provider that enables profiling events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        profile_provider,
        EVENT_TRACE_FLAG_PROFILE,
        krabs::guids::perf_info);

    /**
     * <summary>A provider that enables registry events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        registry_provider,
        EVENT_TRACE_FLAG_REGISTRY,
        krabs::guids::registry);

    /**
     * <summary>A provider that enables split I/O events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        split_io_provider,
        EVENT_TRACE_FLAG_SPLIT_IO,
        krabs::guids::split_io);

    /**
     * <summary>A provider that enables system call events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        system_call_provider,
        EVENT_TRACE_FLAG_SYSTEMCALL,
        krabs::guids::perf_info);

    /**
     * <summary>A provider that enables thread start and stop events.</summary>
     */
    CREATE_CONVENIENCE_KERNEL_PROVIDER(
        thread_provider,
        EVENT_TRACE_FLAG_THREAD,
        krabs::guids::thread);

     /**
      * <summary>A provider that enables file map and unmap (excluding images) events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER(
         vamap_provider,
         EVENT_TRACE_FLAG_VAMAP,
         krabs::guids::file_io);

     /**
      * <summary>A provider that enables VirtualAlloc and VirtualFree events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER(
         virtual_alloc_provider,
         EVENT_TRACE_FLAG_VIRTUAL_ALLOC,
         krabs::guids::page_fault);

     /**
      * <summary>A provider that enables Object Manager events.</summary>
      */
     CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK(
         object_manager_provider,
         krabs::guids::ob_trace,
         PERF_OB_HANDLE);

#undef CREATE_CONVENIENCE_KERNEL_PROVIDER
#undef CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK

} /* namespace kernel */ } /* namespace krabs */


================================================
FILE: libs/krabs/krabs/kt.hpp
================================================
// 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 "compiler_check.hpp"
#include "kernel_guids.hpp"
#include "perfinfo_groupmask.hpp"
#include "provider.hpp"
#include "trace.hpp"
#include "ut.hpp"
#include "version_helpers.hpp"

#include <Evntrace.h>

namespace krabs { namespace details {

    /**
     * <summary>
     *   Used as a template argument to a trace instance. This class implements
     *   code paths for kernel traces. Should never be used or seen by client
     *   code.
     * </summary>
     */
    struct kt {

        typedef krabs::kernel_provider provider_type;

        /**
         * <summary>
         *   Used to assign a name to the trace instance that is being
         *   instantiated.
         * </summary>
         * <remarks>
         *   In pre-Win8 days, there could only be a single kernel trace
         *   instance on an entire machine, and that instance had to be named
         *   a particular name. This restriction was loosened in Win8, but
         *   the trace still needs to do the right thing on older OSes.
         * </remarks>
         */
        static const std::wstring enforce_name_policy(
            const std::wstring &name);

        /**
         * <summary>
         *   Generates a value that fills the EnableFlags field in an
         *   EVENT_TRACE_PROPERTIES structure. This controls the providers that
         *   get enabled for a kernel trace.
         * </summary>
         */
        static const unsigned long construct_enable_flags(
            const krabs::trace<krabs::details::kt> &trace);

        /** 
         * <summary>
         *   Enables the providers that are attached to the given trace.
         * </summary>
         */
        static void enable_providers(
            const krabs::trace<krabs::details::kt> &trace);

        /**
         * <summary>
         *   Enables the configured kernel rundown flags.
         * </summary>
         * <remarks>
         *   This ETW feature is undocumented and should be used with caution.
         * </remarks>
         */
        static void enable_rundown(
            const krabs::trace<krabs::details::kt>& trace);

        /**
         * <summary>
         *   Decides to forward an event to any of the providers in the trace.
         * </summary>
         */
        static void forward_events(
            const EVENT_RECORD &record,
            const krabs::trace<krabs::details::kt> &trace);

        /**
         * <summary>
         *   Sets the ETW trace log file mode.
         * </summary>
         */
        static unsigned long augment_file_mode();

        /**
         * <summary>
         *   Returns the GUID of the trace session.
         * </summary>
         */
        static krabs::guid get_trace_guid();

    };

    // Implementation
    // ------------------------------------------------------------------------

    inline const std::wstring kt::enforce_name_policy(
        const std::wstring &name_hint)
    {
        if (IsWindows8OrGreater()) {
            return krabs::details::ut::enforce_name_policy(name_hint);
        }

        return KERNEL_LOGGER_NAME;
    }

    inline const unsigned long kt::construct_enable_flags(
        const krabs::trace<krabs::details::kt> &trace)
    {
        unsigned long flags = 0;
        for (auto &provider : trace.providers_) {
            flags |= provider.get().flags();
        }

        return flags;
    }

    inline void kt::enable_providers(
        const krabs::trace<krabs::details::kt> &trace)
    {
        EVENT_TRACE_GROUPMASK_INFORMATION gmi = { 0 };
        gmi.EventTraceInformationClass = EventTraceGroupMaskInformation;
        gmi.TraceHandle = trace.registrationHandle_;

        // initialise EventTraceGroupMasks to the values that have been enabled via the trace flags
        ULONG status = NtQuerySystemInformation(SystemPerformanceTraceInformation, &gmi, sizeof(gmi), nullptr);
        error_check_common_conditions(status);

        auto group_mask_set = false;
        for (auto& provider : trace.providers_) {
            auto group = provider.get().group_mask();
            PERFINFO_OR_GROUP_WITH_GROUPMASK(group, &(gmi.EventTraceGroupMasks));
            group_mask_set |= (group != 0);
        }

        if (group_mask_set) {
            // This will fail on Windows 7, so only call it if truly neccessary
            status = NtSetSystemInformation(SystemPerformanceTraceInformation, &gmi, sizeof(gmi));
            error_check_common_conditions(status);
        }

        return;
    }

    inline void kt::enable_rundown(
        const krabs::trace<krabs::details::kt>& trace)
    {
        bool rundown_enabled = false;
        ULONG rundown_flags = 0;
        for (auto& provider : trace.providers_) {
            rundown_enabled |= provider.get().rundown_enabled();
            rundown_flags |= provider.get().rundown_flags();
        }

        if (rundown_enabled) {
            ULONG status = EnableTraceEx2(trace.registrationHandle_,
                                          &krabs::guids::rundown,
                                          EVENT_CONTROL_CODE_ENABLE_PROVIDER,
                                          0,
                                          rundown_flags,
                                          0,
                                          0,
                                          NULL);
            error_check_common_conditions(status);
        }
    }


    inline void kt::forward_events(
        const EVENT_RECORD &record,
        const krabs::trace<krabs::details::kt> &trace)
    {
        for (auto &provider : trace.providers_) {
            if (provider.get().id() == record.EventHeader.ProviderId) {
                provider.get().on_event(record, trace.context_);
                return;
            }
        }

        if (trace.default_callback_ != nullptr)
            trace.default_callback_(record, trace.context_);
    }

    inline unsigned long kt::augment_file_mode()
    {
        if (IsWindows8OrGreater()) {
            return EVENT_TRACE_SYSTEM_LOGGER_MODE;
        }

        return 0;
    }

    inline krabs::guid kt::get_trace_guid()
    {
        if (IsWindows8OrGreater()) {
            return krabs::guid::random_guid();
        }

        return krabs::guid(SystemTraceControlGuid);
    }

} /* namespace details */ } /* namespace krabs */


================================================
FILE: libs/krabs/krabs/parse_types.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#pragma once

#ifndef  WIN32_LEAN_AND_MEAN
#define  WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <sddl.h>

#include <vector>
#include <type_traits>

#include "compiler_check.hpp"

namespace krabs {

    /**
     * <summary>
     *   Provided entirely for code clarity purposes.
     *   Indicates that the number is intended to be used as an ID
     * </summary>
     * <remarks>
     *   This should be turned into an _id user defined literal when our
     *   compiler decides to catch up to the times.
     * </remarks>
     * <example>
     *     id(1000);
     * </example>
     */
     template <typename T>
     T id(T n)
     {
        return n;
     }

    /**
     * <summary>
     *   Provided entirely for code clarity purposes.
     *   Indicates that the number is intended to be used as a version
     * </summary>
     * <remarks>
     *   This should be turned into a _vers user defined literal when our
     *   compiler decides to catch up to the times.
     * </remarks>
     * <example>
     *     id(1000);
     * </example>
     */
     template <typename T>
     T version(T n)
     {
        return n;
     }

    /**
     * <summary>
     *   Provided entirely for code clarity purposes.
     *   Indicates that the number is intended to be used as an opcode
     * </summary>
     * <remarks>
     *   This should be turned into a _opcode user defined literal when our
     *   compiler decides to catch up to the times.
     * </remarks>
     * <example>
     *     opcode(1000);
     * </example>
     */
     template <typename T>
     T opcode(T n)
     {
        return n;
     }


    /**
     * <summary>
     * Used to discriminate between hex ints and regular ints in ETW events.
     * </summary>
     * <remarks>
     * Q: Why in the world? I can't even.
     * A: ETW differentiates between hexints and regular ints. When
     *    record_builder validates that the input type matches the type
     *    specified in the schema, getting this wrong will cause an
     *    exception. A quick little type wrapper like this lets us
     *    discriminate based on the type and everything turns out better.
     * </remarks>
     */
    struct hexint32 {
        hexint32(int v)
        : value(v)
        {}

        int value;
    };

    struct hexint64 {
        hexint64(long long v)
        : value(v)
        {}

        long long value;
    };

    /**
     * <summary>
     * Used to support parsing and creation of binary ETW fields.
     * </summary>
     */
    struct binary {
    public:
        binary() : bytes_() { }

        binary(const BYTE* start, size_t n)
        : bytes_(start, start + n)
        { }

        const std::vector<BYTE>& bytes() const
        {
            return bytes_;
        }

    private:
        std::vector<BYTE> bytes_;
    };

    template<typename T>
    binary make_binary(const T& value, size_t n)
    {
        const auto start = (BYTE*)&value;
        return binary(start, n);
    }

    /**
     * <summary>
     * Used to handle parsing of IPv4 and IPv6 fields in an ETW record.
     * This is used in the parser class in a template specialization.
     * </summary>
     */
    struct ip_address {
        union {
            DWORD v4;
            BYTE v6[16];
        };
        bool is_ipv6;

        static ip_address from_ipv6(const BYTE* bytes)
        {
            ip_address addr;
            addr.is_ipv6 = true;
            memcpy_s(addr.v6, 16, bytes, 16);
            return addr;
        }

        static ip_address from_ipv4(DWORD val)
        {
            ip_address addr;
            addr.is_ipv6 = false;
            addr.v4 = val;
            return addr;
        }

        ip_address() {}
     };

    /**
    * <summary>
    * Used to handle parsing of socket addresses in
    * network order. This union is a convenient wrapper
    * around the type IPv4 and IPv6 types provided by
    * the Winsock (v2) APIs.
    * </summary>
    */
    struct socket_address {
        union {
            struct sockaddr sa;
            struct sockaddr_in sa_in;
            struct sockaddr_in6 sa_in6;
            struct sockaddr_storage sa_stor;
        };
        size_t size;

        static socket_address from_bytes(const BYTE* bytes, size_t size_in_bytes)
        {
            socket_address sa;
            memcpy_s(&(sa.sa_stor), sizeof sa.sa_stor, bytes, size_in_bytes);
            sa.size = size_in_bytes;
            return sa;
        }
    };

    /**
     * <summary>
     * Holds information about an property extracted from the etw schema
     * </summary>
     */
    struct property_info {
        const BYTE *pPropertyIndex_;
        const EVENT_PROPERTY_INFO *pEventPropertyInfo_;
        ULONG length_;

        property_info(
            const BYTE *offset,
            const EVENT_PROPERTY_INFO &evtPropInfo,
            ULONG length)
            : pPropertyIndex_(offset)
            , pEventPropertyInfo_(&evtPropInfo)
            , length_(length)
        { }

        property_info()
            : pPropertyIndex_(nullptr)
            , pEventPropertyInfo_(nullptr)
            , length_(0)
        { }

        inline bool found() const
        {
            return pPropertyIndex_ != nullptr;
        }
    };

    /**
    * <summary>
    * Used to handle parsing of SIDs from either a
    * SID or WBEMSID property
    * </summary>
    */
    struct sid {
        // SIDs are variable-length
        // So the 'best' way to store them is to convert to a string
        // The other-end can either print the string or call ConvertStringSidToSidA
        // to get the SID back
        std::string sid_string;

        static sid from_bytes(const BYTE* bytes, size_t size_in_bytes)
        {
            sid ws;
            LPSTR temp_sid_string;
            UNREFERENCED_PARAMETER(size_in_bytes);

            if (!ConvertSidToStringSidA((PSID)bytes, &temp_sid_string)) {
                throw std::runtime_error(
                    "Failed to get a SID from a property");
            }
            ws.sid_string = temp_sid_string;
            LocalFree(temp_sid_string);
            return ws;
        }

    private:
    };

    /**
    * <summary>
    * Used to handle parsing of Pointer Address types.
    * </summary>
    */
    struct pointer {
        /**
        * We store the pointer as an uint64_t, as it is highly unlikley
        * to be pointing to somewhere accessible to our process
        */
        uint64_t address;

        static pointer from_bytes(const BYTE* bytes, size_t size_in_bytes)
        {
            pointer pt;

            // If 32-Bit, first parse as a uint32
            // Then we can 'cast' that to our uint64_t
            if (size_in_bytes == sizeof(uint32_t)) {
                pt.address = *reinterpret_cast<const uint32_t*>(bytes);
            }
            else if (size_in_bytes == sizeof(uint64_t)) {
                pt.address = *reinterpret_cast<const uint64_t*>(bytes);
            }
            else {
                throw std::runtime_error(
                    "Failed to get a POINTER from a property");
            }

            return pt;
        }

    private:
    };


    /**
     * <summary>
     * Used to handle parsing of CountedStrings in an ETW Record.
     * This is used in the parser class in a template specialization.
     * </summary>
     */
#pragma pack(push,1)
    struct counted_string {
        using value_type = wchar_t;
        using reference = value_type&;
        using pointer = value_type*;
        using const_reference = const value_type&;
        using const_pointer = const value_type*;
        using iterator = value_type*;
        using const_iterator = const value_type*;

        /**
         * size of the string in bytes
         */
        uint16_t size_;
        wchar_t string_[1];

        const_pointer string() const
        {
            return string_;
        }

        size_t length() const
        {
            return size_ / sizeof(value_type);
        }
    };
#pragma pack(pop)

    static_assert(std::is_trivial<counted_string>::value && std::is_standard_layout<counted_string>::value , "Do not modify counted_string");

} /* namespace krabs */


================================================
FILE: libs/krabs/krabs/parser.hpp
================================================
// 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 <cassert>
#include <deque>
#include <utility>
#include <stdexcept>

#include <functional>

#include "compiler_check.hpp"
#include "collection_view.hpp"
#include "property.hpp"
#include "parse_types.hpp"
#include "size_provider.hpp"
#include "tdh_helpers.hpp"

namespace krabs {

    class schema;

    /**
     * <summary>
     * Used to parse specific properties out of an event schema.
     * </summary>
     * <remarks>
     * The parser class dodges the task of trying to validate that the expected
     * type of a field matches the actual type of a field -- the onus is on
     * client code to get this right.
     * </remarks>
     */
    class parser {
    public:

        /**
         * <summary>
         * Constructs an event parser from an event schema.
         * </summary>
         * <example>
         *     void on_event(const EVENT_RECORD &record)
         *     {
         *         krabs::schema schema(record);
         *         krabs::parser parser(schema);
         *     }
         * </example>
         */
        parser(const schema &);

        /**
         * <summary>
         * Returns an iterator that returns each property in the event.
         * </summary>
         * <example>
         *    void on_event(const EVENT_RECORD &record)
         *    {
         *        krabs::schema schema(record);
         *        krabs::parser parser(schema);
         *        for (property &property : parser.properties())
         *        {
         *            // ...
         *        }
         *    }
         * </example>
         */
        property_iterator properties() const;

        /**
         * <summary>
         * Attempts to retrieve the given property by name and type.
         * </summary>
         * <remarks>
         * Type hinting here is taken as the authoritative source. There is no
         * validation that the request for type is correct.
         * </remarks>
         */
        template <typename T>
        bool try_parse(const std::wstring &name, T &out);

        /**
         * <summary>
         * Attempts to parse the given property by name and type. If the
         * property does not exist, an exception is thrown.
         * </summary>
         */
        template <typename T>
        T parse(const std::wstring &name);

        template <typename Adapter>
        auto view_of(const std::wstring &name, Adapter &adapter) -> collection_view<typename Adapter::const_iterator>;

    private:
        property_info find_property(const std::wstring &name);
        void cache_property(const wchar_t *name, property_info info);

    private:
        const schema &schema_;
        const BYTE *pEndBuffer_;
        BYTE *pBufferIndex_;
        ULONG lastPropertyIndex_;

        // Maintain a mapping from property name to blob data index.
        std::deque<std::pair<const wchar_t *, property_info>> propertyCache_;
    };

    // Implementation
    // ------------------------------------------------------------------------

    inline parser::parser(const schema &s)
    : schema_(s)
    , pEndBuffer_((BYTE*)s.record_.UserData + s.record_.UserDataLength)
    , pBufferIndex_((BYTE*)s.record_.UserData)
    , lastPropertyIndex_(0)
    {}

    inline property_iterator parser::properties() const
    {
        return property_iterator(schema_);
    }

    inline property_info parser::find_property(const std::wstring &name)
    {
        // A schema contains a collection of properties that are keyed by name.
        // These properties are stored in a blob of bytes that needs to be
        // interpreted according to information that is packaged up in the
        // schema and that can be retrieved using the Tdh* APIs. This format
        // requires a linear traversal over the blob, incrementing according to
        // the contents within it. This is janky, so our strategy is to
        // minimize this as much as possible via caching.

        // The first step is to use our cache for the property to see if we've
        // discovered it already.
        for (auto &item : propertyCache_) {
            if (name == item.first) {
                return item.second;
            }
        }

        const ULONG totalPropCount = schema_.pSchema_->PropertyCount;

        assert((pBufferIndex_ <= pEndBuffer_ && pBufferIndex_ >= schema_.record_.UserData) &&
               "invariant: we should've already thrown for falling off the edge");

        // accept that last property can be omitted from buffer. this happens if last property
        // is string but empty and the provider strips the null terminator
        assert((pBufferIndex_ == pEndBuffer_ ? ((totalPropCount - lastPropertyIndex_) <= 1)
                                             : true)
               && "invariant: if we've exhausted our buffer, then we must've"
                  "exhausted the properties as well");

        // We've not looked up this property before, so we have to do the work
        // to find it. While we're going through the blob to find it, we'll
        // remember what we've seen to save time later.
        //
        // Question: Why don't we just populate the cache before looking up any
        //           properties and simplify our code (less state, etc)?
        //
        // Answer:   Doing that introduces overhead in the case that only a
        //           subset of properties are needed. While this code is a bit
        //           more complicated, we introduce no additional performance
        //           overhead at runtime.
        for (auto &i = lastPropertyIndex_; i < totalPropCount; ++i) {

            auto &currentPropInfo = schema_.pSchema_->EventPropertyInfoArray[i];
            const wchar_t *pName = reinterpret_cast<const wchar_t*>(
                                        reinterpret_cast<BYTE*>(schema_.pSchema_) +
                                        currentPropInfo.NameOffset);

            ULONG propertyLength = size_provider::get_property_size(
                                        pBufferIndex_,
                                        pName,
                                        schema_.record_,
                                        currentPropInfo);

            // verify that the length of the property doesn't exceed the buffer
            if (pBufferIndex_ + propertyLength > pEndBuffer_) {
                throw std::out_of_range("Property length past end of property buffer");
            }

            property_info propInfo(pBufferIndex_, currentPropInfo, propertyLength);
            cache_property(pName, propInfo);

            // advance the buffer index since we've already processed this property
            pBufferIndex_ += propertyLength;

            // The property was found, return it
            if (name == pName) {
                // advance the index since we've already processed this property
                ++i;
                return propInfo;
            }
        }

        // property wasn't found, return an empty propInfo
        return property_info();
    }

    inline void parser::cache_property(const wchar_t *name, property_info propInfo)
    {
        propertyCache_.push_front(std::make_pair(name, propInfo));
    }

    inline void throw_if_property_not_found(const property_info &propInfo)
    {
        if (!propInfo.found()) {
            throw std::runtime_error("Property with the given name does not exist");
        }
    }

    template <typename T>
    size_t get_string_content_length(const T* string, size_t lengthBytes)
    {
        // for some string types the length includes the null terminator
        // so we need to find the length of just the content part

        T nullChar {0};
        auto length = lengthBytes / sizeof(T);

        for (auto i = length; i >= 1; --i)
            if (string[i - 1] != nullChar) return i;

        return 0;
    }

    // try_parse
    // ------------------------------------------------------------------------

    template <typename T>
    bool parser::try_parse(const std::wstring &name, T &out)
    {
        try {
            out = parse<T>(name);
            return true;
        }

#ifndef NDEBUG
        // in debug builds we want any mismatch asserts
        // to get back to the caller. This is removed
        // in release builds.
        catch (const krabs::type_mismatch_assert&) {
            throw;
        }
#endif // NDEBUG

        catch (...) {
            return false;
        }
    }

    // parse
    // ------------------------------------------------------------------------

    template <typename T>
    T parser::parse(const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<T>(name, propInfo);

        // ensure that size of the type we are requesting is
        // the same size of the property in the event
        if (sizeof(T) != propInfo.length_)
            throw std::runtime_error("Property size doesn't match requested size");

        return *(T*)propInfo.pPropertyIndex_;
    }

    template<>
    inline bool parser::parse<bool>(const std::wstring& name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<bool>(name, propInfo);

        // Boolean in ETW is 4 bytes long
        return static_cast<bool>(*(unsigned*)propInfo.pPropertyIndex_);
    }

    template <>
    inline std::wstring parser::parse<std::wstring>(const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<std::wstring>(name, propInfo);

        auto string = reinterpret_cast<const wchar_t*>(propInfo.pPropertyIndex_);
        auto length = get_string_content_length(string, propInfo.length_);

        return std::wstring(string, length);
    }

    template <>
    inline std::string parser::parse<std::string>(const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<std::string>(name, propInfo);

        auto string = reinterpret_cast<const char*>(propInfo.pPropertyIndex_);
        auto length = get_string_content_length(string, propInfo.length_);

        return std::string(string, length);
    }

    template<>
    inline const counted_string* parser::parse<const counted_string*>(const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<const counted_string*>(name, propInfo);

        return reinterpret_cast<const counted_string*>(propInfo.pPropertyIndex_);
    }

    template<>
    inline binary parser::parse<binary>(const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        // no type asserts for binary - anything can be read as binary

        return binary(propInfo.pPropertyIndex_, propInfo.length_);
    }

    template<>
    inline ip_address parser::parse<ip_address>(
        const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<ip_address>(name, propInfo);

        auto outType = propInfo.pEventPropertyInfo_->nonStructType.OutType;

        switch (outType) {
        case TDH_OUTTYPE_IPV6:
            return ip_address::from_ipv6(propInfo.pPropertyIndex_);

        case TDH_OUTTYPE_IPV4:
            return ip_address::from_ipv4(*(DWORD*)propInfo.pPropertyIndex_);

        default:
            throw std::runtime_error("IP Address was not IPV4 or IPV6");
        }
    }

    template<>
    inline socket_address parser::parse<socket_address>(
        const std::wstring &name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<socket_address>(name, propInfo);

        return socket_address::from_bytes(propInfo.pPropertyIndex_, propInfo.length_);
    }

    template<>
    inline sid parser::parse<sid>(
        const std::wstring& name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<sid>(name, propInfo);
        auto InType = propInfo.pEventPropertyInfo_->nonStructType.InType;

        // A WBEMSID is actually a TOKEN_USER structure followed by the SID.
        // We only care about the SID. From MSDN:
        //
        //      The size of the TOKEN_USER structure differs
        //      depending on whether the events were generated on a 32 - bit
        //      or 64 - bit architecture. Also the structure is aligned
        //      on an 8 - byte boundary, so its size is 8 bytes on a
        //      32 - bit computer and 16 bytes on a 64 - bit computer.
        //      Doubling the pointer size handles both cases.
        ULONG sid_start = 16;
        if (EVENT_HEADER_FLAG_32_BIT_HEADER == (schema_.record_.EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER)) {
            sid_start = 8;
        }
        switch (InType) {
        case TDH_INTYPE_SID:
            return sid::from_bytes(propInfo.pPropertyIndex_, propInfo.length_);
        case TDH_INTYPE_WBEMSID:
            // Safety measure to make sure we don't overflow
            if (propInfo.length_ <= sid_start) {
                throw std::runtime_error(
                    "Requested a WBEMSID property but data is too small");
            }
            return sid::from_bytes(propInfo.pPropertyIndex_ + sid_start, propInfo.length_ - sid_start);

        default:
            throw std::runtime_error("SID was not a SID or WBEMSID");
        }
    }

    template<>
    inline pointer parser::parse<pointer>(const std::wstring& name)
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        krabs::debug::assert_valid_assignment<pointer>(name, propInfo);

        return pointer::from_bytes(propInfo.pPropertyIndex_, propInfo.length_);
    }

    // view_of
    // ------------------------------------------------------------------------

    template <typename Adapter>
    auto parser::view_of(const std::wstring &name, Adapter &adapter)
        -> collection_view<typename Adapter::const_iterator>
    {
        auto propInfo = find_property(name);
        throw_if_property_not_found(propInfo);

        // TODO: type asserts?

        return adapter(propInfo);
    }
}


================================================
FILE: libs/krabs/krabs/perfinfo_groupmask.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#ifndef PERFINFO_GROUPMASK_HPP
#define PERFINFO_GROUPMASK_HPP

#include <Windows.h>
#pragma comment(lib, "ntdll")

// https://geoffchappell.com/studies/windows/km/ntoskrnl/api/etw/tracesup/perfinfo_groupmask.htm

#define PERF_MASK_INDEX         (0xe0000000)
#define PERF_MASK_GROUP         (~PERF_MASK_INDEX)
#define PERF_NUM_MASKS          8

typedef ULONG PERFINFO_MASK;
typedef struct _PERFINFO_GROUPMASK {
    ULONG Masks[PERF_NUM_MASKS];
} PERFINFO_GROUPMASK, *PPERFINFO_GROUPMASK;

#define PERF_GET_MASK_INDEX(GM) (((GM) & PERF_MASK_INDEX) >> 29)
#define PERF_GET_MASK_GROUP(GM) ((GM) & PERF_MASK_GROUP)
#define PERFINFO_OR_GROUP_WITH_GROUPMASK(Group, pGroupMask) \
    (pGroupMask)->Masks[PERF_GET_MASK_INDEX(Group)] |= PERF_GET_MASK_GROUP(Group);

// Masks[0]
#define PERF_PROCESS            EVENT_TRACE_FLAG_PROCESS
#define PERF_THREAD             EVENT_TRACE_FLAG_THREAD
#define PERF_PROC_THREAD        EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_THREAD
#define PERF_LOADER             EVENT_TRACE_FLAG_IMAGE_LOAD
#define PERF_PERF_COUNTER       EVENT_TRACE_FLAG_PROCESS_COUNTERS
#define PERF_FILENAME           EVENT_TRACE_FLAG_DISK_FILE_IO
#define PERF_DISK_IO            EVENT_TRACE_FLAG_DISK_FILE_IO | EVENT_TRACE_FLAG_DISK_IO
#define PERF_DISK_IO_INIT       EVENT_TRACE_FLAG_DISK_IO_INIT
#define PERF_ALL_FAULTS         EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS
#define PERF_HARD_FAULTS        EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS
#define PERF_VAMAP              EVENT_TRACE_FLAG_VAMAP
#define PERF_NETWORK            EVENT_TRACE_FLAG_NETWORK_TCPIP
#define PERF_REGISTRY           EVENT_TRACE_FLAG_REGISTRY
#define PERF_DBGPRINT           EVENT_TRACE_FLAG_DBGPRINT
#define PERF_JOB                EVENT_TRACE_FLAG_JOB
#define PERF_ALPC               EVENT_TRACE_FLAG_ALPC
#define PERF_SPLIT_IO           EVENT_TRACE_FLAG_SPLIT_IO
#define PERF_DEBUG_EVENTS       EVENT_TRACE_FLAG_DEBUG_EVENTS
#define PERF_FILE_IO            EVENT_TRACE_FLAG_FILE_IO
#define PERF_FILE_IO_INIT       EVENT_TRACE_FLAG_FILE_IO_INIT
#define PERF_NO_SYSCONFIG       EVENT_TRACE_FLAG_NO_SYSCONFIG

// Masks[1]
#define PERF_MEMORY             0x20000001
#define PERF_PROFILE            0x20000002  // equivalent to EVENT_TRACE_FLAG_PROFILE
#define PERF_CONTEXT_SWITCH     0x20000004  // equivalent to EVENT_TRACE_FLAG_CSWITCH
#define PERF_FOOTPRINT          0x20000008
#define PERF_DRIVERS            0x20000010  // equivalent to EVENT_TRACE_FLAG_DRIVER
#define PERF_REFSET             0x20000020
#define PERF_POOL               0x20000040
#define PERF_POOLTRACE          0x20000041
#define PERF_DPC                0x20000080  // equivalent to EVENT_TRACE_FLAG_DPC
#define PERF_COMPACT_CSWITCH    0x20000100
#define PERF_DISPATCHER         0x20000200  // equivalent to EVENT_TRACE_FLAG_DISPATCHER
#define PERF_PMC_PROFILE        0x20000400
#define PERF_PROFILING          0x20000402
#define PERF_PROCESS_INSWAP     0x20000800
#define PERF_AFFINITY           0x20001000
#define PERF_PRIORITY           0x20002000
#define PERF_INTERRUPT          0x20004000  // equivalent to EVENT_TRACE_FLAG_INTERRUPT
#define PERF_VIRTUAL_ALLOC      0x20008000  // equivalent to EVENT_TRACE_FLAG_VIRTUAL_ALLOC
#define PERF_SPINLOCK           0x20010000
#define PERF_SYNC_OBJECTS       0x20020000
#define PERF_DPC_QUEUE          0x20040000
#define PERF_MEMINFO            0x20080000
#define PERF_CONTMEM_GEN        0x20100000
#define PERF_SPINLOCK_CNTRS     0x20200000
#define PERF_SPININSTR          0x20210000
#define PERF_SESSION            0x20400000
#define PERF_PFSECTION          0x20400000
#define PERF_MEMINFO_WS         0x20800000
#define PERF_KERNEL_QUEUE       0x21000000
#define PERF_INTERRUPT_STEER    0x22000000
#define PERF_SHOULD_YIELD       0x24000000
#define PERF_WS                 0x28000000

// Masks[2]
#define PERF_ANTI_STARVATION    0x40000001
#define PERF_PROCESS_FREEZE     0x40000002
#define PERF_PFN_LIST           0x40000004
#define PERF_WS_DETAIL          0x40000008
#define PERF_WS_ENTRY           0x40000010
#define PERF_HEAP               0x40000020
#define PERF_SYSCALL            0x40000040  // equivalent to EVENT_TRACE_FLAG_SYSTEMCALL
#define PERF_UMS                0x40000080
#define PERF_BACKTRACE          0x40000100
#define PERF_VULCAN             0x40000200
#define PERF_OBJECTS            0x40000400
#define PERF_EVENTS             0x40000800
#define PERF_FULLTRACE          0x40001000
#define PERF_DFSS               0x40002000
#define PERF_PREFETCH           0x40004000
#define PERF_PROCESSOR_IDLE     0x40008000
#define PERF_CPU_CONFIG         0x40010000
#define PERF_TIMER              0x40020000
#define PERF_CLOCK_INTERRUPT    0x40040000
#define PERF_LOAD_BALANCER      0x40080000
#define PERF_CLOCK_TIMER        0x40100000
#define PERF_IDLE_SELECTION     0x40200000
#define PERF_IPI                0x40400000
#define PERF_IO_TIMER           0x40800000
#define PERF_REG_HIVE           0x41000000
#define PERF_REG_NOTIF          0x42000000
#define PERF_PPM_EXIT_LATENCY   0x44000000
#define PERF_WORKER_THREAD      0x48000000

// Masks[4]
#define PERF_OPTICAL_IO         0x80000001
#define PERF_OPTICAL_IO_INIT    0x80000002
#define PERF_DLL_INFO           0x80000008
#define PERF_DLL_FLUSH_WS       0x80000010
#define PERF_OB_HANDLE          0x80000040
#define PERF_OB_OBJECT          0x80000080
#define PERF_WAKE_DROP          0x80000200
#define PERF_WAKE_EVENT         0x80000400
#define PERF_DEBUGGER           0x80000800
#define PERF_PROC_ATTACH        0x80001000
#define PERF_WAKE_COUNTER       0x80002000
#define PERF_POWER              0x80008000
#define PERF_SOFT_TRIM          0x80010000
#define PERF_CC                 0x80020000
#define PERF_FLT_IO_INIT        0x80080000
#define PERF_FLT_IO             0x80100000
#define PERF_FLT_FASTIO         0x80200000
#define PERF_FLT_IO_FAILURE     0x80400000
#define PERF_HV_PROFILE         0x80800000
#define PERF_WDF_DPC            0x81000000
#define PERF_WDF_INTERRUPT      0x82000000
#define PERF_CACHE_FLUSH        0x84000000

// Masks[5]
#define PERF_HIBER_RUNDOWN      0xA0000001

// Masks[6]
#define PERF_SYSCFG_SYSTEM      0xC0000001
#define PERF_SYSCFG_GRAPHICS    0xC0000002
#define PERF_SYSCFG_STORAGE     0xC0000004
#define PERF_SYSCFG_NETWORK     0xC0000008
#define PERF_SYSCFG_SERVICES    0xC0000010
#define PERF_SYSCFG_PNP         0xC0000020
#define PERF_SYSCFG_OPTICAL     0xC0000040
#define PERF_SYSCFG_ALL         0xDFFFFFFF

// Masks[7] - Control Mask. All flags that change system behavior go here.
#define PERF_CLUSTER_OFF        0xE0000001
#define PERF_MEMORY_CONTROL     0xE0000002

// TraceQueryInformation wasn't introduced until Windows 8, so we need to use
// NtQuerySystemInformation instead in order to maintain support for Windows 7.
// This requires the below additional definitions.

typedef enum _EVENT_TRACE_INFORMATION_CLASS {
    EventTraceKernelVersionInformation,
    EventTraceGroupMaskInformation,
    EventTracePerformanceInformation,
    EventTraceTimeProfileInformation,
    EventTraceSessionSecurityInformation,
    EventTraceSpinlockInformation,
    EventTraceStackTracingInformation,
    EventTraceExecutiveResourceInformation,
    EventTraceHeapTracingInformation,
    EventTraceHeapSummaryTracingInformation,
    EventTracePoolTagFilterInformation,
    EventTracePebsTracingInformation,
    EventTraceProfileConfigInformation,
    EventTraceProfileSourceListInformation,
    EventTraceProfileEventListInformation,
    EventTraceProfileCounterListInformation,
    EventTraceStackCachingInformation,
    EventTraceObjectTypeFilterInformation,
    MaxEventTraceInfoClass
} EVENT_TRACE_INFORMATION_CLASS;

typedef struct _EVENT_TRACE_GROUPMASK_INFORMATION {
    EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;
    TRACEHANDLE TraceHandle;
    PERFINFO_GROUPMASK EventTraceGroupMasks;
} EVENT_TRACE_GROUPMASK_INFORMATION, * PEVENT_TRACE_GROUPMASK_INFORMATION;

#ifndef _WINTERNL_

typedef enum _SYSTEM_INFORMATION_CLASS {
} SYSTEM_INFORMATION_CLASS;

typedef LONG NTSTATUS;

extern "C" NTSTATUS NTAPI NtQuerySystemInformation(
    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
    _In_ ULONG SystemInformationLength,
    _Out_opt_ PULONG ReturnLength
);

#endif // _WINTERNL_

extern "C" NTSTATUS NTAPI NtSetSystemInformation(
    _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
    _In_ ULONG SystemInformationLength
);

constexpr auto SystemPerformanceTraceInformation{ static_cast<SYSTEM_INFORMATION_CLASS>(0x1f) };

#endif // PERFINFO_GROUPMASK_HPP

================================================
FILE: libs/krabs/krabs/property.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#pragma once

#ifndef  WIN32_LEAN_AND_MEAN
#define  WIN32_LEAN_AND_MEAN
#endif

#define INITGUID

#include <memory>
#include <vector>

#include "compiler_check.hpp"
#include "schema.hpp"
#include "errors.hpp"

#include <windows.h>
#include <tdh.h>
#include <evntrace.h>

#pragma comment(lib, "tdh.lib")

namespace krabs {

    /**
     * <summary>
     * Represents a single property of the record schema.
     * </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>
     */
    class property {
    public:

        /**
         * <summary>
         * Constructs a property.
         * </summary>
         * <remarks>
         *   This should be instantiated by client code -- let the parser
         *   object do this for you with its `properties` method.
         * </remarks>
         */
        property(const std::wstring &name, _TDH_IN_TYPE type);

        /**
         * <summary>
         * Retrieves the name of the property.
         * </summary>
         */
        const std::wstring &name() const;

        /**
         * <summary>
         * Retrieves the Tdh type of the property.
         * </summary>
         */
        _TDH_IN_TYPE type() const;

    private:
        std::wstring name_;
        _TDH_IN_TYPE type_;
    };


    /**
     * <summary>
     * Iterates the properties in a given event record.
     * </summary>
     */
    class property_iterator {
    public:

        /**
         * <summary>
         *   Constructs a new iterator that lazily retrieves the properties of
         *   the given event record.
         * </summary>
         * <remarks>
         *   Don't construct this yourself. Let the `parser` class do it for you.
         * </remarks>
         */
        property_iterator(const schema &s);

        /**
         * <summary>
         * Returns an iterator that hasn't yielded any properties yet.
         * </summary>
         */
        std::vector<property>::iterator begin();

        /**
         * <summary>
         * Returns an iterator that has yielded all properties.
         * </summary>
         */
        std::vector<property>::iterator end();

    private:

        /**
         * <summary>
         *   Constructs a property instance out of the raw data of the
         *   given property.
         * </summary>
         */
        property get_property(size_t index) const;

        /**
         * <summary>
         * Collects the names of the properties in the schema.
         * </summary>
         * <remarks>
         *   This is a little lazy of us, as we end up iterating the properties
         *   entirely before allowing enumeration by the client. Because this
         *   code is most likely called in a non-critical path, there's not
         *   much to worry about here.
         */
         std::vector<property> enum_properties() const;


    private:
        const krabs::schema &schema_;
        size_t numProperties_;
        std::vector<property> properties_;
        std::vector<property>::iterator beg_;
        std::vector<property>::iterator end_;
        std::vector<property>::iterator curr_;
    };

    // Implementation
    // ------------------------------------------------------------------------

    inline property::property(const std::wstring &name, _TDH_IN_TYPE type)
    : name_(name)
    , type_(type)
    {}

    inline const std::wstring &property::name() const
    {
        return name_;
    }

    inline _TDH_IN_TYPE property::type() const
    {
        return type_;
    }

    // ------------------------------------------------------------------------

    inline property_iterator::property_iterator(const schema &s)
    : schema_(s)
    , numProperties_(s.pSchema_->TopLevelPropertyCount)
    , properties_(enum_properties())
    , beg_(properties_.begin())
    , end_(properties_.end())
    , curr_(properties_.begin())
    {}

    inline std::vector<property>::iterator property_iterator::begin()
    {
        return beg_;
    }

    inline std::vector<property>::iterator property_iterator::end()
    {
        return end_;
    }

    inline property property_iterator::get_property(size_t index) const
    {
        const auto &curr_prop = schema_.pSchema_->EventPropertyInfoArray[index];

        const wchar_t *pName = reinterpret_cast<const wchar_t*>(
            reinterpret_cast<BYTE*>(schema_.pSchema_) +
            curr_prop.NameOffset);

        auto tdh_type = (_TDH_IN_TYPE)curr_prop.nonStructType.InType;

        return property(pName, tdh_type);
    }

    inline std::vector<property> property_iterator::enum_properties() const
    {
        std::vector<property> props;
        for (size_t i = 0; i < numProperties_; ++i) {
            props.emplace_back(get_property(i));
        }

        return props;
    }


} /* namespace krabs */


================================================
FILE: libs/krabs/krabs/provider.hpp
================================================
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#pragma once

#define INITGUID

#include <deque>
#include <functional>

#include "compiler_check.hpp"
#include "filtering/event_filter.hpp"
#include "perfinfo_groupmask.hpp"
#include "trace_context.hpp"
#include "wstring_convert.hpp"

#include <evntcons.h>
#include <guiddef.h>
#include <pla.h>
#include <comutil.h>

#ifdef _DEBUG
#pragma comment(lib, "comsuppwd.lib")
#else
#pragma comment(lib, "comsuppw.lib")
#endif

namespace krabs { namespace details {
    template <typename T> class trace_manager;

    struct kt;
    struct ut;

} /* namespace details */ } /* namespace krabs */

namespace krabs {

    template <typename T>
    class trace;

    typedef void(*c_provider_callback)(const EVENT_RECORD &, const krabs::trace_context &);
    typedef void(*c_provider_error_callback)(const EVENT_RECORD&, const std::string&);
    typedef std::function<void(const EVENT_RECORD &, const krabs::trace_context &)> provider_callback;
    typedef std::function<void(const EVENT_RECORD&, const std::string&)> provider_error_callback;

    namespace details {

        /**
         * <summary>
         *   Serves as a base for providers and kernel_providers. Handles event
         *   registration and forwarding.
         * </summary>
         */
        template <typename T>
        class base_provider {
        public:

            /**
             * <summary>
             * Adds a function to call when an event for this provider is fired.
             * </summary>
             *
             * <param name="callback">the function to call into</param>
             * <example>
             *    void my_fun(const EVENT_RECORD &record, const krabs::trace_context &trace_context) { ... }
             *    // ...
             *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
             *    provider<> powershell(id);
             *    provider.add_on_event_callback(my_fun);
             * </example>
             *
             * <example>
             *    auto fun = [&](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {...}
             *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
             *    provider<> powershell(id);
             *    provider.add_on_event_callback(fun);
             * </example>
             */
            void add_on_event_callback(c_provider_callback callback);

            template <typename U>
            void add_on_event_callback(U &callback);

            template <typename U>
            void add_on_event_callback(const U &callback);

            /**
             * <summary>
             * Adds a function to call when an error occurs when this provider handles an event.
             * </summary>
             */
            void add_on_error_callback(c_provider_error_callback callback);

            template <typename U>
            void add_on_error_callback(U& callback);

            template <typename U>
            void add_on_error_callback(const U& callback);

            /**
             * <summary>
             *   Adds a new filter to a provider, where the filter is expected
             *   to have callbacks attached to it.
             * </summary>
             * <example>
             *   krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
             *   krabs::provider<> powershell(id);
             *   krabs::event_filter filter(krabs::filtering::any_event);
             *   filter.add_on_event_callback([&](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {...});
             *   powershell.add_filter(filter);
             * </example>
             */
            void add_filter(const event_filter &f);

        protected:

            /**
             * <summary>
             *   Called when an event occurs, forwards to callbacks and filters.
             * </summary>
             */
            void on_event(const EVENT_RECORD &record, const krabs::trace_context &context) const;

        protected:
            std::deque<provider_callback> callbacks_;
            std::deque<provider_error_callback> error_callbacks_;
            std::deque<event_filter> filters_;

        private:
            template <typename T>
            friend class details::trace_manager;

            template <typename T>
            friend class krabs::trace;

            template <typename S>
            friend class base_provider;
        };

    } // namespace details

    /**
     * <summary>
     *   Used to enable specific types of events from specific event sources in
     *   ETW. Corresponds tightly with the concept of an ETW provider. Used for
     *   user trace instances (not kernel trace instances).
     * </summary>
     *
     * <param name='T'>
     * The type of flags to use when filtering event types via any and all.
     * There is an implicitly requirement that T can be downcasted to a
     * ULONGLONG.
     * </param>
     */
    template <typename T = ULONGLONG>
    class provider : public details::base_provider<T> {
    public:

        /**
         * <summary>
         * Constructs a provider with the given guid identifier.
         * </summary>
         *
         * <param name="id">the GUID that identifies the provider.</param>
         * <example>
         *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
         *    provider<> powershell(id);
         * </example>
         */
        provider(GUID id);

        /**
        * <summary>
        * Constructs a provider with the given a provider name.
        * </summary>
        *
        * <param name="id">the provider name.</param>
        * <example>
        *    krabs::guid id(L"Microsoft-Windows-WinINet");
        *    provider<> winINet(id);
        * </example>
        */
        provider(const std::wstring &providerName);

        /**
         * <summary>
         * Sets the "any" flag of the provider.
         * </summary>
         *
         * <param name="value">the value to set <c>any</c> to.</param>
         * <example>
         *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
         *    provider<> powershell(id);
         *    powershell.any(0xFF00);
         * </example>
         */
        void any(T any);

        /**
         * <summary>
         * Sets the "all" flag of the provider.
         * </summary>
         *
         * <param name="value">the value to set <c>all</c> to.</param>
         * <example>
         *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
         *    provider<> powershell(id);
         *    powershell.all(0xFF00);
         * </example>
         */
        void all(T all);

        /**
        * <summary>
        * Sets the "level" flag of the provider. Valid values are 0~255 (0xFF).
        * </summary>
        *
        * <param name="value">the value to set <c>level</c> to.</param>
        * <example>
        *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
        *    provider<> powershell(id);
        *    powershell.level(0x00);
        * </example>
        */
        void level(T level);

        /**
        * <summary>
        * Sets the "EnableProperty" flag on the ENABLE_TRACE_PARAMETER struct.
        * These properties configure behaviours for a specified user-mode provider.
        * Valid values can be found here:
        *   https://msdn.microsoft.com/en-us/library/windows/desktop/dd392306(v=vs.85).aspx
        * </summary>
        *
        * <param name="value">the value to set</param>
        * <example>
        *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
        *    provider<> powershell(id);
        *    powershell.trace_flags(EVENT_ENABLE_PROPERTY_STACK_TRACE);
        * </example>
        */
        void trace_flags(T trace_flags);

        /**
        * <summary>
        * Gets the configured value for the "EnableProperty" flag on the 
        * ENABLE_TRACE_PARAMETER struct. See void trace_flags(T trace_flags)
        * for details on what the values mean.
        * </summary>
        * <returns>The value to set when the provider is enabled.</returns>
        * <example>
        *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
        *    provider<> powershell(id);
        *    powershell.trace_flags(EVENT_ENABLE_PROPERTY_STACK_TRACE);
        *    auto flags = powershell.get_trace_flags(); 
        *    assert(flags == EVENT_ENABLE_PROPERTY_STACK_TRACE);
        * </example>
        */
        T trace_flags() const;

        /**
        * <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>
        *     krabs::provider<> process_provider(L"Microsoft-Windows-Kernel-Process");
        *     process_provider.any(0x10);  // WINEVENT_KEYWORD_PROCESS
        *     process_provider.enable_rundown_events();
        * </example>
        */
        void enable_rundown_events();

        /**
         * <summary>
         * Turns a strongly typed provider<T> to provider<> (useful for
         * creating collections of providers).
         * </summary>
         *
         * <example>
         *    krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
         *    provider<CustomFlagType> powershell(id);
         *    provider<> blah(powershell);
         * </example>
         */
        operator provider<>() const;

    private:
        GUID guid_;
        T any_;
        T all_;
        T level_;
        T trace_flags_;
        bool rundown_enabled_;

    private:
        template <typename T>
        friend class details::trace_manager;

        template <typename T>
        friend class krabs::trace;

        template <typename S>
        friend class base_provider;

        friend struct details::ut;

    };

    /**
     * <summary>
     *   Used to enable specific types of event sources from an ETW kernel
     *   trace.
     * </summary>
     */
    class kernel_provider : public details::base_provider<ULONGLONG> {
    public:

        /**
         * <summary>
         *   Constructs a kernel_provider that enables events of the given
         *   flags.
         * </summary>
         */
        kernel_provider(unsigned long flags, const GUID &id)
        : p_(flags)
        , id_(id)
        , gm_(0)
        , r_(0)
        , rundown_enabled_(false)
        {}

        /**
         * <summary>
         *   Constructs a kernel_provider that enables events of the given
         *   group mask.
         * </summary>
         * <remarks>
         *   Only supported on Windows 8 and newer.
         * </remarks>
         */
        kernel_provider(const GUID& id, PERFINFO_MASK group_mask)
        : p_(0)
        , id_(id)
        , gm_(group_mask)
        , r_(0)
        , rundown_enabled_(false)
        {}

        /**
         * <summary>
         *   Retrieves the GUID associated with this provider.
         * </summary>
         */
         const krabs::guid &id() const;

         /**
         * <summary>
         *   Sets flags to be enabled for the kernel rundown GUID.
         * </summary>
         * <remarks>
         *   This ETW feature is undocumented and should be used with caution.
         * </remarks>
         */
         void set_rundown_flags(unsigned long rundown_flags) {
             r_ = rundown_flags;
             rundown_enabled_ = true;
         };

    private:

        /**
         * <summary>
         *   Retrieves the flag value associated with this provider.
         * </summary>
         */
        unsigned long flags() const { return p_; }

        /**
         * <summary>
         *   Retrieves the group mask value associated with this provider.
         * </summary>
         */
        PERFINFO_MASK group_mask() const { return gm_; }

        /**
         * <summary>
         *   Retrieves the rundown flag value associated with this provider.
         * </summary>
         */
        unsigned long rundown_flags() const { return r_; }

        /**
         * <summary>
         *   Have rundown flags been set for this this provider?
         * </summary>
         */
        bool rundown_enabled() const { return rundown_enabled_; }

    private:
        unsigned long p_;
        const krabs::guid id_;
        PERFINFO_MASK gm_;
        unsigned long r_;
        bool rundown_enabled_;

    private:
        friend struct details::kt;
    };


    // Implementation
    // ------------------------------------------------------------------------

    namespace details {

        template <typename T>
        void base_pro
Download .txt
gitextract_85lvkvnd/

├── Hunt-Weird-Syscalls/
│   ├── Detectors.cpp
│   ├── Detectors.h
│   ├── Helpers.cpp
│   ├── Helpers.h
│   ├── Hunt-Weird-Syscalls.sln
│   ├── Hunt-Weird-Syscalls.vcxproj
│   ├── Hunt-Weird-Syscalls.vcxproj.filters
│   ├── Hunt-Weird-Syscalls.vcxproj.user
│   ├── Main.cpp
│   ├── SetThreadContext_Direct/
│   │   ├── Main.c
│   │   ├── SetThreadContext_Direct.vcxproj
│   │   ├── SetThreadContext_Direct.vcxproj.filters
│   │   ├── SetThreadContext_Direct.vcxproj.user
│   │   ├── threadcontext_embedded.c
│   │   ├── threadcontext_embedded.h
│   │   └── threadcontext_embedded_-asm.x64.asm
│   └── SetThreadContext_Indirect/
│       ├── Main.c
│       ├── SetThreadContext_Indirect.vcxproj
│       ├── SetThreadContext_Indirect.vcxproj.filters
│       ├── SetThreadContext_Indirect.vcxproj.user
│       ├── threadcontext_jumper_randomized.c
│       ├── threadcontext_jumper_randomized.h
│       └── threadcontext_jumper_randomized_-asm.x64.asm
├── README.md
└── libs/
    └── krabs/
        ├── LICENSE
        ├── README.md
        ├── krabs/
        │   ├── client.hpp
        │   ├── collection_view.hpp
        │   ├── compiler_check.hpp
        │   ├── errors.hpp
        │   ├── etw.hpp
        │   ├── filtering/
        │   │   ├── comparers.hpp
        │   │   ├── event_filter.hpp
        │   │   ├── predicates.hpp
        │   │   └── view_adapters.hpp
        │   ├── guid.hpp
        │   ├── kernel_guids.hpp
        │   ├── kernel_providers.hpp
        │   ├── kt.hpp
        │   ├── parse_types.hpp
        │   ├── parser.hpp
        │   ├── perfinfo_groupmask.hpp
        │   ├── property.hpp
        │   ├── provider.hpp
        │   ├── schema.hpp
        │   ├── schema_locator.hpp
        │   ├── size_provider.hpp
        │   ├── tdh_helpers.hpp
        │   ├── testing/
        │   │   ├── event_filter_proxy.hpp
        │   │   ├── extended_data_builder.hpp
        │   │   ├── filler.hpp
        │   │   ├── proxy.hpp
        │   │   ├── record_builder.hpp
        │   │   ├── record_property_thunk.hpp
        │   │   └── synth_record.hpp
        │   ├── trace.hpp
        │   ├── trace_context.hpp
        │   ├── ut.hpp
        │   ├── version_helpers.hpp
        │   └── wstring_convert.hpp
        ├── krabs.hpp
        ├── krabs.runsettings
        └── krabs.sln
Download .txt
SYMBOL INDEX (382 symbols across 44 files)

FILE: Hunt-Weird-Syscalls/Detectors.cpp
  type Detectors (line 3) | namespace Detectors {
    function VOID (line 14) | VOID DirectSyscall ( DWORD pid, HANDLE hProcess, std::vector<ULONG_PTR...
    function VOID (line 33) | VOID InDirectSyscall ( DWORD pid, HANDLE hProcess, std::vector<ULONG_P...

FILE: Hunt-Weird-Syscalls/Detectors.h
  function namespace (line 8) | namespace Detectors {

FILE: Hunt-Weird-Syscalls/Helpers.cpp
  type Helpers (line 3) | namespace Helpers {
    function BOOL (line 5) | BOOL ModuleNameFromAddress ( HANDLE hProcess, PVOID pAddr, std::string...
    function VOID (line 30) | VOID RemoveKernelAddrs ( std::vector<ULONG_PTR>& stack ) {
    function BOOL (line 48) | BOOL IsElevated ( VOID ) {

FILE: Hunt-Weird-Syscalls/Helpers.h
  function namespace (line 8) | namespace Helpers {

FILE: Hunt-Weird-Syscalls/Main.cpp
  function VOID (line 12) | VOID EnableAuditApiTracing ( krabs::user_trace& userTrace ) {
  function VOID (line 32) | VOID OnObservableSyscall ( const EVENT_RECORD& record, const krabs::trac...
  function VOID (line 70) | VOID Go ( krabs::user_trace* userTrace ) {
  function main (line 74) | int main ( int argc, char** argv ) {

FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/Main.c
  function main (line 4) | int main(int argc, char** argv) {

FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded.c
  function EXTERN_C (line 10) | EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
  function DWORD (line 42) | DWORD SW3_HashSyscall(PCSTR FunctionName)
  function PVOID (line 57) | PVOID SC_Address(PVOID NtApiAddress)
  function PVOID (line 62) | PVOID SC_Address(PVOID NtApiAddress)
  function BOOL (line 142) | BOOL SW3_PopulateSyscallList()
  function EXTERN_C (line 234) | EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
  function EXTERN_C (line 250) | EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
  function EXTERN_C (line 266) | EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)

FILE: Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded.h
  type SW3_SYSCALL_ENTRY (line 20) | typedef struct _SW3_SYSCALL_ENTRY
  type SW3_SYSCALL_LIST (line 27) | typedef struct _SW3_SYSCALL_LIST
  type SW3_PEB_LDR_DATA (line 33) | typedef struct _SW3_PEB_LDR_DATA {
  type SW3_LDR_DATA_TABLE_ENTRY (line 39) | typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
  type SW3_PEB (line 46) | typedef struct _SW3_PEB {

FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/Main.c
  function main (line 4) | int main(int argc, char** argv) {

FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized.c
  function EXTERN_C (line 10) | EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
  function DWORD (line 42) | DWORD SW3_HashSyscall(PCSTR FunctionName)
  function PVOID (line 57) | PVOID SC_Address(PVOID NtApiAddress)
  function PVOID (line 62) | PVOID SC_Address(PVOID NtApiAddress)
  function BOOL (line 142) | BOOL SW3_PopulateSyscallList()
  function EXTERN_C (line 234) | EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
  function EXTERN_C (line 250) | EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
  function EXTERN_C (line 266) | EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)

FILE: Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized.h
  type SW3_SYSCALL_ENTRY (line 20) | typedef struct _SW3_SYSCALL_ENTRY
  type SW3_SYSCALL_LIST (line 27) | typedef struct _SW3_SYSCALL_LIST
  type SW3_PEB_LDR_DATA (line 33) | typedef struct _SW3_PEB_LDR_DATA {
  type SW3_LDR_DATA_TABLE_ENTRY (line 39) | typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
  type SW3_PEB (line 46) | typedef struct _SW3_PEB {

FILE: libs/krabs/krabs/client.hpp
  type krabs (line 11) | namespace krabs {

FILE: libs/krabs/krabs/collection_view.hpp
  type krabs (line 10) | namespace krabs {
    type collection_view (line 19) | struct collection_view
      method collection_view (line 30) | collection_view(const T begin, const T end)
      method T (line 38) | const T begin() const
      method T (line 46) | const T end() const
    function view (line 56) | inline collection_view<T> view(const T& begin, const T& end)
    function view (line 65) | inline collection_view<typename std::basic_string<T>::const_iterator> ...
    function view (line 74) | inline collection_view<const T*> view(const T* begin, size_t length)
    function view (line 83) | inline collection_view<const T*> view(const T(&arr)[n])

FILE: libs/krabs/krabs/errors.hpp
  type krabs (line 10) | namespace krabs {
    class trace_already_registered (line 12) | class trace_already_registered : public std::runtime_error {
      method trace_already_registered (line 14) | trace_already_registered()
    class invalid_parameter (line 19) | class invalid_parameter : public std::logic_error {
      method invalid_parameter (line 21) | invalid_parameter()
    class open_trace_failure (line 26) | class open_trace_failure : public std::runtime_error {
      method open_trace_failure (line 28) | open_trace_failure()
    class need_to_be_admin_failure (line 33) | class need_to_be_admin_failure : public std::runtime_error {
      method need_to_be_admin_failure (line 35) | need_to_be_admin_failure()
    class could_not_find_schema (line 40) | class could_not_find_schema : public std::runtime_error {
      method could_not_find_schema (line 42) | could_not_find_schema()
      method could_not_find_schema (line 46) | could_not_find_schema(const std::string& context)
    class type_mismatch_assert (line 51) | class type_mismatch_assert : public std::runtime_error {
      method type_mismatch_assert (line 53) | type_mismatch_assert(
    class no_trace_sessions_remaining (line 62) | class no_trace_sessions_remaining : public std::runtime_error {
      method no_trace_sessions_remaining (line 64) | no_trace_sessions_remaining()
    class function_not_supported (line 69) | class function_not_supported : public std::runtime_error {
      method function_not_supported (line 71) | function_not_supported()
    class unexpected_error (line 76) | class unexpected_error : public std::runtime_error {
      method unexpected_error (line 78) | unexpected_error(ULONG status)
      method unexpected_error (line 83) | unexpected_error(const std::string &context)
    function get_status_and_record_context (line 88) | inline std::string get_status_and_record_context(ULONG status, const E...
    function error_check_common_conditions (line 104) | inline void error_check_common_conditions(ULONG status)
    function error_check_common_conditions (line 131) | inline void error_check_common_conditions(ULONG status, const EVENT_RE...

FILE: libs/krabs/krabs/etw.hpp
  type krabs (line 20) | namespace krabs { namespace details {
    type details (line 20) | namespace details {
      class trace_info (line 27) | class trace_info {
      class trace_manager (line 40) | class trace_manager {
      function trace_callback_thunk (line 135) | static void __stdcall trace_callback_thunk(EVENT_RECORD *pRecord)
      function ULONG (line 155) | static ULONG __stdcall trace_buffer_callback(EVENT_TRACE_LOGFILE *pL...
      function EVENT_TRACE_LOGFILE (line 180) | EVENT_TRACE_LOGFILE trace_manager<T>::open()
      function EVENT_TRACE_PROPERTIES (line 194) | EVENT_TRACE_PROPERTIES trace_manager<T>::query()
      function trace_info (line 234) | trace_info trace_manager<T>::fill_trace_info()
      function EVENT_TRACE_LOGFILE (line 262) | EVENT_TRACE_LOGFILE trace_manager<T>::fill_logfile()
      function EVENT_TRACE_PROPERTIES (line 299) | EVENT_TRACE_PROPERTIES trace_manager<T>::query_trace()
      function EVENT_TRACE_LOGFILE (line 358) | EVENT_TRACE_LOGFILE trace_manager<T>::open_trace()

FILE: libs/krabs/krabs/filtering/comparers.hpp
  type krabs (line 10) | namespace krabs { namespace predicates {
    type predicates (line 10) | namespace predicates {
      type comparers (line 12) | namespace comparers {
        type equals (line 21) | struct equals
        type contains (line 34) | struct contains
        type starts_with (line 49) | struct starts_with
        type ends_with (line 63) | struct ends_with
        type iequal_to (line 83) | struct iequal_to
        type iequal_to<wchar_t> (line 99) | struct iequal_to<wchar_t>
        type iequal_to<char> (line 114) | struct iequal_to<char>

FILE: libs/krabs/krabs/filtering/event_filter.hpp
  type krabs (line 14) | namespace krabs { namespace testing {
    type testing (line 14) | namespace testing {
      class event_filter_proxy (line 15) | class event_filter_proxy
    type details (line 18) | namespace details {
      class base_provider (line 19) | class base_provider
    class provider (line 31) | class provider
    class event_filter (line 45) | class event_filter {
  type krabs (line 18) | namespace krabs { namespace details {
    type testing (line 14) | namespace testing {
      class event_filter_proxy (line 15) | class event_filter_proxy
    type details (line 18) | namespace details {
      class base_provider (line 19) | class base_provider
    class provider (line 31) | class provider
    class event_filter (line 45) | class event_filter {
  type krabs (line 23) | namespace krabs {
    type testing (line 14) | namespace testing {
      class event_filter_proxy (line 15) | class event_filter_proxy
    type details (line 18) | namespace details {
      class base_provider (line 19) | class base_provider
    class provider (line 31) | class provider
    class event_filter (line 45) | class event_filter {

FILE: libs/krabs/krabs/filtering/predicates.hpp
  type krabs (line 19) | namespace krabs { namespace predicates {
    type predicates (line 19) | namespace predicates {
      type details (line 21) | namespace details {
        type predicate_base (line 29) | struct predicate_base
        type any_event (line 39) | struct any_event : predicate_base {
        type no_event (line 51) | struct no_event : predicate_base {
        type and_filter (line 64) | struct and_filter : predicate_base {
          method and_filter (line 65) | and_filter(const T1 &t1, const T2 &t2)
        type or_filter (line 86) | struct or_filter : predicate_base {
          method or_filter (line 87) | or_filter(const T1 &t1, const T2 &t2)
        type not_filter (line 108) | struct not_filter : predicate_base {
          method not_filter (line 109) | not_filter(const T1 &t1)
        type property_is (line 128) | struct property_is : predicate_base {
          method property_is (line 129) | property_is(const std::wstring &property, const T &expected)
        type property_view_predicate (line 161) | struct property_view_predicate : details::predicate_base
          method property_view_predicate (line 163) | property_view_predicate(
      type id_is (line 219) | struct id_is : details::predicate_base {
        method id_is (line 220) | id_is(size_t expected)
      type opcode_is (line 238) | struct opcode_is : details::predicate_base {
        method opcode_is (line 239) | opcode_is(size_t expected)
      type any_of (line 257) | struct any_of : details::predicate_base {
        method any_of (line 258) | any_of(std::vector<details::predicate_base*> list)
      type all_of (line 280) | struct all_of : details::predicate_base {
        method all_of (line 281) | all_of(std::vector<details::predicate_base*> list)
      type none_of (line 306) | struct none_of : details::predicate_base {
        method none_of (line 307) | none_of(std::vector<details::predicate_base*> list)
      type version_is (line 329) | struct version_is : details::predicate_base {
        method version_is (line 330) | version_is(size_t expected)
      type process_id_is (line 348) | struct process_id_is : details::predicate_base {
        method process_id_is (line 349) | process_id_is(size_t expected)
      function property_is (line 368) | details::property_is<T> property_is(
      function property_is (line 380) | inline details::property_is<std::wstring> property_is(
      function property_is (line 387) | inline details::property_is<std::string> property_is(
      function property_equals (line 414) | details::property_view_predicate<T, Adapter, Comparer> property_equals(
      function property_iequals (line 428) | details::property_view_predicate<T, Adapter, Comparer> property_iequ...
      function property_contains (line 442) | details::property_view_predicate<T, Adapter, Comparer> property_cont...
      function property_icontains (line 456) | details::property_view_predicate<T, Adapter, Comparer> property_icon...
      function property_starts_with (line 470) | details::property_view_predicate<T, Adapter, Comparer> property_star...
      function property_istarts_with (line 484) | details::property_view_predicate<T, Adapter, Comparer> property_ista...
      function property_ends_with (line 498) | details::property_view_predicate<T, Adapter, Comparer> property_ends...
      function property_iends_with (line 512) | details::property_view_predicate<T, Adapter, Comparer> property_iend...
      function and_filter (line 525) | details::and_filter<T1, T2> and_filter(const T1 &t1, const T2 &t2)
      function or_filter (line 536) | details::or_filter<T1, T2> or_filter(const T1 &t1, const T2 &t2)
      function not_filter (line 547) | details::not_filter<T1> not_filter(const T1 &t1)

FILE: libs/krabs/krabs/filtering/view_adapters.hpp
  type krabs (line 11) | namespace krabs { namespace predicates {
    type predicates (line 11) | namespace predicates {
      type adapters (line 13) | namespace adapters {
        type counted_string (line 18) | struct counted_string
        type generic_string (line 34) | struct generic_string

FILE: libs/krabs/krabs/guid.hpp
  type krabs (line 21) | namespace krabs {
    class guid (line 28) | class guid {
    class guid_parser (line 58) | class guid_parser {
    function GUID (line 146) | inline guid::operator GUID() const
    function guid (line 156) | inline guid guid::random_guid()
    type CoTaskMemDeleter (line 163) | struct CoTaskMemDeleter {
    function GUID (line 261) | inline GUID guid_parser::parse_guid(const char* str, unsigned int length)
  type std (line 301) | namespace std
    function to_wstring (line 306) | inline std::wstring to_wstring(const krabs::guid& guid)
    function to_string (line 321) | inline std::string to_string(const GUID& guid)
    type std::hash<krabs::guid> (line 335) | struct std::hash<krabs::guid>

FILE: libs/krabs/krabs/kernel_guids.hpp
  type krabs (line 10) | namespace krabs { namespace guids {
    type guids (line 10) | namespace guids {

FILE: libs/krabs/krabs/kernel_providers.hpp
  type krabs (line 14) | namespace krabs { namespace kernel {
    type kernel (line 14) | namespace kernel {

FILE: libs/krabs/krabs/kt.hpp
  type krabs (line 16) | namespace krabs { namespace details {
    type details (line 16) | namespace details {
      type kt (line 25) | struct kt {

FILE: libs/krabs/krabs/parse_types.hpp
  type krabs (line 20) | namespace krabs {
    function T (line 36) | T id(T n)
    function T (line 55) | T version(T n)
    function T (line 74) | T opcode(T n)
    type hexint32 (line 93) | struct hexint32 {
      method hexint32 (line 94) | hexint32(int v)
    type hexint64 (line 101) | struct hexint64 {
      method hexint64 (line 102) | hexint64(long long v)
    type binary (line 114) | struct binary {
      method binary (line 116) | binary() : bytes_() { }
      method binary (line 118) | binary(const BYTE* start, size_t n)
    function binary (line 132) | binary make_binary(const T& value, size_t n)
      method binary (line 116) | binary() : bytes_() { }
      method binary (line 118) | binary(const BYTE* start, size_t n)
    type ip_address (line 144) | struct ip_address {
      method ip_address (line 151) | static ip_address from_ipv6(const BYTE* bytes)
      method ip_address (line 159) | static ip_address from_ipv4(DWORD val)
      method ip_address (line 167) | ip_address() {}
    type socket_address (line 178) | struct socket_address {
      type sockaddr (line 180) | struct sockaddr
      type sockaddr_in (line 181) | struct sockaddr_in
      type sockaddr_in6 (line 182) | struct sockaddr_in6
      type sockaddr_storage (line 183) | struct sockaddr_storage
      method socket_address (line 187) | static socket_address from_bytes(const BYTE* bytes, size_t size_in_b...
    type property_info (line 201) | struct property_info {
      method property_info (line 206) | property_info(
      method property_info (line 215) | property_info()
      method found (line 221) | inline bool found() const
    type sid (line 233) | struct sid {
      method sid (line 240) | static sid from_bytes(const BYTE* bytes, size_t size_in_bytes)
    type pointer (line 263) | struct pointer {
      method pointer (line 270) | static pointer from_bytes(const BYTE* bytes, size_t size_in_bytes)
    type counted_string (line 301) | struct counted_string {
      method const_pointer (line 316) | const_pointer string() const
      method length (line 321) | size_t length() const

FILE: libs/krabs/krabs/parser.hpp
  type krabs (line 20) | namespace krabs {
    class schema (line 22) | class schema
    class parser (line 34) | class parser {
    function property_iterator (line 117) | inline property_iterator parser::properties() const
    function property_info (line 122) | inline property_info parser::find_property(const std::wstring &name)
    function throw_if_property_not_found (line 204) | inline void throw_if_property_not_found(const property_info &propInfo)
    function get_string_content_length (line 212) | size_t get_string_content_length(const T* string, size_t lengthBytes)
    function catch (line 241) | catch (const krabs::type_mismatch_assert&) {
    function catch (line 246) | catch (...) {
    function T (line 255) | T parser::parse(const std::wstring &name)
    function counted_string (line 311) | inline const counted_string* parser::parse<const counted_string*>(cons...
    function binary (line 322) | inline binary parser::parse<binary>(const std::wstring &name)
    function ip_address (line 333) | inline ip_address parser::parse<ip_address>(
    function socket_address (line 356) | inline socket_address parser::parse<socket_address>(
    function sid (line 368) | inline sid parser::parse<sid>(
    function pointer (line 407) | inline pointer parser::parse<pointer>(const std::wstring& name)

FILE: libs/krabs/krabs/perfinfo_groupmask.hpp
  type _PERFINFO_GROUPMASK (line 17) | struct _PERFINFO_GROUPMASK {
  type _EVENT_TRACE_INFORMATION_CLASS (line 158) | enum _EVENT_TRACE_INFORMATION_CLASS {
  type _EVENT_TRACE_GROUPMASK_INFORMATION (line 180) | struct _EVENT_TRACE_GROUPMASK_INFORMATION {
  type _SYSTEM_INFORMATION_CLASS (line 188) | enum _SYSTEM_INFORMATION_CLASS {

FILE: libs/krabs/krabs/property.hpp
  type krabs (line 25) | namespace krabs {
    class property (line 39) | class property {
    class property_iterator (line 78) | class property_iterator {
    function _TDH_IN_TYPE (line 151) | inline _TDH_IN_TYPE property::type() const
    function property (line 177) | inline property property_iterator::get_property(size_t index) const

FILE: libs/krabs/krabs/provider.hpp
  type krabs (line 28) | namespace krabs { namespace details {
    type details (line 28) | namespace details {
      class trace_manager (line 29) | class trace_manager
      type kt (line 31) | struct kt
      type ut (line 32) | struct ut
      class base_provider (line 55) | class base_provider {
    class trace (line 39) | class trace
    type details (line 46) | namespace details {
      class trace_manager (line 29) | class trace_manager
      type kt (line 31) | struct kt
      type ut (line 32) | struct ut
      class base_provider (line 55) | class base_provider {
    class provider (line 156) | class provider : public details::base_provider<T> {
    class kernel_provider (line 317) | class kernel_provider : public details::base_provider<ULONGLONG> {
      method kernel_provider (line 326) | kernel_provider(unsigned long flags, const GUID &id)
      method kernel_provider (line 343) | kernel_provider(const GUID& id, PERFINFO_MASK group_mask)
      method set_rundown_flags (line 366) | void set_rundown_flags(unsigned long rundown_flags) {
      method flags (line 378) | unsigned long flags() const { return p_; }
      method PERFINFO_MASK (line 385) | PERFINFO_MASK group_mask() const { return gm_; }
      method rundown_flags (line 392) | unsigned long rundown_flags() const { return r_; }
      method rundown_enabled (line 399) | bool rundown_enabled() const { return rundown_enabled_; }
    type details (line 416) | namespace details {
      class trace_manager (line 29) | class trace_manager
      type kt (line 31) | struct kt
      type ut (line 32) | struct ut
      class base_provider (line 55) | class base_provider {
    function check_com_hr (line 521) | inline void check_com_hr(HRESULT hr) {
    function check_provider_hr (line 531) | inline void check_provider_hr(HRESULT hr, const std::wstring &provider...
    function T (line 637) | T provider<T>::trace_flags() const
  type krabs (line 36) | namespace krabs {
    type details (line 28) | namespace details {
      class trace_manager (line 29) | class trace_manager
      type kt (line 31) | struct kt
      type ut (line 32) | struct ut
      class base_provider (line 55) | class base_provider {
    class trace (line 39) | class trace
    type details (line 46) | namespace details {
      class trace_manager (line 29) | class trace_manager
      type kt (line 31) | struct kt
      type ut (line 32) | struct ut
      class base_provider (line 55) | class base_provider {
    class provider (line 156) | class provider : public details::base_provider<T> {
    class kernel_provider (line 317) | class kernel_provider : public details::base_provider<ULONGLONG> {
      method kernel_provider (line 326) | kernel_provider(unsigned long flags, const GUID &id)
      method kernel_provider (line 343) | kernel_provider(const GUID& id, PERFINFO_MASK group_mask)
      method set_rundown_flags (line 366) | void set_rundown_flags(unsigned long rundown_flags) {
      method flags (line 378) | unsigned long flags() const { return p_; }
      method PERFINFO_MASK (line 385) | PERFINFO_MASK group_mask() const { return gm_; }
      method rundown_flags (line 392) | unsigned long rundown_flags() const { return r_; }
      method rundown_enabled (line 399) | bool rundown_enabled() const { return rundown_enabled_; }
    type details (line 416) | namespace details {
      class trace_manager (line 29) | class trace_manager
      type kt (line 31) | struct kt
      type ut (line 32) | struct ut
      class base_provider (line 55) | class base_provider {
    function check_com_hr (line 521) | inline void check_com_hr(HRESULT hr) {
    function check_provider_hr (line 531) | inline void check_provider_hr(HRESULT hr, const std::wstring &provider...
    function T (line 637) | T provider<T>::trace_flags() const

FILE: libs/krabs/krabs/schema.hpp
  type krabs (line 24) | namespace krabs { namespace testing {
    type testing (line 24) | namespace testing {
      class record_builder (line 25) | class record_builder
    class schema (line 31) | class schema
    class parser (line 32) | class parser
    class schema (line 40) | class schema {
    function wchar_t (line 295) | inline const wchar_t *schema::event_name() const
    function wchar_t (line 313) | inline const wchar_t* schema::opcode_name() const
    function wchar_t (line 328) | inline const wchar_t *schema::task_name() const
    function DECODING_SOURCE (line 340) | inline DECODING_SOURCE schema::decoding_source() const
    function wchar_t (line 365) | inline const wchar_t *schema::provider_name() const
    function LARGE_INTEGER (line 382) | inline LARGE_INTEGER schema::timestamp() const
    function GUID (line 387) | inline GUID schema::activity_id() const
  type krabs (line 29) | namespace krabs {
    type testing (line 24) | namespace testing {
      class record_builder (line 25) | class record_builder
    class schema (line 31) | class schema
    class parser (line 32) | class parser
    class schema (line 40) | class schema {
    function wchar_t (line 295) | inline const wchar_t *schema::event_name() const
    function wchar_t (line 313) | inline const wchar_t* schema::opcode_name() const
    function wchar_t (line 328) | inline const wchar_t *schema::task_name() const
    function DECODING_SOURCE (line 340) | inline DECODING_SOURCE schema::decoding_source() const
    function wchar_t (line 365) | inline const wchar_t *schema::provider_name() const
    function LARGE_INTEGER (line 382) | inline LARGE_INTEGER schema::timestamp() const
    function GUID (line 387) | inline GUID schema::activity_id() const

FILE: libs/krabs/krabs/schema_locator.hpp
  type krabs (line 25) | namespace krabs {
    type schema_key (line 32) | struct schema_key
      method schema_key (line 40) | schema_key(const EVENT_RECORD &record)
    class schema_locator (line 102) | class schema_locator {
    function PTRACE_EVENT_INFO (line 120) | inline const PTRACE_EVENT_INFO schema_locator::get_event_schema(const ...
    function get_event_schema_from_tdh (line 134) | inline std::unique_ptr<char[]> get_event_schema_from_tdh(const EVENT_R...
  type std (line 60) | namespace std {
    type std::hash<krabs::schema_key> (line 68) | struct std::hash<krabs::schema_key>
  type krabs (line 86) | namespace krabs {
    type schema_key (line 32) | struct schema_key
      method schema_key (line 40) | schema_key(const EVENT_RECORD &record)
    class schema_locator (line 102) | class schema_locator {
    function PTRACE_EVENT_INFO (line 120) | inline const PTRACE_EVENT_INFO schema_locator::get_event_schema(const ...
    function get_event_schema_from_tdh (line 134) | inline std::unique_ptr<char[]> get_event_schema_from_tdh(const EVENT_R...

FILE: libs/krabs/krabs/size_provider.hpp
  type krabs (line 16) | namespace krabs {
    class size_provider (line 22) | class size_provider {
    function ULONG (line 53) | inline ULONG size_provider::get_property_size(
    function ULONG (line 105) | inline ULONG size_provider::get_heuristic_size(
    function ULONG (line 155) | inline ULONG size_provider::get_tdh_size(

FILE: libs/krabs/krabs/tdh_helpers.hpp
  type krabs (line 15) | namespace krabs {
    type debug (line 62) | namespace debug {
      function missing_assert_specialization_for (line 67) | inline void missing_assert_specialization_for()
      function assert_valid_assignment (line 77) | inline void assert_valid_assignment(const std::wstring&, const prope...
      function throw_if_invalid (line 95) | inline void throw_if_invalid(

FILE: libs/krabs/krabs/testing/event_filter_proxy.hpp
  type krabs (line 13) | namespace krabs { namespace testing {
    type testing (line 13) | namespace testing {
      class event_filter_proxy (line 22) | class event_filter_proxy {

FILE: libs/krabs/krabs/testing/extended_data_builder.hpp
  type krabs (line 20) | namespace krabs { namespace testing {
    type testing (line 20) | namespace testing {
      class extended_data_builder (line 21) | class extended_data_builder
        method extended_data_builder (line 61) | extended_data_builder()
        method count (line 75) | inline size_t count() const { return items_.size(); }
      class extended_data_thunk (line 29) | class extended_data_thunk
      class extended_data_builder (line 54) | class extended_data_builder
        method extended_data_builder (line 61) | extended_data_builder()
        method count (line 75) | inline size_t count() const { return items_.size(); }

FILE: libs/krabs/krabs/testing/filler.hpp
  type krabs (line 11) | namespace krabs { namespace testing { namespace details {
    type testing (line 11) | namespace testing { namespace details {
      type details (line 11) | namespace details {
        function how_many_bytes_to_fill (line 19) | inline size_t how_many_bytes_to_fill(_TDH_IN_TYPE type)
        type tdh_morphism (line 60) | struct tdh_morphism {
        type tdh_morphism<T*> (line 66) | struct tdh_morphism<T*> {
        type tdh_morphism<std::wstring> (line 71) | struct tdh_morphism<std::wstring> {
        type tdh_morphism<std::string> (line 76) | struct tdh_morphism<std::string> {
        type tdh_morphism<char> (line 81) | struct tdh_morphism<char> {
        type tdh_morphism<unsigned char> (line 86) | struct tdh_morphism<unsigned char> {
        type tdh_morphism<short> (line 91) | struct tdh_morphism<short> {
        type tdh_morphism<unsigned short> (line 96) | struct tdh_morphism<unsigned short> {
        type tdh_morphism<int> (line 101) | struct tdh_morphism<int> {
        type tdh_morphism<unsigned int> (line 106) | struct tdh_morphism<unsigned int> {
        type tdh_morphism<long long> (line 111) | struct tdh_morphism<long long> {
        type tdh_morphism<unsigned long long> (line 116) | struct tdh_morphism<unsigned long long> {
        type tdh_morphism<float> (line 121) | struct tdh_morphism<float> {
        type tdh_morphism<double> (line 126) | struct tdh_morphism<double> {
        type tdh_morphism<bool> (line 131) | struct tdh_morphism<bool> {
        type tdh_morphism<GUID> (line 136) | struct tdh_morphism<GUID> {
        type tdh_morphism<krabs::guid> (line 141) | struct tdh_morphism<krabs::guid> {
        type tdh_morphism<FILETIME> (line 146) | struct tdh_morphism<FILETIME> {
        type tdh_morphism<SYSTEMTIME> (line 151) | struct tdh_morphism<SYSTEMTIME> {
        type tdh_morphism<krabs::hexint32> (line 156) | struct tdh_morphism<krabs::hexint32> {
        type tdh_morphism<krabs::hexint64> (line 161) | struct tdh_morphism<krabs::hexint64> {
        type tdh_morphism<SID> (line 166) | struct tdh_morphism<SID> {
        type tdh_morphism<krabs::binary> (line 171) | struct tdh_morphism<krabs::binary> {

FILE: libs/krabs/krabs/testing/proxy.hpp
  type krabs (line 13) | namespace krabs { namespace testing {
    type testing (line 13) | namespace testing {
      class trace_proxy (line 23) | class trace_proxy {

FILE: libs/krabs/krabs/testing/record_builder.hpp
  type krabs (line 24) | namespace krabs { namespace testing {
    type testing (line 24) | namespace testing {
      class record_builder (line 26) | class record_builder
      type details (line 28) | namespace details {
        type property_adder (line 41) | struct property_adder {
      class record_builder (line 77) | class record_builder {
      function EVENT_HEADER (line 233) | inline EVENT_HEADER &record_builder::header()
      function synth_record (line 243) | inline synth_record record_builder::pack() const
      function synth_record (line 270) | inline synth_record record_builder::pack_incomplete() const
      function EVENT_RECORD (line 284) | inline EVENT_RECORD record_builder::create_stub_record() const

FILE: libs/krabs/krabs/testing/record_property_thunk.hpp
  type krabs (line 9) | namespace krabs { namespace testing {
    type testing (line 9) | namespace testing {
      class record_builder (line 11) | class record_builder
      class record_property_thunk (line 26) | class record_property_thunk {
      function _TDH_IN_TYPE (line 158) | inline const _TDH_IN_TYPE record_property_thunk::type() const

FILE: libs/krabs/krabs/testing/synth_record.hpp
  type krabs (line 20) | namespace krabs { namespace testing {
    type testing (line 20) | namespace testing {
      class synth_record (line 28) | class synth_record {
        method swap (line 95) | void swap(synth_record& left, synth_record& right)
        method synth_record (line 105) | synth_record()
      function synth_record (line 159) | inline synth_record& synth_record::operator=(synth_record other)
        method swap (line 95) | void swap(synth_record& left, synth_record& right)
        method synth_record (line 105) | synth_record()

FILE: libs/krabs/krabs/trace.hpp
  type krabs (line 15) | namespace krabs { namespace details {
    type details (line 15) | namespace details {
      class trace_manager (line 16) | class trace_manager
    type testing (line 19) | namespace testing {
      class trace_proxy (line 20) | class trace_proxy
    class provider (line 27) | class provider
    class trace_stats (line 34) | class trace_stats
      method trace_stats (line 45) | trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& pr...
    class trace (line 64) | class trace {
    function EVENT_TRACE_LOGFILE (line 410) | EVENT_TRACE_LOGFILE trace<T>::open()
    function trace_stats (line 428) | trace_stats trace<T>::query_stats()
      method trace_stats (line 45) | trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& pr...
  type krabs (line 19) | namespace krabs { namespace testing {
    type details (line 15) | namespace details {
      class trace_manager (line 16) | class trace_manager
    type testing (line 19) | namespace testing {
      class trace_proxy (line 20) | class trace_proxy
    class provider (line 27) | class provider
    class trace_stats (line 34) | class trace_stats
      method trace_stats (line 45) | trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& pr...
    class trace (line 64) | class trace {
    function EVENT_TRACE_LOGFILE (line 410) | EVENT_TRACE_LOGFILE trace<T>::open()
    function trace_stats (line 428) | trace_stats trace<T>::query_stats()
      method trace_stats (line 45) | trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& pr...
  type krabs (line 24) | namespace krabs {
    type details (line 15) | namespace details {
      class trace_manager (line 16) | class trace_manager
    type testing (line 19) | namespace testing {
      class trace_proxy (line 20) | class trace_proxy
    class provider (line 27) | class provider
    class trace_stats (line 34) | class trace_stats
      method trace_stats (line 45) | trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& pr...
    class trace (line 64) | class trace {
    function EVENT_TRACE_LOGFILE (line 410) | EVENT_TRACE_LOGFILE trace<T>::open()
    function trace_stats (line 428) | trace_stats trace<T>::query_stats()
      method trace_stats (line 45) | trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& pr...

FILE: libs/krabs/krabs/trace_context.hpp
  type krabs (line 8) | namespace krabs {
    type trace_context (line 16) | struct trace_context

FILE: libs/krabs/krabs/ut.hpp
  type krabs (line 12) | namespace krabs { namespace details {
    type details (line 12) | namespace details {
      type ut (line 21) | struct ut {
        type filter_flags (line 25) | struct filter_flags {
        type filter_settings (line 32) | struct filter_settings{

FILE: libs/krabs/krabs/version_helpers.hpp
  function VERSIONHELPERAPI (line 42) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 60) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 66) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 72) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 78) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 84) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 90) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 96) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 102) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 108) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 114) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 120) | VERSIONHELPERAPI
  function VERSIONHELPERAPI (line 126) | VERSIONHELPERAPI

FILE: libs/krabs/krabs/wstring_convert.hpp
  type krabs (line 6) | namespace krabs {
    function from_wstring (line 13) | inline std::string from_wstring(const std::wstring& wstr, UINT codePag...
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (329K chars).
[
  {
    "path": "Hunt-Weird-Syscalls/Detectors.cpp",
    "chars": 2217,
    "preview": "#include \"Detectors.h\"\n\nnamespace Detectors {\n\n\tstd::vector<PCSTR> allowedSyscallmodules = { \n\t\t\"ntdll.dll\", \n\t\t\"win32u."
  },
  {
    "path": "Hunt-Weird-Syscalls/Detectors.h",
    "chars": 410,
    "preview": "#pragma once\n\n#include \"windows.h\"\n#include <vector>\n\n#include \"Helpers.h\"\n\nnamespace Detectors {\n\n\textern std::vector<P"
  },
  {
    "path": "Hunt-Weird-Syscalls/Helpers.cpp",
    "chars": 1480,
    "preview": "#include \"Helpers.h\"\n\nnamespace Helpers {\n\n\tBOOL ModuleNameFromAddress ( HANDLE hProcess, PVOID pAddr, std::string& modu"
  },
  {
    "path": "Hunt-Weird-Syscalls/Helpers.h",
    "chars": 253,
    "preview": "#pragma once\n#include \"windows.h\"\n#include \"psapi.h\"\n\n#include <string>\n#include <vector>\n\nnamespace Helpers {\n\tVOID Rem"
  },
  {
    "path": "Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.sln",
    "chars": 3011,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.3241"
  },
  {
    "path": "Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.vcxproj",
    "chars": 7243,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msb"
  },
  {
    "path": "Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.vcxproj.filters",
    "chars": 1347,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "Hunt-Weird-Syscalls/Hunt-Weird-Syscalls.vcxproj.user",
    "chars": 163,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Hunt-Weird-Syscalls/Main.cpp",
    "chars": 2941,
    "preview": "#include \"../libs/krabs/krabs.hpp\"\n\n#include \"Detectors.h\"\n#include \"Helpers.h\"\n\n#define EVENTID_SETTHTREADCONTEXT 4\n#de"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/Main.c",
    "chars": 150,
    "preview": "#include \"windows.h\"\n#include \"threadcontext_embedded.h\"\n\nint main(int argc, char** argv) {\n\n\tNtSetContextThread(-1, NUL"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/SetThreadContext_Direct.vcxproj",
    "chars": 7474,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msb"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/SetThreadContext_Direct.vcxproj.filters",
    "chars": 1323,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/SetThreadContext_Direct.vcxproj.user",
    "chars": 163,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded.c",
    "chars": 8379,
    "preview": "#include \"threadcontext_embedded.h\"\n#include <stdio.h>\n\n//#define DEBUG\n\n// JUMPER\n\n#ifdef _M_IX86\n\nEXTERN_C PVOID inter"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded.h",
    "chars": 1708,
    "preview": "#pragma once\n\n// Code below is adapted from @modexpblog. Read linked article for more details.\n// https://www.mdsec.co.u"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Direct/threadcontext_embedded_-asm.x64.asm",
    "chars": 551,
    "preview": ".code\n\nEXTERN SW3_GetSyscallNumber: PROC\n\nNtSetContextThread PROC\n\tmov [rsp +8], rcx          ; Save registers.\n\tmov [rs"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/Main.c",
    "chars": 159,
    "preview": "#include \"windows.h\"\n#include \"threadcontext_jumper_randomized.h\"\n\nint main(int argc, char** argv) {\n\n\tNtSetContextThrea"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/SetThreadContext_Indirect.vcxproj",
    "chars": 7503,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msb"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/SetThreadContext_Indirect.vcxproj.filters",
    "chars": 1350,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/SetThreadContext_Indirect.vcxproj.user",
    "chars": 163,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/ms"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized.c",
    "chars": 8393,
    "preview": "#include \"threadcontext_jumper_randomized.h\"\n#include <stdio.h>\n\n//#define DEBUG\n\n#define JUMPER\n\n#ifdef _M_IX86\n\nEXTERN"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized.h",
    "chars": 1708,
    "preview": "#pragma once\n\n// Code below is adapted from @modexpblog. Read linked article for more details.\n// https://www.mdsec.co.u"
  },
  {
    "path": "Hunt-Weird-Syscalls/SetThreadContext_Indirect/threadcontext_jumper_randomized_-asm.x64.asm",
    "chars": 844,
    "preview": ".code\n\nEXTERN SW3_GetSyscallNumber: PROC\n\nEXTERN SW3_GetRandomSyscallAddress: PROC\n\nNtSetContextThread PROC\n\tmov [rsp +8"
  },
  {
    "path": "README.md",
    "chars": 2134,
    "preview": "# Hunt-Weird-Syscalls\n\nThis is a ETW based POC to monitor for abnormal syscalls.   \n\nFor now, the syscalls ``NtOpenThrea"
  },
  {
    "path": "libs/krabs/LICENSE",
    "chars": 1107,
    "preview": "krabsetw\n\nCopyright (c) Microsoft Corporation\n\nAll rights reserved.\n\nMIT License\n\nPermission is hereby granted, free of "
  },
  {
    "path": "libs/krabs/README.md",
    "chars": 866,
    "preview": "# Krabs Readme\n\nImportant Preprocessor Definitions:\n\n* `UNICODE` - krabsetw expects the `UNICODE` preprocessor definitio"
  },
  {
    "path": "libs/krabs/krabs/client.hpp",
    "chars": 622,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/collection_view.hpp",
    "chars": 2187,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/compiler_check.hpp",
    "chars": 279,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/errors.hpp",
    "chars": 4834,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/etw.hpp",
    "chars": 12478,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/filtering/comparers.hpp",
    "chars": 3725,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/filtering/event_filter.hpp",
    "chars": 8232,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/filtering/predicates.hpp",
    "chars": 16429,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/filtering/view_adapters.hpp",
    "chars": 1589,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/guid.hpp",
    "chars": 11419,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/kernel_guids.hpp",
    "chars": 4308,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/kernel_providers.hpp",
    "chars": 7464,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/kt.hpp",
    "chars": 6491,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/parse_types.hpp",
    "chars": 8405,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/parser.hpp",
    "chars": 14823,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/perfinfo_groupmask.hpp",
    "chars": 8810,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/property.hpp",
    "chars": 5284,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/provider.hpp",
    "chars": 20768,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/schema.hpp",
    "chars": 13255,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/schema_locator.hpp",
    "chars": 4293,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/size_provider.hpp",
    "chars": 5933,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/tdh_helpers.hpp",
    "chars": 7747,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/event_filter_proxy.hpp",
    "chars": 2334,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/extended_data_builder.hpp",
    "chars": 6241,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/filler.hpp",
    "chars": 5450,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/proxy.hpp",
    "chars": 3222,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/record_builder.hpp",
    "chars": 13027,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/record_property_thunk.hpp",
    "chars": 5010,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/testing/synth_record.hpp",
    "chars": 5053,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/trace.hpp",
    "chars": 13454,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/trace_context.hpp",
    "chars": 493,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/ut.hpp",
    "chars": 9263,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/version_helpers.hpp",
    "chars": 3671,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs/wstring_convert.hpp",
    "chars": 1037,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs.hpp",
    "chars": 2059,
    "preview": "// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root"
  },
  {
    "path": "libs/krabs/krabs.runsettings",
    "chars": 328,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RunSettings>\n  <!-- Configurations that affect the Test Framework -->\n  <RunConf"
  },
  {
    "path": "libs/krabs/krabs.sln",
    "chars": 10002,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.2.3231"
  }
]

About this extraction

This page contains the full source code of the thefLink/Hunt-Weird-Syscalls GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (305.7 KB), approximately 78.0k tokens, and a symbol index with 382 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!