Full Code of D4stiny/PeaceMaker for AI

master c96669d226d7 cached
60 files
315.3 KB
83.0k tokens
126 symbols
1 requests
Download .txt
Showing preview only (333K chars total). Download the full file or copy to clipboard to get everything.
Repository: D4stiny/PeaceMaker
Branch: master
Commit: c96669d226d7
Files: 60
Total size: 315.3 KB

Directory structure:
gitextract_zfage812/

├── .gitignore
├── LICENSE
├── PeaceMaker CLI/
│   ├── IOCTLCommunicationUser.cpp
│   ├── IOCTLCommunicationUser.h
│   ├── PeaceMaker CLI.cpp
│   ├── PeaceMaker CLI.vcxproj
│   └── PeaceMaker CLI.vcxproj.filters
├── PeaceMaker Kernel/
│   ├── AlertQueue.cpp
│   ├── AlertQueue.h
│   ├── DetectionLogic.cpp
│   ├── DetectionLogic.h
│   ├── FSFilter.cpp
│   ├── FSFilter.h
│   ├── FilterTesting.cpp
│   ├── IOCTLCommunication.cpp
│   ├── IOCTLCommunication.h
│   ├── ImageHistoryFilter.cpp
│   ├── ImageHistoryFilter.h
│   ├── PeaceMaker Kernel.inf
│   ├── PeaceMaker Kernel.rc
│   ├── PeaceMaker Kernel.vcxproj
│   ├── PeaceMaker Kernel.vcxproj.filters
│   ├── RCa19580
│   ├── RCa38200
│   ├── RegistryFilter.cpp
│   ├── RegistryFilter.h
│   ├── StackWalker.cpp
│   ├── StackWalker.h
│   ├── StringFilters.cpp
│   ├── StringFilters.h
│   ├── TamperGuard.cpp
│   ├── TamperGuard.h
│   ├── ThreadFilter.cpp
│   ├── ThreadFilter.h
│   ├── common.cpp
│   ├── common.h
│   ├── ntdef.h
│   └── shared.h
├── PeaceMaker Kernel.vcxproj
├── PeaceMaker.sln
├── PeaceMakerGUI/
│   ├── AssetResources.qrc
│   ├── ClickableTab.cpp
│   ├── ClickableTab.h
│   ├── InvestigateProcessWindow.cpp
│   ├── InvestigateProcessWindow.h
│   ├── InvestigateProcessWindow.ui
│   ├── PeaceMakerGUI.pro
│   ├── addfilterwindow.cpp
│   ├── addfilterwindow.h
│   ├── addfilterwindow.ui
│   ├── configparser.cpp
│   ├── configparser.h
│   ├── detailedalertwindow.cpp
│   ├── detailedalertwindow.h
│   ├── detailedalertwindow.ui
│   ├── main.cpp
│   ├── mainwindow.cpp
│   ├── mainwindow.h
│   └── mainwindow.ui
└── README.md

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

================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Bill Demirkapi

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: PeaceMaker CLI/IOCTLCommunicationUser.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "IOCTLCommunicationUser.h"

/**
	Default constructor.
*/
IOCTLCommunication::IOCTLCommunication(
	VOID
	)
{
	
}

/**
	Disconnect from the driver.
*/
IOCTLCommunication::~IOCTLCommunication(
	VOID
	)
{
	CloseHandle(this->device);
}

/**
	Establish communication with the driver.
	@return Whether or not we successfully connected to the driver.
*/
BOOLEAN
IOCTLCommunication::ConnectDevice(
	VOID
	)
{
	this->device = CreateFile(GLOBAL_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (this->device == INVALID_HANDLE_VALUE)
	{
		printf("IOCTLCommunication!IOCTLCommunication: Failed to connect to driver device with error %i.\n", GetLastError());
		return FALSE;
	}

	printf("IOCTLCommunication!IOCTLCommunication: Established communication with driver.\n");
	return TRUE;
}

/**
	Small wrapper around the DeviceIoControl call to the driver.
	@param IOCTLCode - The IOCTL code to pass to the driver.
	@param Input - The input buffer.
	@param InputLength - Size of the input buffer.
	@param Output - The output buffer.
	@param OutputLength - Size of the output buffer.
	@return Whether or not the call succeeded.
*/
BOOLEAN
IOCTLCommunication::GenericQueryDriver (
	_In_ DWORD IOCTLCode,
	_In_ PVOID Input,
	_In_ DWORD InputLength,
	_Out_ PVOID Output,
	_In_ DWORD OutputLength
	)
{
	DWORD bytesReturned;
	return DeviceIoControl(this->device, IOCTLCode, Input, InputLength, Output, OutputLength, &bytesReturned, NULL);
}

/**
	Query if there are alerts queued.
	@return Whether or not alerts are queued.
*/
BOOLEAN
IOCTLCommunication::QueuedAlerts (
	VOID
	)
{
	BOOLEAN queued;

	//
	// Query the driver passing in an output boolean.
	//
	if (this->GenericQueryDriver(IOCTL_ALERTS_QUEUED, NULL, 0, &queued, sizeof(queued)) == FALSE)
	{
		printf("IOCTLCommunication!QueuedAlerts: Failed to query driver with error code %i.\n", GetLastError());
		return FALSE;
	}

	return queued;
}

/**
	Pop a queued alert from the Alerts queue.
	@return An allocated pointer to the alert or NULL if unable to pop an alert. Caller must free to prevent leak.
*/
PBASE_ALERT_INFO
IOCTLCommunication::PopAlert(
	VOID
	)
{
	BOOLEAN success;
	PBASE_ALERT_INFO alert;

	success = FALSE;

	alert = RCAST<PBASE_ALERT_INFO>(malloc(MAX_STACK_VIOLATION_ALERT_SIZE));
	if (alert == NULL)
	{
		printf("IOCTLCommunication!PopAlert: Failed to allocate space for alert.\n");
		goto Exit;
	}
	memset(alert, 0, MAX_STACK_VIOLATION_ALERT_SIZE);

	if (this->GenericQueryDriver(IOCTL_POP_ALERT, NULL, 0, alert, MAX_STACK_VIOLATION_ALERT_SIZE) == FALSE)
	{
		printf("IOCTLCommunication!PopAlert: Failed to query driver with error code %i.\n", GetLastError());
		goto Exit;
	}
	success = TRUE;
Exit:
	if (success == FALSE && alert)
	{
		free(alert);
		alert = NULL;
	}
	return alert;
}

/**
	Request a summary of the most recent processes up to RequestCount.
	@param SkipCount - How many processes to "skip" in iteration.
	@param RequestCount - How many proocesses to get the summary of.
	@return The response to the summary request if any, otherwise NULL. Caller must free to prevent leak.
*/
PPROCESS_SUMMARY_REQUEST
IOCTLCommunication::RequestProcessSummary (
	_In_ ULONG SkipCount,
	_In_ ULONG RequestCount
	)
{
	BOOLEAN success;
	PPROCESS_SUMMARY_REQUEST summaryRequest;
	ULONG summaryRequestSize;

	success = FALSE;
	summaryRequestSize = MAX_PROCESS_SUMMARY_REQUEST_SIZE_RAW(RequestCount);

	summaryRequest = RCAST<PPROCESS_SUMMARY_REQUEST>(malloc(summaryRequestSize));
	if (summaryRequest == NULL)
	{
		printf("IOCTLCommunication!RequestProcessSummary: Failed to allocate space for summaryRequest.\n");
		goto Exit;
	}
	memset(summaryRequest, 0, summaryRequestSize);

	summaryRequest->SkipCount = SkipCount;
	summaryRequest->ProcessHistorySize = RequestCount;

	if (this->GenericQueryDriver(IOCTL_GET_PROCESSES, summaryRequest, summaryRequestSize, summaryRequest, summaryRequestSize) == FALSE)
	{
		printf("IOCTLCommunication!RequestProcessSummary: Failed to query driver with error code %i.\n", GetLastError());
		goto Exit;
	}
	success = TRUE;
Exit:
	if (success == FALSE && summaryRequest)
	{
		free(summaryRequest);
		summaryRequest = NULL;
	}
	return summaryRequest;
}

/**
	Request detailed information on a process.
	@param ProcessId - The subject process.
	@param EpochExecutionTime - The time the process was executed (in seconds since epoch).
	@param MaxImageSize - The maximum number of image entries to copy.
	@param MaxStackSize - The maximum number of stack entries to copy.
	@return The response to the detailed request if any, otherwise NULL. Caller must free to prevent leak.
*/
PPROCESS_DETAILED_REQUEST
IOCTLCommunication::RequestDetailedProcess (
	_In_ HANDLE ProcessId,
	_In_ ULONG EpochExecutionTime,
	_In_ ULONG MaxImageSize,
	_In_ ULONG MaxStackSize
	)
{
	BOOLEAN success;
	PPROCESS_DETAILED_REQUEST detailedRequest;
	ULONG detailedRequestSize;

	success = FALSE;
	detailedRequestSize = sizeof(PROCESS_DETAILED_REQUEST);

	//
	// Allocate the necessary members.
	//
	detailedRequest = RCAST<PPROCESS_DETAILED_REQUEST>(malloc(detailedRequestSize));
	if (detailedRequest == NULL)
	{
		printf("IOCTLCommunication!RequestDetailedProcess: Failed to allocate space for detailedRequest.\n");
		goto Exit;
	}
	memset(detailedRequest, 0, detailedRequestSize);

	detailedRequest->ImageSummary = RCAST<PIMAGE_SUMMARY>(malloc(MaxImageSize * sizeof(IMAGE_SUMMARY)));
	if (detailedRequest->ImageSummary == NULL)
	{
		printf("IOCTLCommunication!RequestDetailedProcess: Failed to allocate space for detailedRequest->ImageSummary.\n");
		goto Exit;
	}
	memset(detailedRequest->ImageSummary, 0, MaxImageSize * sizeof(IMAGE_SUMMARY));

	detailedRequest->StackHistory = RCAST<PSTACK_RETURN_INFO>(malloc(MaxStackSize * sizeof(STACK_RETURN_INFO)));
	if (detailedRequest->StackHistory == NULL)
	{
		printf("IOCTLCommunication!RequestDetailedProcess: Failed to allocate space for detailedRequest->StackHistory.\n");
		goto Exit;
	}
	memset(detailedRequest->StackHistory, 0, MaxStackSize * sizeof(STACK_RETURN_INFO));

	detailedRequest->ProcessId = ProcessId;
	detailedRequest->EpochExecutionTime = EpochExecutionTime;
	detailedRequest->ImageSummarySize = MaxImageSize;
	detailedRequest->StackHistorySize = MaxStackSize;

	if (this->GenericQueryDriver(IOCTL_GET_PROCESS_DETAILED, detailedRequest, detailedRequestSize, detailedRequest, detailedRequestSize) == FALSE)
	{
		printf("IOCTLCommunication!RequestDetailedProcess: Failed to query driver with error code %i.\n", GetLastError());
		goto Exit;
	}
	success = TRUE;
Exit:
	if (success == FALSE && detailedRequest)
	{
		free(detailedRequest);
		detailedRequest = NULL;
	}
	return detailedRequest;
}

/**
	Register a filter with the driver.
	@param Type - The filter type.
	@param Flags - The filter flags (EXECUTE/DELETE/WRITE/ETC).
	@param Content - The content of the filter.
	@param ContentLength - The size of the content.
	@return The filter ID (if added successfully), otherwise 0.
*/
ULONG
IOCTLCommunication::AddFilter (
	_In_ STRING_FILTER_TYPE Type,
	_In_ ULONG Flags,
	_In_ PWCHAR Content,
	_In_ ULONG ContentLength
	)
{

	STRING_FILTER_REQUEST filterRequest;

	//
	// Fill out the struct.
	//
	filterRequest.FilterType = Type;
	filterRequest.Filter.Flags = Flags;
	memcpy_s(filterRequest.Filter.MatchString, sizeof(filterRequest.Filter.MatchString), Content, ContentLength * sizeof(WCHAR));
	filterRequest.Filter.MatchStringSize = ContentLength;

	//
	// Query the driver passing in the filter request.
	//
	if (this->GenericQueryDriver(IOCTL_ADD_FILTER, &filterRequest, sizeof(filterRequest), &filterRequest, sizeof(filterRequest)) == FALSE)
	{
		printf("IOCTLCommunication!AddFilter: Failed to query driver with error code %i.\n", GetLastError());
		return 0;
	}

	return filterRequest.Filter.Id;
}

/**
	Request a list of filters with a constant size of 10. Grab more by using the SkipCount argument.
	@param Type - The type of filters to grab.
	@param SkipCount - The number of filters to skip during iteration.
	@return The response to the request.
*/
LIST_FILTERS_REQUEST
IOCTLCommunication::RequestFilters(
	_In_ STRING_FILTER_TYPE Type,
	_In_ ULONG SkipCount
	)
{
	LIST_FILTERS_REQUEST listRequest;

	listRequest.FilterType = Type;
	listRequest.SkipFilters = SkipCount;

	//
	// Query the driver passing in the list request.
	//
	if (this->GenericQueryDriver(IOCTL_LIST_FILTERS, &listRequest, sizeof(listRequest), &listRequest, sizeof(listRequest)) == FALSE)
	{
		printf("IOCTLCommunication!RequestFilters: Failed to query driver with error code %i.\n", GetLastError());
	}

	return listRequest;
}

/**
	Get the dynamic sizes in a process entry from the driver.
	@param ProcessId - The target process ID.
	@param EpochExecutionTime - The time the target process was executed.
	@return The response.
*/
PROCESS_SIZES_REQUEST
IOCTLCommunication::GetProcessSizes(
	_In_ HANDLE ProcessId,
	_In_ ULONG EpochExecutionTime
	)
{
	PROCESS_SIZES_REQUEST sizeRequest;

	sizeRequest.ProcessId = ProcessId;
	sizeRequest.EpochExecutionTime = EpochExecutionTime;

	//
	// Query the driver passing in the list request.
	//
	if (this->GenericQueryDriver(IOCTL_GET_PROCESS_SIZES, &sizeRequest, sizeof(sizeRequest), &sizeRequest, sizeof(sizeRequest)) == FALSE)
	{
		printf("IOCTLCommunication!GetProcessSizes: Failed to query driver with error code %i.\n", GetLastError());
	}

	return sizeRequest;
}

/**
	Request detailed information on an image.
	@param ProcessId - The subject process.
	@param EpochExecutionTime - The time the process was executed (in seconds since epoch).
	@param MaxStackSize - The maximum number of stack entries to copy.
	@return The response to the detailed request if any, otherwise NULL. Caller must free to prevent leak.
*/
PIMAGE_DETAILED_REQUEST
IOCTLCommunication::RequestDetailedImage (
	_In_ HANDLE ProcessId,
	_In_ ULONG EpochExecutionTime,
	_In_ ULONG ImageIndex,
	_In_ ULONG MaxStackSize
	)
{
	BOOLEAN success;
	PIMAGE_DETAILED_REQUEST imageRequest;
	ULONG imageRequestSize;

	success = FALSE;
	imageRequestSize = MAX_IMAGE_DETAILED_REQUEST_SIZE_RAW(MaxStackSize);

	imageRequest = RCAST<PIMAGE_DETAILED_REQUEST>(malloc(imageRequestSize));
	if (imageRequest == NULL)
	{
		printf("IOCTLCommunication!RequestDetailedImage: Failed to allocate space for imageRequest.\n");
		goto Exit;
	}
	memset(imageRequest, 0, imageRequestSize);

	imageRequest->ProcessId = ProcessId;
	imageRequest->EpochExecutionTime = EpochExecutionTime;
	imageRequest->ImageIndex = ImageIndex;
	imageRequest->StackHistorySize = MaxStackSize;

	if (this->GenericQueryDriver(IOCTL_GET_IMAGE_DETAILED, imageRequest, imageRequestSize, imageRequest, imageRequestSize) == FALSE)
	{
		printf("IOCTLCommunication!RequestDetailedImage: Failed to query driver with error code %i.\n", GetLastError());
		goto Exit;
	}
	success = TRUE;
Exit:
	if (success == FALSE && imageRequest)
	{
		free(imageRequest);
		imageRequest = NULL;
	}
	return imageRequest;
}

/**
	Get global sizes from the kernel
	@return The various sizes of data stored in the kernel.
*/
GLOBAL_SIZES
IOCTLCommunication::GetGlobalSizes (
	VOID
	)
{
	GLOBAL_SIZES sizes;

	//
	// Query the driver passing in the size request.
	//
	if (this->GenericQueryDriver(IOCTL_GET_GLOBAL_SIZES, NULL, 0, &sizes, sizeof(sizes)) == FALSE)
	{
		printf("IOCTLCommunication!GetProcessSizes: Failed to query driver with error code %i.\n", GetLastError());
	}

	return sizes;
}

/**
	Delete a filter.
	@param Filter - The filter to delete.
	@return Whether or not the filter was deleted.
*/
BOOLEAN
IOCTLCommunication::DeleteFilter (
	_In_ FILTER_INFO Filter
	)
{
	DELETE_FILTER_REQUEST deleteFilterRequest;

	deleteFilterRequest.FilterId = Filter.Id;
	deleteFilterRequest.FilterType = Filter.Type;

	//
	// Query the driver passing in the delete request.
	//
	if (this->GenericQueryDriver(IOCTL_DELETE_FILTER, &deleteFilterRequest, sizeof(deleteFilterRequest), &deleteFilterRequest, sizeof(deleteFilterRequest)) == FALSE)
	{
		printf("IOCTLCommunication!DeleteFilter: Failed to query driver with error code %i.\n", GetLastError());
	}

	return deleteFilterRequest.Deleted;
}

================================================
FILE: PeaceMaker CLI/IOCTLCommunicationUser.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include <Windows.h>
#include <cstdio>
#include "shared.h"

class IOCTLCommunication
{
	HANDLE device;

	BOOLEAN GenericQueryDriver(
		_In_ DWORD IOCTLCode,
		_In_ PVOID Input,
		_In_ DWORD InputLength,
		_Out_ PVOID Output,
		_In_ DWORD OutputLength
		);

public:
	IOCTLCommunication(VOID);
	~IOCTLCommunication(VOID);

	BOOLEAN ConnectDevice(
		VOID
		);
	BOOLEAN QueuedAlerts(
		VOID
		);
	PBASE_ALERT_INFO PopAlert(
		VOID
		);
	PPROCESS_SUMMARY_REQUEST RequestProcessSummary(
		_In_ ULONG SkipCount,
		_In_ ULONG RequestCount
		);
	PPROCESS_DETAILED_REQUEST RequestDetailedProcess(
		_In_ HANDLE ProcessId,
		_In_ ULONG EpochExecutionTime,
		_In_ ULONG MaxImageSize,
		_In_ ULONG MaxStackSize
		);
	ULONG AddFilter(
		_In_ STRING_FILTER_TYPE Type,
		_In_ ULONG Flags,
		_In_ PWCHAR Content,
		_In_ ULONG ContentLength
		);
	LIST_FILTERS_REQUEST RequestFilters(
		_In_ STRING_FILTER_TYPE Type,
		_In_ ULONG SkipCount
		);
	PROCESS_SIZES_REQUEST GetProcessSizes(
		_In_ HANDLE ProcessId,
		_In_ ULONG EpochExecutionTime
		);
	PIMAGE_DETAILED_REQUEST RequestDetailedImage(
		_In_ HANDLE ProcessId,
		_In_ ULONG EpochExecutionTime,
		_In_ ULONG ImageIndex,
		_In_ ULONG MaxStackSize
		);
	GLOBAL_SIZES GetGlobalSizes(
		VOID
		);
	BOOLEAN DeleteFilter(
		_In_ FILTER_INFO Filter
		);
};

================================================
FILE: PeaceMaker CLI/PeaceMaker CLI.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include <Windows.h>
#include <iostream>
#include <string>
#include "IOCTLCommunicationUser.h"

/**
	Print stack history.
	@param StackHistory - The history to display.
	@param StackHistorySize - The size of the StackHistory array.
*/
VOID
DisplayStackHistory(
	_In_ PSTACK_RETURN_INFO StackHistory,
	_In_ ULONG StackHistorySize
	)
{
	ULONG i;

	printf("DisplayStackHistory: \tStack History:\n");
	for (i = 0; i < StackHistorySize; i++)
	{
		if (StackHistory[i].MemoryInModule)
		{
			printf("DisplayStackHistory: \t\t%ws+0x%X\n", StackHistory[i].BinaryPath, StackHistory[i].BinaryOffset);
		}
		else
		{
			printf("DisplayStackHistory: \t\t0x%llx (Manual Mapped)\n", StackHistory[i].RawAddress);
		}
	}
}

/**
	Display an alert. Supports the various alert types.
	@param Alert - Alert to display.
*/
VOID
DisplayAlert (
	PBASE_ALERT_INFO Alert
	)
{
	PSTACK_VIOLATION_ALERT stackViolationAlert;
	PFILTER_VIOLATION_ALERT filterViolationAlert;

	//
	// Sanity check.
	//
	if (Alert == NULL)
	{
		printf("DisplayAlert: No alert found.\n");
		return;
	}

	printf("DisplayAlert: Alert dump:\n");
	switch (Alert->AlertSource)
	{
	case ProcessCreate:
		printf("DisplayAlert: \tSource: Process creation callback\n");
		break;
	case ImageLoad:
		printf("DisplayAlert: \tSource: Image load callback\n");
		break;
	case RegistryFilterMatch:
		printf("DisplayAlert: \tSource: Registry filter match\n");
		break;
	case FileFilterMatch:
		printf("DisplayAlert: \tSource: File filter match\n");
		break;
	case ThreadCreate:
		printf("DisplayAlert: \tSource: Thread creation callback\n");
		break;
	}
	
	switch (Alert->AlertType)
	{
	case StackViolation:
		stackViolationAlert = RCAST<PSTACK_VIOLATION_ALERT>(Alert);
		printf("DisplayAlert: \tAlert Type: Stack walk violation\n");
		printf("DisplayAlert: \tViolating Address: 0x%llx\n", stackViolationAlert->ViolatingAddress);
		DisplayStackHistory(stackViolationAlert->StackHistory, stackViolationAlert->StackHistorySize);
		break;
	case FilterViolation:
		filterViolationAlert = RCAST<PFILTER_VIOLATION_ALERT>(Alert);
		printf("DisplayAlert: \tAlert Type: Filter violation\n");
		printf("DisplayAlert: \tFilter content: %ws\n", filterViolationAlert->ViolatedFilter.MatchString);
		printf("DisplayAlert: \tFilter flags: 0x%X\n", filterViolationAlert->ViolatedFilter.Flags);
		DisplayStackHistory(filterViolationAlert->StackHistory, filterViolationAlert->StackHistorySize);
		break;
	}
}

int main()
{
	IOCTLCommunication communicator;
	std::string input;
	int choice;

	PBASE_ALERT_INFO alert;
	PPROCESS_SUMMARY_REQUEST processSummaries;
	PPROCESS_DETAILED_REQUEST processDetailed;
	PROCESS_SIZES_REQUEST processSizes;
	LIST_FILTERS_REQUEST filters;
	PIMAGE_DETAILED_REQUEST imageDetailed;

	ULONG i;
	int skipCount;
	int requestCount;
	HANDLE processID;
	ULONG executionTime;
	STRING_FILTER_TYPE filterType;
	ULONG filterFlags;
	std::wstring filterContent;
	ULONG filterId;
	ULONG imageIndex;

	choice = 7;

	printf("main: Initiating communication with the driver.\n");
	if (communicator.ConnectDevice() == FALSE)
	{
		printf("main: Failed to connect to the device.\n");
		goto Exit;
	}

	printf("main: Communication initiated.\n");
	do
	{
		printf("main: PeaceMaker basic CLI utility\n");
		printf("main: 1. Check if there are alerts queued.\n");
		printf("main: 2. Pop an alert from the list of alerts.\n");
		printf("main: 3. Request a list of process summaries.\n");
		printf("main: 4. Request detailed information on a process.\n");
		printf("main: 5. Request to add a filter.\n");
		printf("main: 6. Request a list of filters.\n");
		printf("main: 7. Request detailed information on an image in a process.\n");
		printf("main: 8. Exit.\n");

		std::cin >> input;
		choice = std::stoi(input);

		//
		// Depending on the user's choice, dispatch to the correct function.
		//
		switch (choice)
		{
		case 1:
			if (communicator.QueuedAlerts())
			{
				printf("main: There are alerts queued.\n");
				break;
			}
			printf("main: There are no alerts queued.\n");
			break;
		case 2:
			alert = communicator.PopAlert();
			DisplayAlert(alert);
			free(alert);
			alert = NULL;
			break;
		case 3:
			//
			// Ask for the necessary information.
			//
			printf("main: How many processes should we skip?\n");
			std::cin >> input;
			skipCount = std::stoi(input);

			printf("main: How many processes should we request?\n");
			std::cin >> input;
			requestCount = std::stoi(input);

			//
			// Get the summamries.
			//
			processSummaries = communicator.RequestProcessSummary(skipCount, requestCount);
			if (processSummaries == NULL)
			{
				printf("main: Failed to retrieve process summaries.\n");
				break;
			}

			//
			// Print the processes in a "table" format.
			//
			printf("main: %-10s\t%-50s\t%-12s\n", "Process ID", "Path", "Execution Time");
			for (i = 0; i < processSummaries->ProcessHistorySize; i++)
			{
				if (processSummaries->ProcessHistory[i].ProcessId == 0)
				{
					continue;
				}
				printf("main: %-10i\t%-50ws\t%-12i\n", processSummaries->ProcessHistory[i].ProcessId, processSummaries->ProcessHistory[i].ImageFileName, processSummaries->ProcessHistory[i].EpochExecutionTime);
			}

			free(processSummaries);
			processSummaries = NULL;
			break;
		case 4:
			//
			// Ask for the necessary information.
			//
			printf("main: What is the target process ID?\n");
			std::cin >> input;
			processID = RCAST<HANDLE>(std::stoi(input));

			printf("main: What is the processes execution time in epoch?\n");
			std::cin >> input;
			executionTime = std::stoi(input);

			processSizes = communicator.GetProcessSizes(processID, executionTime);
			printf("main: ImageSize = %i, StackSize = %i\n", processSizes.ImageSize, processSizes.StackSize);

			//
			// Request a detailed report on the process.
			//
			processDetailed = communicator.RequestDetailedProcess(processID, executionTime, processSizes.ImageSize, processSizes.StackSize);
			if (processDetailed == NULL || processDetailed->Populated == FALSE)
			{
				printf("main: Failed to retrieve a detailed process report.\n");
				break;
			}

			printf("main: Process 0x%X:\n", processID);
			printf("main: \tProcess Path: %ws\n", processDetailed->ProcessPath);
			printf("main: \tCaller Process ID: 0x%X\n", processDetailed->CallerProcessId);
			printf("main: \tCaller Process Path: %ws\n", processDetailed->CallerProcessPath);
			printf("main: \tParent Process ID: 0x%X\n", processDetailed->ParentProcessId);
			printf("main: \tParent Process Path: %ws\n", processDetailed->ParentProcessPath);
			DisplayStackHistory(processDetailed->StackHistory, processDetailed->StackHistorySize);

			printf("main: \t%-3s\t%-100s:\n", "ID", "IMAGE PATH");
			for (i = 0; i < processDetailed->ImageSummarySize; i++)
			{
				printf("main: \t\t%-3i\t%-100ws\n", i, processDetailed->ImageSummary[i].ImagePath);
			}

			free(processDetailed->ImageSummary);
			free(processDetailed->StackHistory);
			free(processDetailed);
			processDetailed = NULL;
			break;
		case 5:
			//
			// Ask for the necessary information.
			//
			printf("main: What type of filter to add (R/F)?\n");
			std::cin >> input;
			switch (input[0])
			{
			case 'R':
			case 'r':
				filterType = RegistryFilter;
				break;
			case 'F':
			case 'f':
				filterType = FilesystemFilter;
				break;
			}

			printf("main: What flags should the filter have (D/W/E, can enter multiple)?\n");
			std::cin >> input;
			filterFlags = 0;
			for (char c : input)
			{
				switch (c)
				{
				case 'D':
				case 'd':
					filterFlags |= FILTER_FLAG_DELETE;
					break;
				case 'W':
				case 'w':
					filterFlags |= FILTER_FLAG_WRITE;
					break;
				case 'E':
				case 'e':
					filterFlags |= FILTER_FLAG_DELETE;
					break;
				}
			}

			printf("main: What should the filter content be?\n");
			std::wcin >> filterContent;

			filterId = communicator.AddFilter(filterType, filterFlags, CCAST<PWCHAR>(filterContent.c_str()), filterContent.length());
			if (filterId)
			{
				printf("main: Filter added with ID 0x%X.\n", filterId);
				break;
			}
			printf("main: Failed to add filter.\n");
			break;
		case 6:
			//
			// Ask for the necessary information.
			//
			printf("main: What type of filter to list (R/F)?\n");
			std::cin >> input;
			switch (input[0])
			{
			case 'R':
			case 'r':
				filterType = RegistryFilter;
				break;
			case 'F':
			case 'f':
				filterType = FilesystemFilter;
				break;
			}

			printf("main: How many filters should we skip?\n");
			std::cin >> input;
			skipCount = std::stoi(input);

			filters = communicator.RequestFilters(filterType, skipCount);
			for (i = 0; i < filters.CopiedFilters; i++)
			{
				printf("main: Filter 0x%X:\n");
				switch (filters.Filters[i].Type)
				{
				case RegistryFilter:
					printf("main: \tFilter Type: Registry filter");
					break;
				case FilesystemFilter:
					printf("main: \tFilter Type: Filesystem filter");
					break;
				}

				printf("main: \tFilter Flags: ");

				if (FlagOn(filters.Filters[i].Flags, FILTER_FLAG_DELETE))
				{
					printf("main: \t\tDELETE\n");
				}
				if (FlagOn(filters.Filters[i].Flags, FILTER_FLAG_WRITE))
				{
					printf("main: \t\tWRITE\n");
				}
				if (FlagOn(filters.Filters[i].Flags, FILTER_FLAG_EXECUTE))
				{
					printf("main: \t\tDELETE\n");
				}

				printf("main: \tFilter Content: %ws\n", filters.Filters[i].MatchString);
			}
			break;
		case 7:
			//
			// Ask for the necessary information.
			//
			printf("main: What is the target process ID?\n");
			std::cin >> input;
			processID = RCAST<HANDLE>(std::stoi(input));

			printf("main: What is the processes execution time in epoch?\n");
			std::cin >> input;
			executionTime = std::stoi(input);

			processSizes = communicator.GetProcessSizes(processID, executionTime);
			printf("main: ImageSize = %i, StackSize = %i\n", processSizes.ImageSize, processSizes.StackSize);

			//
			// Request a detailed report on the process.
			//
			processDetailed = communicator.RequestDetailedProcess(processID, executionTime, processSizes.ImageSize, processSizes.StackSize);
			if (processDetailed == NULL || processDetailed->Populated == FALSE)
			{
				printf("main: Failed to retrieve a detailed process report.\n");
				break;
			}

			printf("main: \t%-3s\t%-50s\n", "ID", "IMAGE PATH");
			for (i = 0; i < processDetailed->ImageSummarySize; i++)
			{
				printf("main: \t%-3i\t%-50ws\n", i, processDetailed->ImageSummary[i].ImagePath);
			}

			printf("main: Enter the ID of the image to query.\n");
			std::cin >> input;
			imageIndex = std::stoi(input);

			printf("main: Image stack size: %i\n", processDetailed->ImageSummary[imageIndex].StackSize);

			imageDetailed = communicator.RequestDetailedImage(processID, executionTime, imageIndex, processDetailed->ImageSummary[imageIndex].StackSize);
			if (imageDetailed == NULL || imageDetailed->Populated == FALSE)
			{
				printf("main: Failed to retrieve a detailed image report.\n");
				break;
			}

			printf("main: Image %i:\n", imageIndex);
			printf("main: \tPath: %ws\n", imageDetailed->ImagePath);
			DisplayStackHistory(imageDetailed->StackHistory, imageDetailed->StackHistorySize);

			free(processDetailed);
			free(imageDetailed);
			break;
		case 8:
			//
			// No handling required, will exit when the while condition is checked.
			//
			break;
		default:
			printf("main: Unrecognized option %i.\n", choice);
			break;
		}
	} while (input != "8");
Exit:
	_fgetchar();
	return 0;
}

================================================
FILE: PeaceMaker CLI/PeaceMaker CLI.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>
    <ProjectGuid>{A287D40E-AB7B-4FE9-AA84-44114766C79D}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>PeaceMakerCLI</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>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</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)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
    <IncludePath>$(SolutionDir)\PeaceMaker Kernel;$(IncludePath)</IncludePath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>MaxSpeed</Optimization>
      <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>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <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)'=='Debug|x64'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <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|Win32'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>MaxSpeed</Optimization>
      <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>
  <ItemGroup>
    <ClCompile Include="IOCTLCommunicationUser.cpp" />
    <ClCompile Include="PeaceMaker CLI.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="IOCTLCommunicationUser.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: PeaceMaker CLI/PeaceMaker CLI.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;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;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="PeaceMaker CLI.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="IOCTLCommunicationUser.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="IOCTLCommunicationUser.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
</Project>

================================================
FILE: PeaceMaker Kernel/AlertQueue.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "AlertQueue.h"

/**
	Initialize basic members of the AlertQueue class.
*/
AlertQueue::AlertQueue()
{
	this->alertsLock = RCAST<PKSPIN_LOCK>(ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK), ALERT_LOCK_TAG));
	NT_ASSERT(this->alertsLock);
	this->destroying = FALSE;
	KeInitializeSpinLock(this->alertsLock);
	InitializeListHead(RCAST<PLIST_ENTRY>(&this->alertsHead));
}

/**
	Clear the queue of alerts.
*/
AlertQueue::~AlertQueue()
{
	PLIST_ENTRY currentEntry;
	KIRQL oldIRQL;

	//
	// Make sure no one is doing operations on the AlertQueue.
	//
	this->destroying = TRUE;

	KeAcquireSpinLock(this->alertsLock, &oldIRQL);
	KeReleaseSpinLock(this->alertsLock, oldIRQL);

	while (IsListEmpty(RCAST<PLIST_ENTRY>(&this->alertsHead)) == FALSE)
	{
		currentEntry = RemoveHeadList(RCAST<PLIST_ENTRY>(&this->alertsHead));
		//
		// Free the entry.
		//
		ExFreePoolWithTag(SCAST<PVOID>(currentEntry), ALERT_QUEUE_ENTRY_TAG);
	}

	ExFreePoolWithTag(this->alertsLock, ALERT_LOCK_TAG);
}

/**
	Push an alert to the queue.
	@param Alert - The alert to push.
	@return Whether or not pushing the alert was successful.
*/
VOID
AlertQueue::PushAlert (
	_In_ PBASE_ALERT_INFO Alert,
	_In_ ULONG AlertSize
	)
{
	PBASE_ALERT_INFO newAlert;

	if (this->destroying)
	{
		return;
	}

	//
	// Allocate space for the new alert and copy the details.
	//
	newAlert = RCAST<PBASE_ALERT_INFO>(ExAllocatePoolWithTag(NonPagedPool, AlertSize, ALERT_QUEUE_ENTRY_TAG));
	if (newAlert == NULL)
	{
		DBGPRINT("AlertQueue!PushAlert: Failed to allocate space for new alert.");
		return;
	}
	memset(newAlert, 0, AlertSize);
	memcpy(newAlert, Alert, AlertSize);
	newAlert->AlertSize = AlertSize;

	//
	// Queue the alert.
	//
	ExInterlockedInsertTailList(RCAST<PLIST_ENTRY>(&this->alertsHead), RCAST<PLIST_ENTRY>(newAlert), this->alertsLock);
}

/**
	Pop an alert from the queue of alerts. Follows FI-FO.
	@return The first in queued alert.
*/
PBASE_ALERT_INFO
AlertQueue::PopAlert (
	VOID
	)
{
	if (this->destroying)
	{
		return NULL;
	}
	return RCAST<PBASE_ALERT_INFO>(ExInterlockedRemoveHeadList(RCAST<PLIST_ENTRY>(&this->alertsHead), this->alertsLock));
}

/**
	Check if the queue of alerts is empty.
	@return Whether or not the alerts queue is empty.
*/
BOOLEAN
AlertQueue::IsQueueEmpty (
	VOID
	)
{
	BOOLEAN empty;
	KIRQL oldIrql;

	ExAcquireSpinLock(this->alertsLock, &oldIrql);
	empty = IsListEmpty(RCAST<PLIST_ENTRY>(&this->alertsHead));
	ExReleaseSpinLock(this->alertsLock, oldIrql);

	return empty;
}


/**
	Free a previously pop'd alert.
	@param Alert - The alert to free.
*/
VOID
AlertQueue::FreeAlert(
	_In_ PBASE_ALERT_INFO Alert
	)
{
	ExFreePoolWithTag(Alert, ALERT_QUEUE_ENTRY_TAG);
}

================================================
FILE: PeaceMaker Kernel/AlertQueue.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "shared.h"

typedef class AlertQueue
{
	BASE_ALERT_INFO alertsHead; // The linked list of alerts.
	PKSPIN_LOCK alertsLock; // The lock protecting the linked-list of alerts.
	BOOLEAN destroying; // This boolean indicates to functions that a lock should not be held as we are in the process of destruction.

public:
	AlertQueue();
	~AlertQueue();

	VOID PushAlert (
		_In_ PBASE_ALERT_INFO Alert,
		_In_ ULONG AlertSize
		);

	PBASE_ALERT_INFO PopAlert (
		VOID
		);

	BOOLEAN IsQueueEmpty (
		VOID
		);

	VOID FreeAlert (
		_In_ PBASE_ALERT_INFO Alert
		);

} ALERT_QUEUE, *PALERT_QUEUE;

#define ALERT_LOCK_TAG 'lAmP'
#define ALERT_QUEUE_ENTRY_TAG 'eAmP'

================================================
FILE: PeaceMaker Kernel/DetectionLogic.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "DetectionLogic.h"

/**
	Initialize class members.
*/
DetectionLogic::DetectionLogic()
{
	alerts = new (NonPagedPool, ALERT_QUEUE_TAG) AlertQueue();
}

/**
	Deconstruct class members.
*/
DetectionLogic::~DetectionLogic()
{
	alerts->~AlertQueue();
	ExFreePoolWithTag(alerts, ALERT_QUEUE_TAG);
}

/**
	Get the alert queue for this detection logic instance.
	@return The Alert Queue.
*/
PALERT_QUEUE
DetectionLogic::GetAlertQueue (
	VOID
	)
{
	return this->alerts;
}

/**
	Audit a stack history for invalid code.
	@param DetectionSource - The filter we are checking the stack of.
	@param SourceProcessId - The source of the audit.
	@param SourcePath - The source path.
	@param TargetPath - The target path.
	@param StackHistory - A variable-length array of stack return history.
	@param StackHistorySize - Size of the StackHistory array.
*/
VOID
DetectionLogic::AuditUserStackWalk (
	_In_ DETECTION_SOURCE DetectionSource,
	_In_ HANDLE SourceProcessId,
	_In_ PUNICODE_STRING SourcePath,
	_In_ PUNICODE_STRING TargetPath,
	_In_ STACK_RETURN_INFO StackHistory[],
	_In_ ULONG StackHistorySize
	)
{
	ULONG i;
	BOOLEAN stackViolation;
	PVOID firstViolatingAddress;

	stackViolation = FALSE;
	firstViolatingAddress = NULL;

	//
	// Check if any of the stack returns are to unmapped code.
	//
	for (i = 0; i < StackHistorySize; i++)
	{
		if (StackHistory[i].MemoryInModule == FALSE &&
			StackHistory[i].ExecutableMemory &&
			StackHistory[i].RawAddress != 0x0 &&
			RCAST<ULONG64>(StackHistory[i].RawAddress) < MmUserProbeAddress)
		{
			DBGPRINT("DetectionLogic!AuditUserStackWalk: Alert pid 0x%X, Violate 0x%llx, Source %i", PsGetCurrentProcessId(), StackHistory[i].RawAddress, DetectionSource);
			stackViolation = TRUE;
			firstViolatingAddress = StackHistory[i].RawAddress;
			break;
		}
	}

	if (stackViolation == FALSE)
	{
		return;
	}

	//
	// Push the alert.
	//
	this->PushStackViolationAlert(DetectionSource, firstViolatingAddress, SourceProcessId, SourcePath, TargetPath, StackHistory, StackHistorySize);
}

/**
	Create and push a stack violation alert.
	@param DetectionSource - The filter we are checking the stack of.
	@param ViolatingAddress - If the origin of this alert is from an audit address operation, log the specific address.
	@param SourceProcessId - The source of the audit.
	@param SourcePath - The source path.
	@param TargetPath - The target path.
	@param StackHistory - A variable-length array of stack return history.
	@param StackHistorySize - Size of the StackHistory array.
*/
VOID
DetectionLogic::PushStackViolationAlert(
	_In_ DETECTION_SOURCE DetectionSource,
	_In_ PVOID ViolatingAddress,
	_In_ HANDLE SourceProcessId,
	_In_ PUNICODE_STRING SourcePath,
	_In_ PUNICODE_STRING TargetPath,
	_In_ STACK_RETURN_INFO StackHistory[],
	_In_ ULONG StackHistorySize
	)
{
	ULONG stackHistoryBytes;
	PSTACK_VIOLATION_ALERT stackViolationAlert;

	//
	// Calculate the size of the StackHistory array in bytes.
	//
	stackHistoryBytes = sizeof(STACK_RETURN_INFO) * (StackHistorySize-1);

	//
	// Allocate space for the alert depending on the size of StackHistory.
	//
	stackViolationAlert = RCAST<PSTACK_VIOLATION_ALERT>(ExAllocatePoolWithTag(PagedPool, sizeof(STACK_VIOLATION_ALERT) + stackHistoryBytes, STACK_VIOLATION_TAG));
	if (stackViolationAlert == NULL)
	{
		DBGPRINT("DetectionLogic!PushStackViolationAlert: Failed to allocate space for the alert.");
		return;
	}
	memset(stackViolationAlert, 0, sizeof(STACK_VIOLATION_ALERT) + stackHistoryBytes);

	//
	// Fill the fields of the alert.
	//
	stackViolationAlert->AlertInformation.AlertType = StackViolation;
	stackViolationAlert->AlertInformation.AlertSource = DetectionSource;
	stackViolationAlert->ViolatingAddress = ViolatingAddress;
	stackViolationAlert->AlertInformation.SourceId = SourceProcessId;

	if (SourcePath)
	{
		RtlStringCbCopyUnicodeString(stackViolationAlert->AlertInformation.SourcePath, MAX_PATH, SourcePath);
	}
	if (TargetPath)
	{
		RtlStringCbCopyUnicodeString(stackViolationAlert->AlertInformation.TargetPath, MAX_PATH, TargetPath);
	}

	stackViolationAlert->StackHistorySize = StackHistorySize;
	memcpy(&stackViolationAlert->StackHistory, StackHistory, sizeof(STACK_RETURN_INFO) * StackHistorySize);

	//
	// Push the alert.
	//
	this->alerts->PushAlert(RCAST<PBASE_ALERT_INFO>(stackViolationAlert), sizeof(STACK_VIOLATION_ALERT) + stackHistoryBytes);

	//
	// PushAlert copies the alert, so we can free our copy.
	//
	ExFreePoolWithTag(stackViolationAlert, STACK_VIOLATION_TAG);
}

/**
	Validate a user-mode pointer.
	@param DetectionSource - The filter we are checking the stack of.
	@param UserPtr - The pointer to check.
	@param SourceProcessId - The source of the audit.
	@param SourcePath - The source path.
	@param TargetPath - The target path.
	@param StackHistory - A variable-length array of stack return history.
	@param StackHistorySize - Size of the StackHistory array.
*/
VOID
DetectionLogic::AuditUserPointer (
	_In_ DETECTION_SOURCE DetectionSource,
	_In_ PVOID UserPtr,
	_In_ HANDLE SourceProcessId,
	_In_ PUNICODE_STRING SourcePath,
	_In_ PUNICODE_STRING TargetPath,
	_In_ STACK_RETURN_INFO StackHistory[],
	_In_ ULONG StackHistorySize
	)
{
	STACK_RETURN_INFO info;

	info.RawAddress = UserPtr;

	//
	// Resolve basic information about the module.
	//
	resolver.ResolveAddressModule(UserPtr, &info);

	//
	// If the user pointer isn't mapped, something's wrong.
	//
	if (info.MemoryInModule == FALSE &&
		info.ExecutableMemory &&
		info.RawAddress != 0x0 &&
		RCAST<ULONG64>(info.RawAddress) < MmUserProbeAddress)
	{
		this->PushStackViolationAlert(DetectionSource, UserPtr, SourceProcessId, SourcePath, TargetPath, StackHistory, StackHistorySize);
	}
}

/**
	Check if an operation is on a remote process. This is called by suspicious operation callbacks such as Thread Creation.
	@param DetectionSource - The filter we are checking the stack of.
	@param UserPtr - The pointer to check.
	@param SourceProcessId - The source of the audit.
	@param SourceProcessId - The target of the operation.
	@param SourcePath - The source path.
	@param TargetPath - The target path.
	@param StackHistory - A variable-length array of stack return history.
	@param StackHistorySize - Size of the StackHistory array.
*/
VOID
DetectionLogic::AuditCallerProcessId(
	_In_ DETECTION_SOURCE DetectionSource,
	_In_ HANDLE CallerProcessId,
	_In_ HANDLE TargetProcessId,
	_In_ PUNICODE_STRING SourcePath,
	_In_ PUNICODE_STRING TargetPath,
	_In_ STACK_RETURN_INFO StackHistory[],
	_In_ ULONG StackHistorySize
	)
{
	ULONG stackHistoryBytes;
	PREMOTE_OPERATION_ALERT remoteOperationAlert;

	//
	// If the operation is on the current process, no problems!
	//
	if (CallerProcessId == TargetProcessId)
	{
		return;
	}

	//
	// Calculate the size of the StackHistory array in bytes.
	//
	stackHistoryBytes = sizeof(STACK_RETURN_INFO) * (StackHistorySize - 1);

	//
	// Allocate space for the alert depending on the size of StackHistory.
	//
	remoteOperationAlert = RCAST<PREMOTE_OPERATION_ALERT>(ExAllocatePoolWithTag(PagedPool, sizeof(REMOTE_OPERATION_ALERT) + stackHistoryBytes, STACK_VIOLATION_TAG));
	if (remoteOperationAlert == NULL)
	{
		DBGPRINT("DetectionLogic!PushStackViolationAlert: Failed to allocate space for the alert.");
		return;
	}
	memset(remoteOperationAlert, 0, sizeof(REMOTE_OPERATION_ALERT) + stackHistoryBytes);

	//
	// Fill the fields of the alert.
	//
	switch (DetectionSource)
	{
	case ProcessCreate:
		remoteOperationAlert->AlertInformation.AlertType = ParentProcessIdSpoofing;
		break;
	case ThreadCreate:
		remoteOperationAlert->AlertInformation.AlertType = RemoteThreadCreation;
		break;
	}
	remoteOperationAlert->AlertInformation.AlertSource = DetectionSource;
	remoteOperationAlert->AlertInformation.SourceId = CallerProcessId;
	remoteOperationAlert->RemoteTargetId = TargetProcessId;

	if (SourcePath)
	{
		RtlStringCbCopyUnicodeString(remoteOperationAlert->AlertInformation.SourcePath, MAX_PATH, SourcePath);
	}
	if (TargetPath)
	{
		RtlStringCbCopyUnicodeString(remoteOperationAlert->AlertInformation.TargetPath, MAX_PATH, TargetPath);
	}

	remoteOperationAlert->StackHistorySize = StackHistorySize;
	memcpy(&remoteOperationAlert->StackHistory, StackHistory, sizeof(STACK_RETURN_INFO) * StackHistorySize);

	//
	// Push the alert.
	//
	this->alerts->PushAlert(RCAST<PBASE_ALERT_INFO>(remoteOperationAlert), sizeof(REMOTE_OPERATION_ALERT) + stackHistoryBytes);

	//
	// PushAlert copies the alert, so we can free our copy.
	//
	ExFreePoolWithTag(remoteOperationAlert, STACK_VIOLATION_TAG);
}

/**
	Report a filter violation.
	@param DetectionSource - The filter type that was violated.
	@param CallerProcessId - The process ID of the caller that violated the filter.
	@param CallerPath - The path of the caller process.
	@param ViolatingPath - The path that triggered the filter violation.
	@param StackHistory - A variable-length array of stack return history.
	@param StackHistorySize - Size of the StackHistory array.
*/
VOID
DetectionLogic::ReportFilterViolation (
	_In_ DETECTION_SOURCE DetectionSource,
	_In_ HANDLE CallerProcessId,
	_In_ PUNICODE_STRING CallerPath,
	_In_ PUNICODE_STRING ViolatingPath,
	_In_ STACK_RETURN_INFO StackHistory[],
	_In_ ULONG StackHistorySize
	)
{
	ULONG stackHistoryBytes;
	PFILTER_VIOLATION_ALERT filterViolationAlert;

	//
	// Sanity check, sometimes stack history can be NULL if the stackwalk failed.
	//
	if (StackHistory == NULL || StackHistorySize == 0)
	{
		DBGPRINT("DetectionLogic!ReportFilterViolation: StackHistory was invalid!");
		return;
	}

	//
	// Calculate the size of the StackHistory array in bytes.
	//
	stackHistoryBytes = sizeof(STACK_RETURN_INFO) * (StackHistorySize - 1);

	//
	// Allocate space for the alert depending on the size of StackHistory.
	//
	filterViolationAlert = RCAST<PFILTER_VIOLATION_ALERT>(ExAllocatePoolWithTag(PagedPool, sizeof(FILTER_VIOLATION_ALERT) + stackHistoryBytes, STACK_VIOLATION_TAG));
	if (filterViolationAlert == NULL)
	{
		DBGPRINT("DetectionLogic!ReportFilterViolation: Failed to allocate space for the alert.");
		return;
	}
	memset(filterViolationAlert, 0, sizeof(FILTER_VIOLATION_ALERT) + stackHistoryBytes);

	filterViolationAlert->AlertInformation.AlertType = FilterViolation;
	filterViolationAlert->AlertInformation.AlertSource = DetectionSource;
	filterViolationAlert->AlertInformation.SourceId = CallerProcessId;

	if (CallerPath)
	{
		RtlStringCbCopyUnicodeString(filterViolationAlert->AlertInformation.SourcePath, MAX_PATH, CallerPath);
	}
	if (ViolatingPath)
	{
		RtlStringCbCopyUnicodeString(filterViolationAlert->AlertInformation.TargetPath, MAX_PATH, ViolatingPath);
	}

	filterViolationAlert->StackHistorySize = StackHistorySize;
	memcpy(&filterViolationAlert->StackHistory, StackHistory, sizeof(STACK_RETURN_INFO) * StackHistorySize);

	//
	// Push the alert.
	//
	this->alerts->PushAlert(RCAST<PBASE_ALERT_INFO>(filterViolationAlert), sizeof(FILTER_VIOLATION_ALERT) + stackHistoryBytes);

	//
	// PushAlert copies the alert, so we can free our copy.
	//
	ExFreePoolWithTag(filterViolationAlert, STACK_VIOLATION_TAG);
}

================================================
FILE: PeaceMaker Kernel/DetectionLogic.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "AlertQueue.h"
#include "StackWalker.h"
#include "shared.h"

typedef class DetectionLogic
{
	PALERT_QUEUE alerts;
	StackWalker resolver;

	VOID PushStackViolationAlert (
		_In_ DETECTION_SOURCE DetectionSource,
		_In_ PVOID ViolatingAddress,
		_In_ HANDLE SourceProcessId,
		_In_ PUNICODE_STRING SourcePath,
		_In_ PUNICODE_STRING TargetPath,
		_In_ STACK_RETURN_INFO StackHistory[],
		_In_ ULONG StackHistorySize
		);

public:
	DetectionLogic();
	~DetectionLogic();

	PALERT_QUEUE GetAlertQueue (
		VOID
		);

	VOID AuditUserStackWalk (
		_In_ DETECTION_SOURCE DetectionSource,
		_In_ HANDLE SourceProcessId,
		_In_ PUNICODE_STRING SourcePath,
		_In_ PUNICODE_STRING TargetPath,
		_In_ STACK_RETURN_INFO StackHistory[],
		_In_ ULONG StackHistorySize
		);

	VOID AuditUserPointer (
		_In_ DETECTION_SOURCE DetectionSource,
		_In_ PVOID UserPtr,
		_In_ HANDLE SourceProcessId,
		_In_ PUNICODE_STRING SourcePath,
		_In_ PUNICODE_STRING TargetPath,
		_In_ STACK_RETURN_INFO StackHistory[],
		_In_ ULONG StackHistorySize
		);

	VOID AuditCallerProcessId (
		_In_ DETECTION_SOURCE DetectionSource,
		_In_ HANDLE CallerProcessId,
		_In_ HANDLE TargetProcessId,
		_In_ PUNICODE_STRING SourcePath,
		_In_ PUNICODE_STRING TargetPath,
		_In_ STACK_RETURN_INFO StackHistory[],
		_In_ ULONG StackHistorySize
		);

	VOID ReportFilterViolation (
		_In_ DETECTION_SOURCE DetectionSource,
		_In_ HANDLE CallerProcessId,
		_In_ PUNICODE_STRING CallerPath,
		_In_ PUNICODE_STRING ViolatingPath,
		_In_ STACK_RETURN_INFO StackHistory[],
		_In_ ULONG StackHistorySize
		);
} DETECTION_LOGIC, *PDETECTION_LOGIC;

#define ALERT_QUEUE_TAG 'qAmP'
#define STACK_VIOLATION_TAG 'vSmP'

================================================
FILE: PeaceMaker Kernel/FSFilter.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "FSFilter.h"

FLT_REGISTRATION FSBlockingFilter::FilterRegistration;
PSTRING_FILTERS FSBlockingFilter::FileStringFilters;
STACK_WALKER FSBlockingFilter::walker;
PDETECTION_LOGIC FSBlockingFilter::detector;

/**
	Initializes the necessary components of the filesystem filter.
	@param DriverObject - The object of the driver necessary for mini-filter initialization.
	@param RegistryPath - The registry path of the driver.
	@param UnloadRoutine - The function to call on the unload of the mini-filter.
	@param Detector - Detection instance used to analyze untrusted operations.
	@param InitializeStatus - Status of initialization.
	@param FilterHandle - The pointer to place the handle for the filter to.
*/
FSBlockingFilter::FSBlockingFilter (
	_In_ PDRIVER_OBJECT DriverObject,
	_In_ PUNICODE_STRING RegistryPath,
	_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,
	_In_ PDETECTION_LOGIC Detector,
	_Out_ NTSTATUS* InitializeStatus,
	_Out_ PFLT_FILTER* FilterHandle
	)
{

	FSBlockingFilter::FileStringFilters = new (PagedPool, STRING_FILE_FILTERS_TAG) StringFilters(FilesystemFilter, RegistryPath, L"FileFilterStore");
	if (FSBlockingFilter::FileStringFilters == NULL)
	{
		DBGPRINT("FSBlockingFilter!FSBlockingFilter: Failed to allocate memory for string filters.");
		*InitializeStatus = STATUS_NO_MEMORY;
		return;
	}
	//
	// Restore existing filters.
	//
	FSBlockingFilter::FileStringFilters->RestoreFilters();

	//
	// This isn't a constant because the unload routine changes.
	//
	FSBlockingFilter::FilterRegistration = {
		sizeof(FLT_REGISTRATION),           //  Size
		FLT_REGISTRATION_VERSION,           //  Version
		0,                                  //  Flags

		NULL,                               //  Context
		Callbacks,                          //  Operation callbacks
		UnloadRoutine,

		FSBlockingFilter::HandleInstanceSetup,
		FSBlockingFilter::HandleInstanceQueryTeardown,
		FSBlockingFilter::HandleInstanceTeardownStart,
		FSBlockingFilter::HandleInstanceTeardownComplete,

		NULL,                               //  GenerateFileName
		NULL,                               //  GenerateDestinationFileName
		NULL                                //  NormalizeNameComponent
	};

	//
	//  Register with FltMgr to tell it our callback routines.
	//
	*InitializeStatus = FltRegisterFilter(DriverObject, &FilterRegistration, FilterHandle);

	FLT_ASSERT(NT_SUCCESS(*InitializeStatus));

	//
	// Start filtering.
	//
	*InitializeStatus = FltStartFiltering(*FilterHandle);

	//
	// If we can't start filtering, unregister the filter.
	//
	if (NT_SUCCESS(*InitializeStatus) == FALSE) {

		FltUnregisterFilter(*FilterHandle);
	}

	//
	// Set the detector.
	//
	FSBlockingFilter::detector = Detector;
}

/**
	Free data members that were dynamically allocated.
*/
FSBlockingFilter::~FSBlockingFilter()
{
	DBGPRINT("FSBlockingFilter!~FSBlockingFilter: Deconstructing class.");
	//
	// Make sure to deconstruct the class.
	//
	if (FSBlockingFilter::FileStringFilters)
	{
		FSBlockingFilter::FileStringFilters->~StringFilters();
		ExFreePoolWithTag(FSBlockingFilter::FileStringFilters, STRING_FILE_FILTERS_TAG);
		FSBlockingFilter::FileStringFilters = NULL;
	}
}

/**
	Get the pointer to the filters used by this filesystem filter. Useful if you want to add/remove filters.
*/
PSTRING_FILTERS FSBlockingFilter::GetStringFilters()
{
	return FSBlockingFilter::FileStringFilters;
}

/**
	This function is called prior to a create operation.
	Data - The data associated with the current operation.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	CompletionContext - Optional context to be passed to post operation callbacks.
*/
FLT_PREOP_CALLBACK_STATUS
FSBlockingFilter::HandlePreCreateOperation(
	_Inout_ PFLT_CALLBACK_DATA Data,
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
	)
{
	FLT_PREOP_CALLBACK_STATUS callbackStatus;
	PFLT_FILE_NAME_INFORMATION fileNameInfo;

	PUNICODE_STRING callerProcessPath;
	PSTACK_RETURN_INFO fileOperationStack;
	ULONG fileOperationStackSize;
	BOOLEAN reportOperation;

	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(CompletionContext);

	reportOperation = FALSE;
	fileOperationStackSize = MAX_STACK_RETURN_HISTORY;
	fileNameInfo = NULL;
	callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;

	//
	// PeaceMaker is not designed to block kernel operations.
	//
	if (ExGetPreviousMode() == KernelMode)
	{
		return callbackStatus;
	}

	if (FlagOn(Data->Iopb->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))
	{
		if (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))
		{
			if (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_DELETE) != FALSE)
			{
				DBGPRINT("FSBlockingFilter!HandlePreCreateOperation: Detected FILE_DELETE_ON_CLOSE of %wZ. Prevented deletion!", fileNameInfo->Name);

				Data->Iopb->TargetFileObject->DeletePending = FALSE;
				Data->IoStatus.Information = 0;
				Data->IoStatus.Status = STATUS_ACCESS_DENIED;
				callbackStatus = FLT_PREOP_COMPLETE;
				reportOperation = TRUE;
			}
		}
	}
	
	if (Data->Iopb->Parameters.Create.SecurityContext && FlagOn(Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess, FILE_EXECUTE))
	{
		if (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))
		{
			if (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_EXECUTE) != FALSE)
			{
				DBGPRINT("FSBlockingFilter!HandlePreCreateOperation: Detected FILE_EXECUTE desired access of %wZ. Prevented execute access!", fileNameInfo->Name);
				Data->Iopb->TargetFileObject->DeletePending = FALSE;
				Data->IoStatus.Information = 0;
				Data->IoStatus.Status = STATUS_ACCESS_DENIED;
				callbackStatus = FLT_PREOP_COMPLETE;
				reportOperation = TRUE;
			}
		}
	}

	if (reportOperation)
	{
		//
		// Grab the caller's path.
		//
		ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);

		//
		// Walk the stack.
		//
		FSBlockingFilter::walker.WalkAndResolveStack(&fileOperationStack, &fileOperationStackSize, STACK_HISTORY_TAG);

		NT_ASSERT(fileOperationStack);

		//
		// Only if we successfully walked the stack, report the violation.
		//
		if (fileOperationStack != NULL && fileOperationStackSize != 0)
		{
			//
			// Report the violation.
			//
			FSBlockingFilter::detector->ReportFilterViolation(FileFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &fileNameInfo->Name, fileOperationStack, fileOperationStackSize);

			//
			// Clean up.
			//
			ExFreePoolWithTag(fileOperationStack, STACK_HISTORY_TAG);
		}

		ExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);
	}

	if (fileNameInfo)
	{
		FltReleaseFileNameInformation(fileNameInfo);
	}

    return callbackStatus;
}

/**
	This function is called prior to a write operation.
	Data - The data associated with the current operation.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	CompletionContext - Optional context to be passed to post operation callbacks.
*/
FLT_PREOP_CALLBACK_STATUS
FSBlockingFilter::HandlePreWriteOperation(
	_Inout_ PFLT_CALLBACK_DATA Data,
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
	)
{
	FLT_PREOP_CALLBACK_STATUS callbackStatus;
	PFLT_FILE_NAME_INFORMATION fileNameInfo;

	PUNICODE_STRING callerProcessPath;
	PSTACK_RETURN_INFO fileOperationStack;
	ULONG fileOperationStackSize;
	BOOLEAN reportOperation;

	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(CompletionContext);

	reportOperation = FALSE;
	fileOperationStackSize = MAX_STACK_RETURN_HISTORY;
	fileNameInfo = NULL;
	callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;

	//
	// PeaceMaker is not designed to block kernel operations.
	//
	if (ExGetPreviousMode() == KernelMode)
	{
		return callbackStatus;
	}

	if (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))
	{
		if (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_WRITE) != FALSE)
		{
			DBGPRINT("FSBlockingFilter!HandlePreWriteOperation: Detected write on %wZ. Prevented write!", fileNameInfo->Name);
			Data->Iopb->TargetFileObject->DeletePending = FALSE;
			Data->IoStatus.Information = 0;
			Data->IoStatus.Status = STATUS_ACCESS_DENIED;
			callbackStatus = FLT_PREOP_COMPLETE;
			reportOperation = TRUE;
		}
	}

	if (reportOperation)
	{
		//
		// Grab the caller's path.
		//
		ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);

		//
		// Walk the stack.
		//
		FSBlockingFilter::walker.WalkAndResolveStack(&fileOperationStack, &fileOperationStackSize, STACK_HISTORY_TAG);

		NT_ASSERT(fileOperationStack);

		//
		// Only if we successfully walked the stack, report the violation.
		//
		if (fileOperationStack != NULL && fileOperationStackSize != 0)
		{
			//
			// Report the violation.
			//
			FSBlockingFilter::detector->ReportFilterViolation(FileFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &fileNameInfo->Name, fileOperationStack, fileOperationStackSize);

			//
			// Clean up.
			//
			ExFreePoolWithTag(fileOperationStack, STACK_HISTORY_TAG);
		}

		ExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);
	}

	if (fileNameInfo)
	{
		FltReleaseFileNameInformation(fileNameInfo);
	}

	return callbackStatus;
}

/**
	This function is called prior to a set information operation.
	Data - The data associated with the current operation.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	CompletionContext - Optional context to be passed to post operation callbacks.
*/
FLT_PREOP_CALLBACK_STATUS
FSBlockingFilter::HandlePreSetInfoOperation(
	_Inout_ PFLT_CALLBACK_DATA Data,
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
	)
{
	FLT_PREOP_CALLBACK_STATUS callbackStatus;
	PFLT_FILE_NAME_INFORMATION fileNameInfo;

	PUNICODE_STRING callerProcessPath;
	PSTACK_RETURN_INFO fileOperationStack;
	ULONG fileOperationStackSize;
	BOOLEAN reportOperation;

	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(CompletionContext);

	reportOperation = FALSE;
	fileOperationStackSize = MAX_STACK_RETURN_HISTORY;
	fileNameInfo = NULL;
	callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;

	//
	// PeaceMaker is not designed to block kernel operations.
	//
	if (ExGetPreviousMode() == KernelMode)
	{
		return callbackStatus;
	}

	switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass) {
	case FileDispositionInformation:
	case FileDispositionInformationEx:
		if (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))
		{
			if (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_DELETE) != FALSE)
			{
				DBGPRINT("FSBlockingFilter!HandlePreSetInfoOperation: Detected attempted file deletion of %wZ. Prevented deletion!", fileNameInfo->Name);
				Data->IoStatus.Information = 0;
				Data->IoStatus.Status = STATUS_ACCESS_DENIED;
				callbackStatus = FLT_PREOP_COMPLETE;
				reportOperation = TRUE;
			}
		}
		break;
	}

	if (reportOperation)
	{
		//
		// Grab the caller's path.
		//
		ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);

		//
		// Walk the stack.
		//
		FSBlockingFilter::walker.WalkAndResolveStack(&fileOperationStack, &fileOperationStackSize, STACK_HISTORY_TAG);

		NT_ASSERT(fileOperationStack);

		//
		// Only if we successfully walked the stack, report the violation.
		//
		if (fileOperationStack != NULL && fileOperationStackSize != 0)
		{
			//
			// Report the violation.
			//
			FSBlockingFilter::detector->ReportFilterViolation(FileFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &fileNameInfo->Name, fileOperationStack, fileOperationStackSize);

			//
			// Clean up.
			//
			ExFreePoolWithTag(fileOperationStack, STACK_HISTORY_TAG);
		}

		ExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);
	}

	if (fileNameInfo)
	{
		FltReleaseFileNameInformation(fileNameInfo);
	}

	return callbackStatus;
}

/**
	This function determines whether or not the mini-filter should attach to the volume.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	Flags - Flags that indicate the reason for the volume attach request.
	VolumeDeviceType - The device type of the specified volume.
	VolumeFilesystemType - The filesystem type of the specified volume.
*/
NTSTATUS
FSBlockingFilter::HandleInstanceSetup(
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_In_ FLT_INSTANCE_SETUP_FLAGS Flags,
	_In_ DEVICE_TYPE VolumeDeviceType,
	_In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
	)
{
	NTSTATUS status = STATUS_SUCCESS;
	BOOLEAN isWritable = FALSE;

	UNREFERENCED_PARAMETER(Flags);
	UNREFERENCED_PARAMETER(VolumeDeviceType);

	status = FltIsVolumeWritable(FltObjects->Volume,
		&isWritable);

	if (!NT_SUCCESS(status)) {

		return STATUS_FLT_DO_NOT_ATTACH;
	}

	//
	// If you can't write to a volume... how can you delete a file in it?
	//
	if (isWritable) {

		switch (VolumeFilesystemType) {

		case FLT_FSTYPE_NTFS:
		case FLT_FSTYPE_REFS:

			status = STATUS_SUCCESS;
			break;

		default:

			return STATUS_FLT_DO_NOT_ATTACH;
		}

	}
	else {

		return STATUS_FLT_DO_NOT_ATTACH;
	}

	return status;
}


/**
	This function is called when an instance is being deleted.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	Flags - Flags that indicate the reason for the detach request.
*/
NTSTATUS
FSBlockingFilter::HandleInstanceQueryTeardown(
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
	)
{
	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(Flags);

	return STATUS_SUCCESS;
}

/**
	This function is called at the start of an instance teardown.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	Flags - Flags that indicate the reason for the deletion.
*/
VOID
FSBlockingFilter::HandleInstanceTeardownStart(
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
	)
{
	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(Flags);
}

/**
	This function is called at the end of an instance teardown.
	FltObjects - Objects related to the filter, instance, and its associated volume.
	Flags - Flags that indicate the reason for the deletion.
*/
VOID
FSBlockingFilter::HandleInstanceTeardownComplete(
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
	)
{
	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(Flags);
}

================================================
FILE: PeaceMaker Kernel/FSFilter.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "StringFilters.h"
#include "StackWalker.h"
#include "ImageHistoryFilter.h"

typedef class FSBlockingFilter
{
	static FLT_PREOP_CALLBACK_STATUS
	HandlePreCreateOperation (
		_Inout_ PFLT_CALLBACK_DATA Data,
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
		);

	static FLT_PREOP_CALLBACK_STATUS
	HandlePreWriteOperation (
		_Inout_ PFLT_CALLBACK_DATA Data,
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
		);

	static FLT_PREOP_CALLBACK_STATUS
	HandlePreSetInfoOperation (
		_Inout_ PFLT_CALLBACK_DATA Data,
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
		);

	static NTSTATUS
	HandleInstanceSetup (
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_In_ FLT_INSTANCE_SETUP_FLAGS Flags,
		_In_ DEVICE_TYPE VolumeDeviceType,
		_In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
		);

	static NTSTATUS
	HandleInstanceQueryTeardown (
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
		);

	static VOID
	HandleInstanceTeardownStart (
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
		);

	static VOID
	HandleInstanceTeardownComplete (
		_In_ PCFLT_RELATED_OBJECTS FltObjects,
		_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
		);

	//
	// Class callbacks for necessary filesystem operations.
	//
	static constexpr FLT_OPERATION_REGISTRATION Callbacks[] = {

		{ IRP_MJ_CREATE,
		  0,
		  FSBlockingFilter::HandlePreCreateOperation,
		  NULL },

		{ IRP_MJ_WRITE,
		  0,
		  FSBlockingFilter::HandlePreWriteOperation,
		  NULL },

		{ IRP_MJ_SET_INFORMATION,
		  FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,
		  FSBlockingFilter::HandlePreSetInfoOperation,
		  NULL },

		{ IRP_MJ_OPERATION_END }
	};

	//
	// The registration context for the mini-filter.
	//
	static FLT_REGISTRATION FilterRegistration;

	//
	// Contains strings to block various filesystem operations.
	//
	static PSTRING_FILTERS FileStringFilters;

	static STACK_WALKER walker;
	static PDETECTION_LOGIC detector;
public:
	FSBlockingFilter (
		_In_ PDRIVER_OBJECT DriverObject,
		_In_ PUNICODE_STRING RegistryPath,
		_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,
		_In_ PDETECTION_LOGIC Detector,
		_Out_ NTSTATUS* InitializeStatus,
		_Out_ PFLT_FILTER* FilterHandle
		);
	~FSBlockingFilter();

	static PSTRING_FILTERS GetStringFilters();
	
} FS_BLOCKING_FILTER, *PFS_BLOCKING_FILTER;

#define STRING_FILE_FILTERS_TAG 'fFmP'

================================================
FILE: PeaceMaker Kernel/FilterTesting.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "common.h"
#include "IOCTLCommunication.h"

PIOCTL_COMMUNICATION Communicator;

#pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")

/*************************************************************************
    Prototypes
*************************************************************************/

EXTERN_C_START

DRIVER_INITIALIZE DriverEntry;
NTSTATUS
DriverEntry (
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
    );

NTSTATUS
FilterUnload(
    _In_ FLT_FILTER_UNLOAD_FLAGS Flags
    );

EXTERN_C_END

//
//  Assign text sections for each routine.
//

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, FilterUnload)
#endif

/*************************************************************************
    MiniFilter initialization and unload routines.
*************************************************************************/

/**
	Initialize the mini-filter driver.
	DriverObject - The driver's object.
	RegistryPath - The path to the driver's registry entry.
*/
NTSTATUS
DriverEntry (
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS status;

	status = STATUS_SUCCESS;

	DBGPRINT("FilterTesting!DriverEntry: Hello world.");

	Communicator = new (NonPagedPool, 'cImP') IOCTLCommunication(DriverObject, RegistryPath, NULL, &status);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("FilterTesting!DriverEntry: Failed to initialize communication with status 0x%X.", status);
	}

    return status;
}

/**
	This function handles unloading the mini-filter.
	@param Flags - Flags indicating whether or not this is a mandatory unload.
*/
NTSTATUS
FilterUnload (
    _In_ FLT_FILTER_UNLOAD_FLAGS Flags
    )
{
    UNREFERENCED_PARAMETER( Flags );

    PAGED_CODE();

	DBGPRINT("FilterTesting!FilterUnload: Unloading filter.");

	Communicator->~IOCTLCommunication();
	ExFreePoolWithTag(Communicator, 'cImP');

    return STATUS_SUCCESS;
}

================================================
FILE: PeaceMaker Kernel/IOCTLCommunication.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "IOCTLCommunication.h"

PDRIVER_OBJECT IOCTLCommunication::DriverObject;
PDETECTION_LOGIC IOCTLCommunication::Detector;
PIMAGE_HISTORY_FILTER IOCTLCommunication::ImageProcessFilter;
PFLT_FILTER IOCTLCommunication::FileFilterHandle;
PFS_BLOCKING_FILTER IOCTLCommunication::FilesystemMonitor;
PREGISTRY_BLOCKING_FILTER IOCTLCommunication::RegistryMonitor;
PTHREAD_FILTER IOCTLCommunication::ThreadOperationFilter;
PTAMPER_GUARD IOCTLCommunication::TamperGuardFilter;

/**
	Construct the IOCTLCommunication class by initializing the driver object and detector.
	@param DriverObject - The driver's object.
	@param RegistryPath - The registry path of the driver.
	@param UnloadRoutine - The routine to call when the filter is unloading.
	@param InitializeStatus - Status of initialization.
*/
IOCTLCommunication::IOCTLCommunication (
	_In_ PDRIVER_OBJECT Driver,
	_In_ PUNICODE_STRING RegistryPath,
	_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,
	_Inout_ NTSTATUS* InitializeStatus
	)
{
	this->DriverObject = Driver;

	*InitializeStatus = STATUS_SUCCESS;

	//
	// Initialize the class members.
	//
	this->Detector = new (NonPagedPool, DETECTION_LOGIC_TAG) DetectionLogic();
	if (this->Detector == NULL)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to allocate space for detection logic.");
		*InitializeStatus = STATUS_NO_MEMORY;
		return;
	}

	this->ImageProcessFilter = new (NonPagedPool, IMAGE_HISTORY_FILTER_TAG) ImageHistoryFilter(this->Detector, InitializeStatus);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to initialize image process history filter with status 0x%X.", *InitializeStatus);
		return;
	}
	if (this->ImageProcessFilter == NULL)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to allocate space for image process history filter.");
		*InitializeStatus = STATUS_NO_MEMORY;
		return;
	}

	FilesystemMonitor = new (NonPagedPool, FILE_MONITOR_TAG) FSBlockingFilter(DriverObject, RegistryPath, UnloadRoutine, this->Detector, InitializeStatus, &FileFilterHandle);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to initialize the filesystem blocking filter with status 0x%X.", *InitializeStatus);
		return;
	}

	RegistryMonitor = new (NonPagedPool, REGISTRY_MONITOR_TAG) RegistryBlockingFilter(DriverObject, RegistryPath, this->Detector, InitializeStatus);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to initialize the registry blocking filter with status 0x%X.", *InitializeStatus);
		return;
	}

	this->ThreadOperationFilter = new (NonPagedPool, THREAD_FILTER_TAG) ThreadFilter(this->Detector, InitializeStatus);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to initialize thread operation filters with status 0x%X.", *InitializeStatus);
		return;
	}
	if (this->ThreadOperationFilter == NULL)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to allocate space for thread operation filters.");
		*InitializeStatus = STATUS_NO_MEMORY;
		return;
	}

	this->TamperGuardFilter = new (NonPagedPool, TAMPER_GUARD_TAG) TamperGuard(InitializeStatus);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!IOCTLCommunication: Failed to initialize tamper guard with status 0x%X.", *InitializeStatus);
		return;
	}

	InitializeDriverIOCTL();
}

/**
	Deconstruct the IOCTLCommunication class.
*/
IOCTLCommunication::~IOCTLCommunication	(
	VOID
	)
{
	this->Detector->~DetectionLogic();
	ExFreePoolWithTag(this->Detector, DETECTION_LOGIC_TAG);

	this->ImageProcessFilter->~ImageHistoryFilter();
	ExFreePoolWithTag(this->ImageProcessFilter, IMAGE_HISTORY_FILTER_TAG);

	FltUnregisterFilter(FileFilterHandle);

	this->FilesystemMonitor->~FSBlockingFilter();
	ExFreePoolWithTag(this->FilesystemMonitor, FILE_MONITOR_TAG);

	this->RegistryMonitor->~RegistryBlockingFilter();
	ExFreePoolWithTag(this->RegistryMonitor, REGISTRY_MONITOR_TAG);

	this->ThreadOperationFilter->~ThreadFilter();
	ExFreePoolWithTag(this->ThreadOperationFilter, THREAD_FILTER_TAG);

	this->TamperGuardFilter->~TamperGuard();
	ExFreePoolWithTag(this->TamperGuardFilter, TAMPER_GUARD_TAG);

	UninitializeDriverIOCTL();
}

/**
	Handle basic create / close of device, always return success with no change.
	@param DeviceObject - The driver's device object.
	@param Irp - The current IRP.
*/
NTSTATUS
IOCTLCommunication::IOCTLCreateClose (
	_In_ PDEVICE_OBJECT DeviceObject,
	_In_ PIRP Irp
	)
{
	UNREFERENCED_PARAMETER(DeviceObject);

	//
	// Just accept everyone for now.
	// TODO: Implement some sort of authentication?
	//
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return STATUS_SUCCESS;
}

/**
	Handle IO controls for communication with the PeaceMaker user-mode interface.
	@param DeviceObject - The driver's device object.
	@param Irp - The current IRP.
*/
NTSTATUS
IOCTLCommunication::IOCTLDeviceControl (
	_In_ PDEVICE_OBJECT DeviceObject,
	_In_ PIRP Irp
	)
{
	NTSTATUS status;
	PIO_STACK_LOCATION irpStackLocation;
	ULONG ioctlCode;
	ULONG inputLength;
	ULONG outputLength;
	ULONG minimumLength;
	ULONG writtenLength;

	PBASE_ALERT_INFO poppedAlert;
	PPROCESS_SUMMARY_REQUEST processSummaryRequest;
	PPROCESS_DETAILED_REQUEST processDetailedRequest;
	PSTRING_FILTER_REQUEST filterAddRequest;
	PLIST_FILTERS_REQUEST listFiltersRequest;
	PIMAGE_DETAILED_REQUEST imageDetailedRequest;
	PDELETE_FILTER_REQUEST deleteFilterRequest;
	PGLOBAL_SIZES globalSizes;

	WCHAR temporaryFilterBuffer[MAX_PATH];

	UNREFERENCED_PARAMETER(DeviceObject);

	status = STATUS_SUCCESS;
	irpStackLocation = IoGetCurrentIrpStackLocation(Irp);

	//
	// Grab basic information about the request.
	//
	ioctlCode = irpStackLocation->Parameters.DeviceIoControl.IoControlCode;
	inputLength = irpStackLocation->Parameters.DeviceIoControl.InputBufferLength;
	outputLength = irpStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
	writtenLength = 0;
	
	//
	// Update the tamper guard.
	//
	IOCTLCommunication::TamperGuardFilter->UpdateProtectedProcess(PsGetCurrentProcessId());

	DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: ioctlCode = 0x%X, inputLength = 0x%X, outputLength = 0x%X", ioctlCode, inputLength, outputLength);

	//
	// Handle the different IOCTL request types.
	//
	switch (ioctlCode)
	{
	case IOCTL_ALERTS_QUEUED:
		if (outputLength >= sizeof(BOOLEAN))
		{
			//
			// Return the status of the Queue.
			//
			*RCAST<BOOLEAN*>(Irp->AssociatedIrp.SystemBuffer) = !IOCTLCommunication::Detector->GetAlertQueue()->IsQueueEmpty();
			writtenLength = sizeof(BOOLEAN);
		}
		break;
	case IOCTL_POP_ALERT:
		if (outputLength < MAX_STACK_VIOLATION_ALERT_SIZE)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_POP_ALERT but output buffer with size 0x%X smaller then minimum 0x%X.", outputLength, MAX_STACK_VIOLATION_ALERT_SIZE);
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}
		//
		// Pop an alert from the queue.
		//
		poppedAlert = IOCTLCommunication::Detector->GetAlertQueue()->PopAlert();
		if (poppedAlert == NULL)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_POP_ALERT but no alert to pop.");
			status = STATUS_NOT_FOUND;
			goto Exit;
		}

		DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Got alert 0x%llx for IOCTL_POP_ALERT with size 0x%llx.\n", poppedAlert, poppedAlert->AlertSize);

		//
		// Copy the alert.
		//
		memcpy_s(Irp->AssociatedIrp.SystemBuffer, outputLength, poppedAlert, poppedAlert->AlertSize);

		writtenLength = poppedAlert->AlertSize;

		//
		// Free the alert entry.
		//
		IOCTLCommunication::Detector->GetAlertQueue()->FreeAlert(poppedAlert);
		break;
	case IOCTL_GET_PROCESSES:
		if (inputLength < sizeof(PROCESS_SUMMARY_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESSES but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		//
		// Verify the specified array size.
		//
		processSummaryRequest = RCAST<PPROCESS_SUMMARY_REQUEST>(Irp->AssociatedIrp.SystemBuffer);
		if (processSummaryRequest->ProcessHistorySize <= 0 || outputLength < MAX_PROCESS_SUMMARY_REQUEST_SIZE(processSummaryRequest))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESSES but output buffer with size 0x%X smaller then minimum 0x%X.", outputLength, MAX_PROCESS_SUMMARY_REQUEST_SIZE(processSummaryRequest));
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		//
		// Grab the history summaries.
		//
		processSummaryRequest->ProcessHistorySize = IOCTLCommunication::ImageProcessFilter->GetProcessHistorySummary(processSummaryRequest->SkipCount, RCAST<PPROCESS_SUMMARY_ENTRY>(&processSummaryRequest->ProcessHistory[0]), processSummaryRequest->ProcessHistorySize);
		writtenLength = MAX_PROCESS_SUMMARY_REQUEST_SIZE(processSummaryRequest);

		DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: IOCTL_GET_PROCESSES found %i processes.", processSummaryRequest->ProcessHistorySize);
		break;
	case IOCTL_GET_PROCESS_DETAILED:
		if (inputLength < sizeof(PROCESS_DETAILED_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_DETAILED but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		processDetailedRequest = RCAST<PPROCESS_DETAILED_REQUEST>(Irp->AssociatedIrp.SystemBuffer);

		minimumLength = sizeof(PROCESS_DETAILED_REQUEST);
		//
		// Verify the specified array size.
		//
		if (outputLength < minimumLength)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_DETAILED but output buffer with size 0x%X smaller then minimum 0x%X.", outputLength, minimumLength);
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		//
		// Verify the user buffers.
		//
		__try
		{
			ProbeForWrite(processDetailedRequest->ImageSummary, processDetailedRequest->ImageSummarySize * sizeof(IMAGE_SUMMARY), sizeof(ULONG));
			ProbeForWrite(processDetailedRequest->StackHistory, processDetailedRequest->StackHistorySize * sizeof(STACK_RETURN_INFO), sizeof(ULONG));
		}
		__except (1)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_DETAILED but user buffers were invalid.");
			status = STATUS_BAD_DATA;
			goto Exit;
		}
		
		//
		// Populate the detailed request.
		//
		IOCTLCommunication::ImageProcessFilter->PopulateProcessDetailedRequest(processDetailedRequest);
		writtenLength = minimumLength;
		break;
	case IOCTL_ADD_FILTER:
		//
		// Validate the size of the input and output buffers.
		//
		if (inputLength < sizeof(STRING_FILTER_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_ADD_FILTER but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}
		if (outputLength < sizeof(STRING_FILTER_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_ADD_FILTER but output buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		filterAddRequest = RCAST<PSTRING_FILTER_REQUEST>(Irp->AssociatedIrp.SystemBuffer);

		//
		// Copy the filter content to a temporary string (ensures null-terminator).
		//
		status = RtlStringCchCopyNW(temporaryFilterBuffer, MAX_PATH, filterAddRequest->Filter.MatchString, MAX_PATH);
		if (NT_SUCCESS(status) == FALSE)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Failed to copy filter content to temporary buffer with status 0x%X.", status);
			goto Exit;
		}

		//
		// Sanity check.
		//
		if (wcsnlen_s(temporaryFilterBuffer, MAX_PATH) == 0)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Blocked empty filter.");
			goto Exit;
		}
		
		//
		// Depending on the type of filter, add the string.
		//
		switch (filterAddRequest->FilterType)
		{
		case FilesystemFilter:
			filterAddRequest->Filter.Id = FilesystemMonitor->GetStringFilters()->AddFilter(temporaryFilterBuffer, filterAddRequest->Filter.Flags);
			break;
		case RegistryFilter:
			filterAddRequest->Filter.Id = RegistryMonitor->GetStringFilters()->AddFilter(temporaryFilterBuffer, filterAddRequest->Filter.Flags);
			break;
		}
		writtenLength = sizeof(STRING_FILTER_REQUEST);
		break;
	case IOCTL_LIST_FILTERS:
		//
		// Validate the size of the input and output buffers.
		//
		if (inputLength < sizeof(LIST_FILTERS_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_LIST_FILTERS but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}
		if (outputLength < sizeof(LIST_FILTERS_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_LIST_FILTERS but output buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		listFiltersRequest = RCAST<PLIST_FILTERS_REQUEST>(Irp->AssociatedIrp.SystemBuffer);
		switch (listFiltersRequest->FilterType)
		{
		case FilesystemFilter:
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Retrieving filesystem filters.");
			listFiltersRequest->CopiedFilters = FilesystemMonitor->GetStringFilters()->GetFilters(listFiltersRequest->SkipFilters, RCAST<PFILTER_INFO>(&listFiltersRequest->Filters), 10);
			break;
		case RegistryFilter:
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Retrieving registry filters.");
			listFiltersRequest->CopiedFilters = RegistryMonitor->GetStringFilters()->GetFilters(listFiltersRequest->SkipFilters, RCAST<PFILTER_INFO>(&listFiltersRequest->Filters), 10);
			break;
		}
		writtenLength = sizeof(LIST_FILTERS_REQUEST);
		break;
	case IOCTL_GET_PROCESS_SIZES:
		//
		// Validate the size of the input and output buffers.
		//
		if (inputLength < sizeof(PROCESS_SIZES_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_SIZES but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}
		if (outputLength < sizeof(PROCESS_SIZES_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_SIZES but output buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		IOCTLCommunication::ImageProcessFilter->PopulateProcessSizes(RCAST<PPROCESS_SIZES_REQUEST>(Irp->AssociatedIrp.SystemBuffer));
		writtenLength = sizeof(PROCESS_SIZES_REQUEST);
		break;
	case IOCTL_GET_IMAGE_DETAILED:
		//
		// Validate the size of the input and output buffers.
		//
		if (inputLength < sizeof(IMAGE_DETAILED_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_IMAGE_DETAILED but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		imageDetailedRequest = RCAST<PIMAGE_DETAILED_REQUEST>(Irp->AssociatedIrp.SystemBuffer);
		minimumLength = MAX_IMAGE_DETAILED_REQUEST_SIZE(imageDetailedRequest);
		DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: IOCTL_GET_IMAGE_DETAILED minimumLength = 0x%X.", minimumLength);

		if (inputLength < minimumLength)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_IMAGE_DETAILED but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}
		if (outputLength < minimumLength)
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_IMAGE_DETAILED but output buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}
		IOCTLCommunication::ImageProcessFilter->PopulateImageDetailedRequest(imageDetailedRequest);
		writtenLength = MAX_IMAGE_DETAILED_REQUEST_SIZE(imageDetailedRequest);
		break;
	case IOCTL_GET_GLOBAL_SIZES:
		//
		// Validate the size of the output buffer.
		//
		if (outputLength < sizeof(GLOBAL_SIZES))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_GLOBAL_SIZES but output buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		globalSizes = RCAST<PGLOBAL_SIZES>(Irp->AssociatedIrp.SystemBuffer);
		globalSizes->ProcessHistorySize = ImageHistoryFilter::ProcessHistorySize;
		globalSizes->FilesystemFilterSize = FilesystemMonitor->GetStringFilters()->filtersCount;
		globalSizes->RegistryFilterSize = RegistryMonitor->GetStringFilters()->filtersCount;
		writtenLength = sizeof(GLOBAL_SIZES);
		break;
	case IOCTL_DELETE_FILTER:
		//
		// Validate the size of the input buffer.
		//
		if (inputLength < sizeof(DELETE_FILTER_REQUEST))
		{
			DBGPRINT("IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_DELETE_FILTER but input buffer is too small.");
			status = STATUS_INSUFFICIENT_RESOURCES;
			goto Exit;
		}

		deleteFilterRequest = RCAST<PDELETE_FILTER_REQUEST>(Irp->AssociatedIrp.SystemBuffer);
		switch (deleteFilterRequest->FilterType)
		{
		case FilesystemFilter:
			deleteFilterRequest->Deleted = FilesystemMonitor->GetStringFilters()->RemoveFilter(deleteFilterRequest->FilterId);
			break;
		case RegistryFilter:
			deleteFilterRequest->Deleted = RegistryMonitor->GetStringFilters()->RemoveFilter(deleteFilterRequest->FilterId);
			break;
		}
		writtenLength = sizeof(DELETE_FILTER_REQUEST);
		break;
	}

Exit:
	Irp->IoStatus.Status = status;
	Irp->IoStatus.Information = writtenLength;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return status;
}

/**
	Initialize the driver object to support IOCTL communication.
*/
NTSTATUS
IOCTLCommunication::InitializeDriverIOCTL (
	VOID
	)
{
	NTSTATUS status;
	UNICODE_STRING ioctlDeviceName;
	UNICODE_STRING ioctlDosDevicesName;
	PDEVICE_OBJECT ioctlDevice;

	RtlInitUnicodeString(&ioctlDeviceName, NT_DEVICE_NAME);

	//
	// Create IO Device Object.
	// TODO: Implement secure device creation (with secure DACL).
	//
	status = IoCreateDevice(DriverObject, NULL, &ioctlDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, TRUE, &ioctlDevice);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!InitializeDriverIOCTL: Failed to create kernel device object with error 0x%X.", status);
		goto Exit;
	}

	//
	// Set the handlers for our IOCTL.
	//
	DriverObject->MajorFunction[IRP_MJ_CREATE] = IOCTLCreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = IOCTLCreateClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOCTLDeviceControl;

	RtlInitUnicodeString(&ioctlDosDevicesName, DOS_DEVICE_NAME);

	status = IoCreateSymbolicLink(&ioctlDosDevicesName, &ioctlDeviceName);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("IOCTLCommunication!InitializeDriverIOCTL: Failed to create symbolic link to device with error 0x%X.", status);
		IoDeleteDevice(ioctlDevice);
		goto Exit;
	}
Exit:
	return status;
}

/**
	Undo everything done in InitializeDriverObject.
	@return The status of uninitialization.
*/
VOID
IOCTLCommunication::UninitializeDriverIOCTL (
	VOID
	)
{
	PDEVICE_OBJECT deviceObject;
	UNICODE_STRING ioctlDosDevicesName;

	deviceObject = DriverObject->DeviceObject;

	//
	// Initialize the unicode string of our DosDevices symlink.
	//
	RtlInitUnicodeString(&ioctlDosDevicesName, DOS_DEVICE_NAME);

	//
	// Delete IOCTL symlink because we're unloading.
	//
	IoDeleteSymbolicLink(&ioctlDosDevicesName);
	if (deviceObject != NULL)
	{
		//
		// Delete the device while unloading.
		//
		IoDeleteDevice(deviceObject);
	}
}

================================================
FILE: PeaceMaker Kernel/IOCTLCommunication.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "DetectionLogic.h"
#include "ImageHistoryFilter.h"
#include "ThreadFilter.h"
#include "FSFilter.h"
#include "RegistryFilter.h"
#include "TamperGuard.h"

typedef class IOCTLCommunication
{
	static PDRIVER_OBJECT DriverObject;
	static PDETECTION_LOGIC Detector;
	static PIMAGE_HISTORY_FILTER ImageProcessFilter;
	static PFLT_FILTER FileFilterHandle;
	static PFS_BLOCKING_FILTER FilesystemMonitor;
	static PREGISTRY_BLOCKING_FILTER RegistryMonitor;
	static PTHREAD_FILTER ThreadOperationFilter;
	static PTAMPER_GUARD TamperGuardFilter;

	NTSTATUS InitializeDriverIOCTL(VOID);
	VOID UninitializeDriverIOCTL(VOID);

	static NTSTATUS IOCTLCreateClose(
		_In_ PDEVICE_OBJECT DeviceObject,
		_In_ PIRP Irp
		);
	static NTSTATUS IOCTLDeviceControl(
		_In_ PDEVICE_OBJECT DeviceObject,
		_In_ PIRP Irp
		);

public:
	IOCTLCommunication(
		_In_ PDRIVER_OBJECT Driver,
		_In_ PUNICODE_STRING RegistryPath,
		_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,
		_Inout_ NTSTATUS* InitializeStatus
		);
	~IOCTLCommunication(VOID);
} IOCTL_COMMUNICATION, *PIOCTL_COMMUNICATION;

#define DETECTION_LOGIC_TAG 'lDmP'
#define IMAGE_HISTORY_FILTER_TAG 'fImP'
#define FILE_MONITOR_TAG 'mFmP'
#define REGISTRY_MONITOR_TAG 'mRmP'
#define THREAD_FILTER_TAG 'fTmP'
#define TAMPER_GUARD_TAG 'gTmP'

================================================
FILE: PeaceMaker Kernel/ImageHistoryFilter.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "ImageHistoryFilter.h"

StackWalker ImageHistoryFilter::walker;
PPROCESS_HISTORY_ENTRY ImageHistoryFilter::ProcessHistoryHead;
EX_PUSH_LOCK ImageHistoryFilter::ProcessHistoryLock;
BOOLEAN ImageHistoryFilter::destroying;
ULONG64 ImageHistoryFilter::ProcessHistorySize;
PDETECTION_LOGIC ImageHistoryFilter::detector;

/**
	Register the necessary notify routines.
	@param Detector - Detection instance used to analyze untrusted operations.
	@param InitializeStatus - Status of initialization.
*/
ImageHistoryFilter::ImageHistoryFilter (
	_In_ PDETECTION_LOGIC Detector,
	_Out_ NTSTATUS* InitializeStatus
	)
{
	//
	// Set the create process notify routine.
	//
	*InitializeStatus = PsSetCreateProcessNotifyRoutineEx(ImageHistoryFilter::CreateProcessNotifyRoutine, FALSE);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("ImageHistoryFilter!ImageHistoryFilter: Failed to register create process notify routine with status 0x%X.", *InitializeStatus);
		return;
	}
	
	//
	// Set the load image notify routine.
	//
	*InitializeStatus = PsSetLoadImageNotifyRoutine(ImageHistoryFilter::LoadImageNotifyRoutine);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("ImageHistoryFilter!ImageHistoryFilter: Failed to register load image notify routine with status 0x%X.", *InitializeStatus);
		return;
	}

	FltInitializePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	ImageHistoryFilter::ProcessHistoryHead = RCAST<PPROCESS_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(PROCESS_HISTORY_ENTRY), PROCESS_HISTORY_TAG));
	if (ImageHistoryFilter::ProcessHistoryHead == NULL)
	{
		DBGPRINT("ImageHistoryFilter!ImageHistoryFilter: Failed to allocate the process history head.");
		*InitializeStatus = STATUS_NO_MEMORY;
		return;
	}
	memset(ImageHistoryFilter::ProcessHistoryHead, 0, sizeof(PROCESS_HISTORY_ENTRY));
	InitializeListHead(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead));
	this->ProcessHistorySize = 0;

	//
	// Set the detector.
	//
	ImageHistoryFilter::detector = Detector;
}

/**
	Clean up the process history linked-list.
*/
ImageHistoryFilter::~ImageHistoryFilter (
	VOID
	)
{
	PPROCESS_HISTORY_ENTRY currentProcessHistory;
	PIMAGE_LOAD_HISTORY_ENTRY currentImageEntry;

	//
	// Set destroying to TRUE so that no other threads can get a lock.
	//
	ImageHistoryFilter::destroying = TRUE;

	//
	// Remove the notify routines.
	//
	PsSetCreateProcessNotifyRoutineEx(ImageHistoryFilter::CreateProcessNotifyRoutine, TRUE);
	PsRemoveLoadImageNotifyRoutine(ImageHistoryFilter::LoadImageNotifyRoutine);

	//
	// Acquire an exclusive lock to push out other threads.
	//
	FltAcquirePushLockExclusive(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Delete the lock for the process history linked-list.
	//
	FltDeletePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Go through each process history and free it.
	//
	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		while (IsListEmpty(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead)) == FALSE)
		{
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(RemoveHeadList(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead)));
			//
			// Clear the images linked-list.
			//
			FltDeletePushLock(&currentProcessHistory->ImageLoadHistoryLock);
			if (currentProcessHistory->ImageLoadHistory)
			{
				while (IsListEmpty(RCAST<PLIST_ENTRY>(currentProcessHistory->ImageLoadHistory)) == FALSE)
				{
					currentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(RemoveHeadList(RCAST<PLIST_ENTRY>(currentProcessHistory->ImageLoadHistory)));

					//
					// Free the image name.
					//
					if (currentImageEntry->ImageFileName.Buffer)
					{
						ExFreePoolWithTag(currentImageEntry->ImageFileName.Buffer, IMAGE_NAME_TAG);
					}

					if (currentImageEntry->CallerImageFileName)
					{
						ExFreePoolWithTag(currentImageEntry->CallerImageFileName, IMAGE_NAME_TAG);
					}

					//
					// Free the stack history.
					//
					ExFreePoolWithTag(currentImageEntry->CallerStackHistory, STACK_HISTORY_TAG);

					ExFreePoolWithTag(currentImageEntry, IMAGE_HISTORY_TAG);
				}

				//
				// Finally, free the list head.
				//
				ExFreePoolWithTag(currentProcessHistory->ImageLoadHistory, IMAGE_HISTORY_TAG);
			}

			//
			// Free the names.
			//
			if (currentProcessHistory->ProcessImageFileName)
			{
				ExFreePoolWithTag(currentProcessHistory->ProcessImageFileName, IMAGE_NAME_TAG);
			}
			if (currentProcessHistory->CallerImageFileName)
			{
				ExFreePoolWithTag(currentProcessHistory->CallerImageFileName, IMAGE_NAME_TAG);
			}
			if (currentProcessHistory->ParentImageFileName)
			{
				ExFreePoolWithTag(currentProcessHistory->ParentImageFileName, IMAGE_NAME_TAG);
			}
			if (currentProcessHistory->ProcessCommandLine)
			{
				ExFreePoolWithTag(currentProcessHistory->ProcessCommandLine, IMAGE_COMMMAND_TAG);
			}

			//
			// Free the stack history.
			//
			ExFreePoolWithTag(currentProcessHistory->CallerStackHistory, STACK_HISTORY_TAG);

			//
			// Free the process history.
			//
			ExFreePoolWithTag(currentProcessHistory, PROCESS_HISTORY_TAG);
		}

		//
		// Finally, free the list head.
		//
		ExFreePoolWithTag(ImageHistoryFilter::ProcessHistoryHead, PROCESS_HISTORY_TAG);
	}
}

/**
	Add a process to the linked-list of process history objects. This function attempts to add a history object regardless of failures.
	@param ProcessId - The process ID of the process to add.
	@param CreateInfo - Information about the process being created.
*/
VOID
ImageHistoryFilter::AddProcessToHistory (
	_In_ HANDLE ProcessId,
	_In_ PPS_CREATE_NOTIFY_INFO CreateInfo
	)
{
	NTSTATUS status;
	PPROCESS_HISTORY_ENTRY newProcessHistory;
	LARGE_INTEGER systemTime;
	LARGE_INTEGER localSystemTime;
	BOOLEAN processHistoryLockHeld;

	processHistoryLockHeld = FALSE;
	status = STATUS_SUCCESS;

	if (ImageHistoryFilter::destroying)
	{
		return;
	}

	newProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(PROCESS_HISTORY_ENTRY), PROCESS_HISTORY_TAG));
	if (newProcessHistory == NULL)
	{
		DBGPRINT("ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for the process history.");
		status = STATUS_NO_MEMORY;
		goto Exit;
	}

	memset(newProcessHistory, 0, sizeof(PROCESS_HISTORY_ENTRY));

	//
	// Basic fields.
	//
	newProcessHistory->ProcessId = ProcessId;
	newProcessHistory->ParentId = CreateInfo->ParentProcessId;
	newProcessHistory->CallerId = PsGetCurrentProcessId();
	newProcessHistory->ProcessTerminated = FALSE;
	newProcessHistory->ImageLoadHistorySize = 0;
	KeQuerySystemTime(&systemTime);
	ExSystemTimeToLocalTime(&systemTime, &localSystemTime);
	newProcessHistory->EpochExecutionTime = localSystemTime.QuadPart / TICKSPERSEC - SECS_1601_TO_1970;
	//
	// Image file name fields.
	//

	
	//
	// Allocate the necessary space.
	//
	newProcessHistory->ProcessImageFileName = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, sizeof(UNICODE_STRING) + CreateInfo->ImageFileName->Length, IMAGE_NAME_TAG));
	if (newProcessHistory->ProcessImageFileName == NULL)
	{
		DBGPRINT("ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for process ImageFileName.");
		goto Exit;
	}

	newProcessHistory->ProcessImageFileName->Buffer = RCAST<PWCH>(RCAST<ULONG_PTR>(newProcessHistory->ProcessImageFileName) + sizeof(UNICODE_STRING));
	newProcessHistory->ProcessImageFileName->Length = CreateInfo->ImageFileName->Length;
	newProcessHistory->ProcessImageFileName->MaximumLength = CreateInfo->ImageFileName->Length;

	//
	// Copy the image file name string.
	//
	RtlCopyUnicodeString(newProcessHistory->ProcessImageFileName, CreateInfo->ImageFileName);

	//
	// Allocate the necessary space.
	//
	if (CreateInfo->CommandLine)
	{
		newProcessHistory->ProcessCommandLine = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, sizeof(UNICODE_STRING) + CreateInfo->CommandLine->Length, IMAGE_COMMMAND_TAG));
		if (newProcessHistory->ProcessCommandLine == NULL)
		{
			DBGPRINT("ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for process command line.");
			goto Exit;
		}

		newProcessHistory->ProcessCommandLine->Buffer = RCAST<PWCH>(RCAST<ULONG_PTR>(newProcessHistory->ProcessCommandLine) + sizeof(UNICODE_STRING));
		newProcessHistory->ProcessCommandLine->Length = CreateInfo->CommandLine->Length;
		newProcessHistory->ProcessCommandLine->MaximumLength = CreateInfo->CommandLine->Length;

		//
		// Copy the command line string.
		//
		RtlCopyUnicodeString(newProcessHistory->ProcessCommandLine, CreateInfo->CommandLine);
	}
	//
	// These fields are optional.
	//
	ImageHistoryFilter::GetProcessImageFileName(CreateInfo->ParentProcessId, &newProcessHistory->ParentImageFileName);

	if (PsGetCurrentProcessId() != CreateInfo->ParentProcessId)
	{
		ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &newProcessHistory->CallerImageFileName);
	}

	//
	// Grab the user-mode stack.
	//
	newProcessHistory->CallerStackHistorySize = MAX_STACK_RETURN_HISTORY; // Will be updated in the resolve function.
	walker.WalkAndResolveStack(&newProcessHistory->CallerStackHistory, &newProcessHistory->CallerStackHistorySize, STACK_HISTORY_TAG);
	if (newProcessHistory->CallerStackHistory == NULL)
	{
		DBGPRINT("ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for the stack history.");
		status = STATUS_NO_MEMORY;
		goto Exit;
	}

	newProcessHistory->ImageLoadHistory = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(IMAGE_LOAD_HISTORY_ENTRY), IMAGE_HISTORY_TAG));
	if (newProcessHistory->ImageLoadHistory == NULL)
	{
		DBGPRINT("ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for the image load history.");
		status = STATUS_NO_MEMORY;
		goto Exit;
	}
	memset(newProcessHistory->ImageLoadHistory, 0, sizeof(IMAGE_LOAD_HISTORY_ENTRY));

	InitializeListHead(RCAST<PLIST_ENTRY>(newProcessHistory->ImageLoadHistory));

	//
	// Initialize this last so we don't have to delete it if anything failed.
	//
	FltInitializePushLock(&newProcessHistory->ImageLoadHistoryLock);

	//
	// Grab a lock to add an entry.
	//
	FltAcquirePushLockExclusive(&ImageHistoryFilter::ProcessHistoryLock);

	InsertTailList(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead), RCAST<PLIST_ENTRY>(newProcessHistory));
	ImageHistoryFilter::ProcessHistorySize++;

	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Audit the stack.
	//
	ImageHistoryFilter::detector->AuditUserStackWalk(ProcessCreate,
													 newProcessHistory->ProcessId,
													 newProcessHistory->ParentImageFileName,
													 newProcessHistory->ProcessImageFileName,
													 newProcessHistory->CallerStackHistory,
													 newProcessHistory->CallerStackHistorySize);

	//
	// Check for parent process ID spoofing.
	//
	ImageHistoryFilter::detector->AuditCallerProcessId(ProcessCreate,
													   PsGetCurrentProcessId(),
													   CreateInfo->ParentProcessId,
													   newProcessHistory->ParentImageFileName,
													   newProcessHistory->ProcessImageFileName,
													   newProcessHistory->CallerStackHistory,
													   newProcessHistory->CallerStackHistorySize);
Exit:
	if (newProcessHistory && NT_SUCCESS(status) == FALSE)
	{
		ExFreePoolWithTag(newProcessHistory, PROCESS_HISTORY_TAG);
	}
}

/**
	Set a process to terminated, still maintain the history.
	@param ProcessId - The process ID of the process being terminated.
*/
VOID
ImageHistoryFilter::TerminateProcessInHistory (
	_In_ HANDLE ProcessId
	)
{
	PPROCESS_HISTORY_ENTRY currentProcessHistory;

	if (ImageHistoryFilter::destroying)
	{
		return;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Iterate histories for a match.
	//
	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = ImageHistoryFilter::ProcessHistoryHead;
		do
		{
			//
			// Find the process history with the same PID and then set it to terminated.
			//
			if (currentProcessHistory->ProcessId == ProcessId)
			{
				currentProcessHistory->ProcessTerminated = TRUE;
				break;
			}
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);
		} while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead);
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);
}

/**
	Notify routine called on new process execution.
	@param Process - The EPROCESS structure of the new/terminating process.
	@param ProcessId - The new child's process ID.
	@param CreateInfo - Information about the process being created.
*/
VOID
ImageHistoryFilter::CreateProcessNotifyRoutine (
	_In_ PEPROCESS Process,
	_In_ HANDLE ProcessId,
	_In_ PPS_CREATE_NOTIFY_INFO CreateInfo
	)
{
	UNREFERENCED_PARAMETER(Process);
	//
	// If a new process is being created, add it to the history of processes.
	//
	if (CreateInfo)
	{
		ImageHistoryFilter::AddProcessToHistory(ProcessId, CreateInfo);
		DBGPRINT("ImageHistoryFilter!CreateProcessNotifyRoutine: Registered process 0x%X.", ProcessId);
	}
	else
	{
		DBGPRINT("ImageHistoryFilter!CreateProcessNotifyRoutine: Terminating process 0x%X.", ProcessId);
		//
		// Set the process as "terminated".
		//
		ImageHistoryFilter::TerminateProcessInHistory(ProcessId);
	}
}

/**
	Retrieve the full image file name for a process.
	@param ProcessId - The process to get the name of.
	@param ProcessImageFileName - PUNICODE_STRING to fill with the image file name of the process.
*/
BOOLEAN
ImageHistoryFilter::GetProcessImageFileName (
	_In_ HANDLE ProcessId,
	_Inout_ PUNICODE_STRING* ImageFileName
	)
{
	NTSTATUS status;
	PEPROCESS processObject;
	HANDLE processHandle;
	ULONG returnLength;

	processHandle = NULL;
	*ImageFileName = NULL;
	returnLength = 0;

	//
	// Before we can open a handle to the process, we need its PEPROCESS object.
	//
	status = PsLookupProcessByProcessId(ProcessId, &processObject);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("ImageHistoryFilter!GetProcessImageFileName: Failed to find process object with status 0x%X.", status);
		goto Exit;
	}

	//
	// Open a handle to the process.
	//
	status = ObOpenObjectByPointer(processObject, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, *PsProcessType, KernelMode, &processHandle);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("ImageHistoryFilter!GetProcessImageFileName: Failed to open handle to process with status 0x%X.", status);
		goto Exit;
	}

	//
	// Query for the size of the UNICODE_STRING.
	//
	status = NtQueryInformationProcess(processHandle, ProcessImageFileName, NULL, 0, &returnLength);
	if (status != STATUS_INFO_LENGTH_MISMATCH && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_BUFFER_OVERFLOW)
	{
		DBGPRINT("ImageHistoryFilter!GetProcessImageFileName: Failed to query size of process ImageFileName with status 0x%X.", status);
		goto Exit;
	}

	//
	// Allocate the necessary space.
	//
	*ImageFileName = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, returnLength, IMAGE_NAME_TAG));
	if (*ImageFileName == NULL)
	{
		DBGPRINT("ImageHistoryFilter!GetProcessImageFileName: Failed to allocate space for process ImageFileName.");
		goto Exit;
	}

	//
	// Query the image file name.
	//
	status = NtQueryInformationProcess(processHandle, ProcessImageFileName, *ImageFileName, returnLength, &returnLength);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("ImageHistoryFilter!GetProcessImageFileName: Failed to query process ImageFileName with status 0x%X.", status);
		goto Exit;
	}
Exit:
	if (processHandle)
	{
		ZwClose(processHandle);
	}
	if (NT_SUCCESS(status) == FALSE && *ImageFileName)
	{
		ExFreePoolWithTag(*ImageFileName, IMAGE_NAME_TAG);
		*ImageFileName = NULL;
	}
	return NT_SUCCESS(status);
}

/**
	Notify routine called when a new image is loaded into a process. Adds the image to the corresponding process history element.
	@param FullImageName - A PUNICODE_STRING that identifies the executable image file. Might be NULL.
	@param ProcessId - The process ID where this image is being mapped.
	@param ImageInfo - Structure containing a variety of properties about the image being loaded.
*/
VOID
ImageHistoryFilter::LoadImageNotifyRoutine(
	_In_ PUNICODE_STRING FullImageName,
	_In_ HANDLE ProcessId,
	_In_ PIMAGE_INFO ImageInfo
	)
{
	NTSTATUS status;
	PPROCESS_HISTORY_ENTRY currentProcessHistory;
	PIMAGE_LOAD_HISTORY_ENTRY newImageLoadHistory;

	UNREFERENCED_PARAMETER(ImageInfo);

	currentProcessHistory = NULL;
	newImageLoadHistory = NULL;
	status = STATUS_SUCCESS;

	if (ImageHistoryFilter::destroying)
	{
		return;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Iterate histories for a match.
	//
	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = ImageHistoryFilter::ProcessHistoryHead;
		do
		{
			if (currentProcessHistory->ProcessId == ProcessId && currentProcessHistory->ProcessTerminated == FALSE)
			{
				break;
			}
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);
		} while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead);
	}

	//
	// This might happen if we load on a running machine that already has processes.
	//
	if (currentProcessHistory == NULL || currentProcessHistory == ImageHistoryFilter::ProcessHistoryHead)
	{
		DBGPRINT("ImageHistoryFilter!LoadImageNotifyRoutine: Failed to find PID 0x%X in history.", ProcessId);
		status = STATUS_NOT_FOUND;
		goto Exit;
	}

	//
	// Allocate space for the new image history entry.
	//
	newImageLoadHistory = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(IMAGE_LOAD_HISTORY_ENTRY), IMAGE_HISTORY_TAG));
	if (newImageLoadHistory == NULL)
	{
		DBGPRINT("ImageHistoryFilter!LoadImageNotifyRoutine: Failed to allocate space for the image history entry.");
		status = STATUS_NO_MEMORY;
		goto Exit;
	}
	memset(newImageLoadHistory, 0, sizeof(IMAGE_LOAD_HISTORY_ENTRY));

	newImageLoadHistory->CallerProcessId = PsGetCurrentProcessId();
	if (PsGetCurrentProcessId() != ProcessId)
	{
		newImageLoadHistory->RemoteImage = TRUE;
		ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &newImageLoadHistory->CallerImageFileName);
	}

	//
	// Copy the image file name if it is provided.
	//
	if (FullImageName)
	{
		//
		// Allocate the copy buffer. FullImageName will not be valid forever.
		//
		newImageLoadHistory->ImageFileName.Buffer = RCAST<PWCH>(ExAllocatePoolWithTag(PagedPool, SCAST<SIZE_T>(FullImageName->Length) + 2, IMAGE_NAME_TAG));
		if (newImageLoadHistory->ImageFileName.Buffer == NULL)
		{
			DBGPRINT("ImageHistoryFilter!LoadImageNotifyRoutine: Failed to allocate space for the image file name.");
			status = STATUS_NO_MEMORY;
			goto Exit;
		}

		newImageLoadHistory->ImageFileName.Length = SCAST<SIZE_T>(FullImageName->Length) + 2;
		newImageLoadHistory->ImageFileName.MaximumLength = SCAST<SIZE_T>(FullImageName->Length) + 2;

		//
		// Copy the image name.
		//
		status = RtlStringCbCopyUnicodeString(newImageLoadHistory->ImageFileName.Buffer, SCAST<SIZE_T>(FullImageName->Length) + 2, FullImageName);
		if (NT_SUCCESS(status) == FALSE)
		{
			DBGPRINT("ImageHistoryFilter!LoadImageNotifyRoutine: Failed to copy the image file name with status 0x%X. Destination size = 0x%X, Source Size = 0x%X.", status, SCAST<SIZE_T>(FullImageName->Length) + 2, SCAST<SIZE_T>(FullImageName->Length));
			goto Exit;
		}
	}

	//
	// Grab the user-mode stack.
	//
	newImageLoadHistory->CallerStackHistorySize = MAX_STACK_RETURN_HISTORY; // Will be updated in the resolve function.
	walker.WalkAndResolveStack(&newImageLoadHistory->CallerStackHistory, &newImageLoadHistory->CallerStackHistorySize, STACK_HISTORY_TAG);
	if (newImageLoadHistory->CallerStackHistory == NULL)
	{
		DBGPRINT("ImageHistoryFilter!LoadImageNotifyRoutine: Failed to allocate space for the stack history.");
		status = STATUS_NO_MEMORY;
		goto Exit;
	}

	FltAcquirePushLockExclusive(&currentProcessHistory->ImageLoadHistoryLock);

	InsertHeadList(RCAST<PLIST_ENTRY>(currentProcessHistory->ImageLoadHistory), RCAST<PLIST_ENTRY>(newImageLoadHistory));
	currentProcessHistory->ImageLoadHistorySize++;

	FltReleasePushLock(&currentProcessHistory->ImageLoadHistoryLock);

	//
	// Audit the stack.
	//
	ImageHistoryFilter::detector->AuditUserStackWalk(ImageLoad,
													 PsGetCurrentProcessId(),
													 currentProcessHistory->ProcessImageFileName,
													 &newImageLoadHistory->ImageFileName,
													 newImageLoadHistory->CallerStackHistory,
													 newImageLoadHistory->CallerStackHistorySize);
Exit:
	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Clean up on failure.
	//
	if (newImageLoadHistory && NT_SUCCESS(status) == FALSE)
	{
		if (newImageLoadHistory->ImageFileName.Buffer)
		{
			ExFreePoolWithTag(newImageLoadHistory->ImageFileName.Buffer, IMAGE_NAME_TAG);
			DBGPRINT("Free'd 'PmIn' at 0x%llx.", newImageLoadHistory->ImageFileName.Buffer);
		}
		if (newImageLoadHistory->CallerStackHistory)
		{
			ExFreePoolWithTag(newImageLoadHistory->CallerStackHistory, STACK_HISTORY_TAG);
			DBGPRINT("Free'd 'PmSh' at 0x%llx.", newImageLoadHistory->CallerStackHistory);
		}
		ExFreePoolWithTag(newImageLoadHistory, IMAGE_HISTORY_TAG);
		DBGPRINT("Free'd 'PmIh' at 0x%llx.", newImageLoadHistory);
	}
}

/**
	Get the summary for MaxProcessSummaries processes starting from the top of list + SkipCount.
	@param SkipCount - How many processes to skip in the list.
	@param ProcessSummaries - Caller-supplied array of process summaries that this function fills.
	@param MaxProcessSumaries - Maximum number of process summaries that the array allows for.
	@return The actual number of summaries returned.
*/
ULONG
ImageHistoryFilter::GetProcessHistorySummary (
	_In_ ULONG SkipCount,
	_Inout_ PPROCESS_SUMMARY_ENTRY ProcessSummaries,
	_In_ ULONG MaxProcessSummaries
	)
{
	PPROCESS_HISTORY_ENTRY currentProcessHistory;
	ULONG currentProcessIndex;
	ULONG actualFilledSummaries;
	NTSTATUS status;

	currentProcessIndex = 0;
	actualFilledSummaries = 0;

	if (ImageHistoryFilter::destroying)
	{
		return 0;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	//
	// Iterate histories for the MaxProcessSummaries processes after SkipCount processes.
	//
	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Flink);
		while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead && actualFilledSummaries < MaxProcessSummaries)
		{
			if (currentProcessIndex >= SkipCount)
			{
				//
				// Fill out the summary.
				//
				ProcessSummaries[actualFilledSummaries].EpochExecutionTime = currentProcessHistory->EpochExecutionTime;
				ProcessSummaries[actualFilledSummaries].ProcessId = currentProcessHistory->ProcessId;
				ProcessSummaries[actualFilledSummaries].ProcessTerminated = currentProcessHistory->ProcessTerminated;
				
				if (currentProcessHistory->ProcessImageFileName)
				{
					//
					// Copy the image name.
					//
					status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(&ProcessSummaries[actualFilledSummaries].ImageFileName), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ProcessImageFileName);
					if (NT_SUCCESS(status) == FALSE)
					{
						DBGPRINT("ImageHistoryFilter!GetProcessHistorySummary: Failed to copy the image file name with status 0x%X.", status);
						break;
					}
				}
				actualFilledSummaries++;
			}
			currentProcessIndex++;
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Flink);
		}
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	return actualFilledSummaries;
}

/**
	Populate a request for detailed information on a process.
	@param ProcessDetailedRequest - The request to populate.
*/
VOID
ImageHistoryFilter::PopulateProcessDetailedRequest (
	_Inout_ PPROCESS_DETAILED_REQUEST ProcessDetailedRequest
	)
{
	NTSTATUS status;
	PPROCESS_HISTORY_ENTRY currentProcessHistory;
	PIMAGE_LOAD_HISTORY_ENTRY currentImageEntry;
	ULONG i;

	i = 0;

	if (ImageHistoryFilter::destroying)
	{
		return;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);
		while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)
		{
			if (ProcessDetailedRequest->ProcessId == currentProcessHistory->ProcessId &&
				ProcessDetailedRequest->EpochExecutionTime == currentProcessHistory->EpochExecutionTime)
			{
				//
				// Set basic fields.
				//
				ProcessDetailedRequest->Populated = TRUE;
				ProcessDetailedRequest->CallerProcessId = currentProcessHistory->CallerId;
				ProcessDetailedRequest->ParentProcessId = currentProcessHistory->ParentId;

				//
				// Copy the stack history.
				//
				ProcessDetailedRequest->StackHistorySize = (ProcessDetailedRequest->StackHistorySize > currentProcessHistory->CallerStackHistorySize) ? currentProcessHistory->CallerStackHistorySize : ProcessDetailedRequest->StackHistorySize;
				memcpy(ProcessDetailedRequest->StackHistory, currentProcessHistory->CallerStackHistory, ProcessDetailedRequest->StackHistorySize * sizeof(STACK_RETURN_INFO));

				//
				// Copy the paths.
				//
				if (currentProcessHistory->ProcessImageFileName)
				{
					status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ProcessPath), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ProcessImageFileName);
					if (NT_SUCCESS(status) == FALSE)
					{
						DBGPRINT("ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of the process with status 0x%X.", status);
						break;
					}
				}
				if (currentProcessHistory->CallerImageFileName)
				{
					status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->CallerProcessPath), MAX_PATH * sizeof(WCHAR), currentProcessHistory->CallerImageFileName);
					if (NT_SUCCESS(status) == FALSE)
					{
						DBGPRINT("ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of the caller with status 0x%X.", status);
						break;
					}
				}
				if (currentProcessHistory->ParentImageFileName)
				{
					status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ParentProcessPath), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ParentImageFileName);
					if (NT_SUCCESS(status) == FALSE)
					{
						DBGPRINT("ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of the parent with status 0x%X.", status);
						break;
					}
				}
				if (currentProcessHistory->ProcessCommandLine)
				{
					status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ProcessCommandLine), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ProcessCommandLine);
					if (NT_SUCCESS(status) == FALSE)
					{
						DBGPRINT("ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the command line of the process with status 0x%X.", status);
						break;
					}
				}

				//
				// Iterate the images for basic information.
				//
				FltAcquirePushLockShared(&currentProcessHistory->ImageLoadHistoryLock);

				//
				// The head isn't an element so skip it.
				//
				currentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentProcessHistory->ImageLoadHistory->ListEntry.Flink);
				while (currentImageEntry != currentProcessHistory->ImageLoadHistory && i < ProcessDetailedRequest->ImageSummarySize)
				{
					__try
					{
						if (currentImageEntry->ImageFileName.Buffer)
						{
							status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ImageSummary[i].ImagePath), MAX_PATH * sizeof(WCHAR), &currentImageEntry->ImageFileName);
							if (NT_SUCCESS(status) == FALSE)
							{
								DBGPRINT("ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of an image with status 0x%X and source size %i.", status, currentImageEntry->ImageFileName.Length);
								break;
							}
						}
						ProcessDetailedRequest->ImageSummary[i].StackSize = currentImageEntry->CallerStackHistorySize;
					}
					__except (1)
					{
						DBGPRINT("ImageHistoryFilter!PopulateProcessDetailedRequest: Exception while processing image summaries.");
						break;
					}
					
					i++;

					currentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentImageEntry->ListEntry.Flink);
				}

				FltReleasePushLock(&currentProcessHistory->ImageLoadHistoryLock);

				ProcessDetailedRequest->ImageSummarySize = i; // Actual number of images put into the array.
				break;
			}
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);
		}
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);
}

/**
	Populate a process sizes request.
	@param ProcesSizesRequest - The request to populate.
*/
VOID
ImageHistoryFilter::PopulateProcessSizes (
	_Inout_ PPROCESS_SIZES_REQUEST ProcessSizesRequest
	)
{
	PPROCESS_HISTORY_ENTRY currentProcessHistory;

	if (ImageHistoryFilter::destroying)
	{
		return;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);
		while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)
		{
			if (ProcessSizesRequest->ProcessId == currentProcessHistory->ProcessId &&
				ProcessSizesRequest->EpochExecutionTime == currentProcessHistory->EpochExecutionTime)
			{
				ProcessSizesRequest->StackSize = currentProcessHistory->CallerStackHistorySize;
				ProcessSizesRequest->ImageSize = currentProcessHistory->ImageLoadHistorySize;
				break;
			}
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);
		}
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);
}

/**
	Increment process thread count by one and retrieve the latest value.
	@param ProcessId - The process ID of the target process.
	@param ThreadCount - The resulting thread count.
	@return Whether or not the process was found.
*/
BOOLEAN
ImageHistoryFilter::AddProcessThreadCount (
	_In_ HANDLE ProcessId,
	_Inout_ ULONG* ThreadCount
	)
{
	PPROCESS_HISTORY_ENTRY currentProcessHistory;
	BOOLEAN foundProcess;

	foundProcess = FALSE;

	if (ImageHistoryFilter::destroying)
	{
		return foundProcess;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);
		while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)
		{
			if (ProcessId == currentProcessHistory->ProcessId &&
				currentProcessHistory->ProcessTerminated == FALSE)
			{
				currentProcessHistory->ProcessThreadCount++;
				*ThreadCount = currentProcessHistory->ProcessThreadCount;
				foundProcess = TRUE;
				break;
			}
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);
		}
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);

	return foundProcess;
}

VOID
ImageHistoryFilter::PopulateImageDetailedRequest(
	_Inout_ PIMAGE_DETAILED_REQUEST ImageDetailedRequest
	)
{
	NTSTATUS status;
	PPROCESS_HISTORY_ENTRY currentProcessHistory;
	PIMAGE_LOAD_HISTORY_ENTRY currentImageEntry;
	ULONG i;

	i = 0;

	if (ImageHistoryFilter::destroying)
	{
		return;
	}

	//
	// Acquire a shared lock to iterate processes.
	//
	FltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);

	if (ImageHistoryFilter::ProcessHistoryHead)
	{
		currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);
		while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)
		{
			if (ImageDetailedRequest->ProcessId == currentProcessHistory->ProcessId &&
				ImageDetailedRequest->EpochExecutionTime == currentProcessHistory->EpochExecutionTime)
			{
				//
				// Iterate the images for basic information.
				//
				FltAcquirePushLockShared(&currentProcessHistory->ImageLoadHistoryLock);

				//
				// The head isn't an element so skip it.
				//
				currentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentProcessHistory->ImageLoadHistory->ListEntry.Flink);
				while (currentImageEntry != currentProcessHistory->ImageLoadHistory)
				{
					if (i == ImageDetailedRequest->ImageIndex)
					{
						if (currentImageEntry->ImageFileName.Buffer)
						{
							status = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ImageDetailedRequest->ImagePath), MAX_PATH * sizeof(WCHAR), &currentImageEntry->ImageFileName);
							if (NT_SUCCESS(status) == FALSE)
							{
								DBGPRINT("ImageHistoryFilter!PopulateImageDetailedRequest: Failed to copy the image file name of an image with status 0x%X and source size %i.", status, currentImageEntry->ImageFileName.Length);
								break;
							}
						}

						//
						// Copy the stack history.
						//
						ImageDetailedRequest->StackHistorySize = (ImageDetailedRequest->StackHistorySize > currentImageEntry->CallerStackHistorySize) ? currentImageEntry->CallerStackHistorySize : ImageDetailedRequest->StackHistorySize;
						memcpy(ImageDetailedRequest->StackHistory, currentImageEntry->CallerStackHistory, ImageDetailedRequest->StackHistorySize * sizeof(STACK_RETURN_INFO));

						ImageDetailedRequest->Populated = TRUE;
					}
					i++;
					currentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentImageEntry->ListEntry.Flink);
				}

				FltReleasePushLock(&currentProcessHistory->ImageLoadHistoryLock);
				break;
			}
			currentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);
		}
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);
}

================================================
FILE: PeaceMaker Kernel/ImageHistoryFilter.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "StackWalker.h"
#include "shared.h"
#include "DetectionLogic.h"

#define IMAGE_NAME_TAG 'nImP'
#define IMAGE_COMMMAND_TAG 'cImP'
#define PROCESS_HISTORY_TAG 'hPmP'
#define STACK_HISTORY_TAG 'hSmP'
#define IMAGE_HISTORY_TAG 'hImP'

typedef struct ImageLoadHistoryEntry
{
	LIST_ENTRY ListEntry;					// The list entry to iterate multiple images in a process.
	UNICODE_STRING ImageFileName;			// The full image file name of loaded image.
	HANDLE CallerProcessId;					// The real caller of the load image routine.
	BOOLEAN RemoteImage;					// Whether or not the image was loaded remotely.
	PUNICODE_STRING CallerImageFileName;		// The full image file name of the caller. Only specified if RemoteImage == TRUE.
	PSTACK_RETURN_INFO CallerStackHistory;	// A variable-length array of the stack that loaded the image.
	ULONG CallerStackHistorySize;			// The size of the variable-length stack history array.
} IMAGE_LOAD_HISTORY_ENTRY, *PIMAGE_LOAD_HISTORY_ENTRY;

typedef struct ProcessHistoryEntry
{
	LIST_ENTRY ListEntry;						// The list entry to iterate multiple process histories.

	HANDLE CallerId;							// The process id of the caller process.
	PUNICODE_STRING CallerImageFileName;		// OPTIONAL: The image file name of the caller process.

	HANDLE ParentId;							// The process id of the alleged parent process.
	PUNICODE_STRING ParentImageFileName;		// OPTIONAL: The image file name of the alleged parent process.

	HANDLE ProcessId;							// The process id of the executed process.
	PUNICODE_STRING ProcessImageFileName;		// The image file name of the executed process.

	PUNICODE_STRING ProcessCommandLine;			// The command-line string for the executed process.

	ULONG ProcessThreadCount;					// The number of threads the process has.
	
	ULONGLONG EpochExecutionTime;				// Process execution time in seconds since 1970.
	BOOLEAN ProcessTerminated;					// Whether or not the process has terminated.

	PSTACK_RETURN_INFO CallerStackHistory;		// A variable-length array of the stack that started the process.
	ULONG CallerStackHistorySize;				// The size of the variable-length stack history array.

	PIMAGE_LOAD_HISTORY_ENTRY ImageLoadHistory;	// A linked-list of loaded images and their respective stack histories.
	EX_PUSH_LOCK ImageLoadHistoryLock;			// The lock protecting the linked-list of loaded images.
	ULONG ImageLoadHistorySize;					// The size of the image load history linked-list.
} PROCESS_HISTORY_ENTRY, *PPROCESS_HISTORY_ENTRY;

typedef class ImageHistoryFilter
{

	static VOID CreateProcessNotifyRoutine (
		_In_ PEPROCESS Process,
		_In_ HANDLE ProcessId,
		_In_ PPS_CREATE_NOTIFY_INFO CreateInfo
		);

	static VOID LoadImageNotifyRoutine (
		_In_ PUNICODE_STRING FullImageName,
		_In_ HANDLE ProcessId,
		_In_ PIMAGE_INFO ImageInfo
		);

	static StackWalker walker;							// Stack walking utility.
	static PPROCESS_HISTORY_ENTRY ProcessHistoryHead;	// Linked-list of process history objects.
	static EX_PUSH_LOCK ProcessHistoryLock;				// Lock protecting the ProcessHistory linked-list.
	static BOOLEAN destroying;							// This boolean indicates to functions that a lock should not be held as we are in the process of destruction.
	static PDETECTION_LOGIC detector;

	static VOID AddProcessToHistory(
		_In_ HANDLE ProcessId,
		_In_ PPS_CREATE_NOTIFY_INFO CreateInfo
		);

	static VOID TerminateProcessInHistory(
		_In_ HANDLE ProcessId
		);

public:
	ImageHistoryFilter(
		_In_ PDETECTION_LOGIC Detector,
		_Out_ NTSTATUS* InitializeStatus
		);
	~ImageHistoryFilter(VOID);

	static BOOLEAN GetProcessImageFileName(
		_In_ HANDLE ProcessId,
		_Inout_ PUNICODE_STRING* ImageFileName
		);

	ULONG GetProcessHistorySummary(
		_In_ ULONG SkipCount,
		_Inout_ PPROCESS_SUMMARY_ENTRY ProcessSummaries,
		_In_ ULONG MaxProcessSummaries
		);

	VOID PopulateProcessDetailedRequest(
		_Inout_ PPROCESS_DETAILED_REQUEST ProcessDetailedRequest
		);

	VOID PopulateProcessSizes(
		_Inout_ PPROCESS_SIZES_REQUEST ProcessSizesRequest
		);

	VOID PopulateImageDetailedRequest(
		_Inout_ PIMAGE_DETAILED_REQUEST ImageDetailedRequest
		);

	static BOOLEAN AddProcessThreadCount(
		_In_ HANDLE ProcessId,
		_Inout_ ULONG* ThreadCount
		);
	static ULONG64 ProcessHistorySize;					// Number of entries in the ProcessHistory linked-list.
} IMAGE_HISTORY_FILTER, *PIMAGE_HISTORY_FILTER;

================================================
FILE: PeaceMaker Kernel/PeaceMaker Kernel.inf
================================================
;;;
;;; FilterTesting
;;;

[Version]
Signature   = "$Windows NT$"
; TODO - Change the Class and ClassGuid to match the Load Order Group value, see https://msdn.microsoft.com/en-us/windows/hardware/gg462963
; Class       = "ActivityMonitor"                         ;This is determined by the work this filter driver does
; ClassGuid   = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}    ;This value is determined by the Load Order Group value
Class = "ActivityMonitor"
ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}
Provider    = %ManufacturerName%
DriverVer   = 12/17/2019,1.0.0.0
CatalogFile = PeaceMakerKernel.cat

[DestinationDirs]
DefaultDestDir          = 12
MiniFilter.DriverFiles  = 12            ;%windir%\system32\drivers

;;
;; Default install sections
;;

[DefaultInstall]
OptionDesc          = %ServiceDescription%
CopyFiles           = MiniFilter.DriverFiles

[DefaultInstall.Services]
AddService          = %ServiceName%,,MiniFilter.Service

;;
;; Default uninstall sections
;;

[DefaultUninstall]
DelFiles   = MiniFilter.DriverFiles

[DefaultUninstall.Services]
DelService = %ServiceName%,0x200      ;Ensure service is stopped before deleting

;
; Services Section
;

[MiniFilter.Service]
DisplayName      = %ServiceName%
Description      = %ServiceDescription%
ServiceBinary    = %12%\%DriverName%.sys        ;%windir%\system32\drivers\
Dependencies     = "FltMgr"
ServiceType      = 2                            ;SERVICE_FILE_SYSTEM_DRIVER
StartType        = 2                            ;SERVICE_AUTO_START
ErrorControl     = 1                            ;SERVICE_ERROR_NORMAL
; TODO - Change the Load Order Group value
; LoadOrderGroup = "FSFilter Activity Monitor"
LoadOrderGroup = "FSFilter Activity Monitor"
AddReg           = MiniFilter.AddRegistry

;
; Registry Modifications
;

[MiniFilter.AddRegistry]
HKR,,"DebugFlags",0x00010001 ,0x0
HKR,,"SupportedFeatures",0x00010001,0x3
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%

;
; Copy Files
;

[MiniFilter.DriverFiles]
%DriverName%.sys

[SourceDisksFiles]
PeaceMakerKernel.sys = 1,,

[SourceDisksNames]
1 = %DiskId1%,,,

;;
;; String Section
;;

[Strings]
; TODO - Add your manufacturer
ManufacturerName        = "Bill Demirkapi"
ServiceDescription      = "Peacemaker Kernel Mini-Filter Driver"
ServiceName             = "Peacemaker Kernel"
DriverName              = "PeaceMakerKernel"
DiskId1                 = "Peacemaker Kernel Device Installation Disk"

;Instances specific information.
DefaultInstance         = "FilterTesting Instance"
Instance1.Name          = "FilterTesting Instance"
; TODO - Change the altitude value, see https://msdn.microsoft.com/en-us/windows/hardware/drivers/ifs/load-order-groups-and-altitudes-for-minifilter-drivers
Instance1.Altitude       = "321410"
Instance1.Flags         = 0x0              ; Allow all attachments


================================================
FILE: PeaceMaker Kernel/PeaceMaker Kernel.rc
================================================
#include <windows.h>

#include <ntverp.h>

#define VER_FILETYPE    VFT_DRV
#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
#define VER_COMPANYNAME_STR 		"Demirkapi Security Group"
#define VER_FILEVERSION_STR			"1.0.0.0"
#define VER_LEGALCOPYRIGHT_STR		"Demirkapi Security Group 2019-2020"
#define VER_PRODUCTNAME_STR			"PeaceMaker Threat Detection"
#define VER_FILEDESCRIPTION_STR     "The PeaceMaker TD Kernel Component."
#define VER_INTERNALNAME_STR		"peacemaker.sys"

#include "common.ver"

================================================
FILE: PeaceMaker Kernel/PeaceMaker Kernel.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" 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>
    <ProjectConfiguration Include="Debug|ARM">
      <Configuration>Debug</Configuration>
      <Platform>ARM</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|ARM">
      <Configuration>Release</Configuration>
      <Platform>ARM</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|ARM64">
      <Configuration>Debug</Configuration>
      <Platform>ARM64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|ARM64">
      <Configuration>Release</Configuration>
      <Platform>ARM64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="TamperGuard.cpp" />
    <ClCompile Include="ThreadFilter.cpp" />
    <ResourceCompile Include="PeaceMaker Kernel.rc" />
    <ClCompile Include="AlertQueue.cpp" />
    <ClCompile Include="common.cpp" />
    <ClCompile Include="DetectionLogic.cpp" />
    <ClCompile Include="FSFilter.cpp" />
    <ClCompile Include="ImageHistoryFilter.cpp" />
    <ClCompile Include="IOCTLCommunication.cpp" />
    <ClCompile Include="RegistryFilter.cpp" />
    <ClCompile Include="StackWalker.cpp" />
    <ClCompile Include="StringFilters.cpp" />
    <ClCompile Include="FilterTesting.cpp" />
    <Inf Include="PeaceMaker Kernel.inf" />
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}</ProjectGuid>
    <TemplateGuid>{f2f62967-0815-4fd7-9b86-6eedcac766eb}</TemplateGuid>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
    <Configuration>Debug</Configuration>
    <Platform Condition="'$(Platform)' == ''">Win32</Platform>
    <RootNamespace>PeaceMaker Kernel</RootNamespace>
    <ProjectName>PeaceMaker Kernel</ProjectName>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <TargetVersion>Windows7</TargetVersion>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
    <TargetVersion>Windows10</TargetVersion>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
    <ConfigurationType>Driver</ConfigurationType>
    <DriverType>WDM</DriverType>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
    <PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalOptions>/INTEGRITYCHECK %(AdditionalOptions)</AdditionalOptions>
    </Link>
    <PostBuildEvent>
      <Command>"$(OutDir)signbinary.bat" "$(TargetPath)"</Command>
    </PostBuildEvent>
    <ClCompile />
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
    <Link>
      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <FilesToPackage Include="$(TargetPath)" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlertQueue.h" />
    <ClInclude Include="common.h" />
    <ClInclude Include="DetectionLogic.h" />
    <ClInclude Include="FSFilter.h" />
    <ClInclude Include="IOCTLCommunication.h" />
    <ClInclude Include="ntdef.h" />
    <ClInclude Include="ImageHistoryFilter.h" />
    <ClInclude Include="RegistryFilter.h" />
    <ClInclude Include="shared.h" />
    <ClInclude Include="StackWalker.h" />
    <ClInclude Include="StringFilters.h" />
    <ClInclude Include="TamperGuard.h" />
    <ClInclude Include="ThreadFilter.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: PeaceMaker Kernel/PeaceMaker Kernel.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;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;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>
    <Filter Include="Driver Files">
      <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
      <Extensions>inf;inv;inx;mof;mc;</Extensions>
    </Filter>
    <Filter Include="Header Files\Filters">
      <UniqueIdentifier>{e51791fd-6d37-4d03-af6a-4cf1d58ff83a}</UniqueIdentifier>
    </Filter>
    <Filter Include="Source Files\Filters">
      <UniqueIdentifier>{07baa70a-638f-458b-a11e-cc54d633a0f5}</UniqueIdentifier>
    </Filter>
    <Filter Include="Header Files\Utilities">
      <UniqueIdentifier>{d2416d0a-1b1f-400a-a990-1af1d2a15b4b}</UniqueIdentifier>
    </Filter>
    <Filter Include="Source Files\Utilities">
      <UniqueIdentifier>{b653583e-a15b-446e-85e9-7f8cceecae8c}</UniqueIdentifier>
    </Filter>
    <Filter Include="Header Files\Core">
      <UniqueIdentifier>{67667525-d9bd-4041-8ca5-f90fe95a4741}</UniqueIdentifier>
    </Filter>
    <Filter Include="Source Files\Core">
      <UniqueIdentifier>{bbb90d1c-ab67-44c2-a036-5847843b131f}</UniqueIdentifier>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <Inf Include="PeaceMaker Kernel.inf">
      <Filter>Driver Files</Filter>
    </Inf>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="PeaceMaker Kernel.rc">
      <Filter>Resource Files</Filter>
    </ResourceCompile>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="FilterTesting.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="common.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="FSFilter.cpp">
      <Filter>Source Files\Filters</Filter>
    </ClCompile>
    <ClCompile Include="RegistryFilter.cpp">
      <Filter>Source Files\Filters</Filter>
    </ClCompile>
    <ClCompile Include="StackWalker.cpp">
      <Filter>Source Files\Utilities</Filter>
    </ClCompile>
    <ClCompile Include="ImageHistoryFilter.cpp">
      <Filter>Source Files\Filters</Filter>
    </ClCompile>
    <ClCompile Include="StringFilters.cpp">
      <Filter>Source Files\Utilities</Filter>
    </ClCompile>
    <ClCompile Include="DetectionLogic.cpp">
      <Filter>Source Files\Core</Filter>
    </ClCompile>
    <ClCompile Include="IOCTLCommunication.cpp">
      <Filter>Source Files\Core</Filter>
    </ClCompile>
    <ClCompile Include="AlertQueue.cpp">
      <Filter>Source Files\Utilities</Filter>
    </ClCompile>
    <ClCompile Include="ThreadFilter.cpp">
      <Filter>Source Files\Filters</Filter>
    </ClCompile>
    <ClCompile Include="TamperGuard.cpp">
      <Filter>Source Files\Filters</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="common.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="FSFilter.h">
      <Filter>Header Files\Filters</Filter>
    </ClInclude>
    <ClInclude Include="RegistryFilter.h">
      <Filter>Header Files\Filters</Filter>
    </ClInclude>
    <ClInclude Include="StackWalker.h">
      <Filter>Header Files\Utilities</Filter>
    </ClInclude>
    <ClInclude Include="ntdef.h">
      <Filter>Header Files\Utilities</Filter>
    </ClInclude>
    <ClInclude Include="ImageHistoryFilter.h">
      <Filter>Header Files\Filters</Filter>
    </ClInclude>
    <ClInclude Include="StringFilters.h">
      <Filter>Header Files\Utilities</Filter>
    </ClInclude>
    <ClInclude Include="AlertQueue.h">
      <Filter>Header Files\Utilities</Filter>
    </ClInclude>
    <ClInclude Include="shared.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="DetectionLogic.h">
      <Filter>Header Files\Core</Filter>
    </ClInclude>
    <ClInclude Include="IOCTLCommunication.h">
      <Filter>Header Files\Core</Filter>
    </ClInclude>
    <ClInclude Include="ThreadFilter.h">
      <Filter>Header Files\Filters</Filter>
    </ClInclude>
    <ClInclude Include="TamperGuard.h">
      <Filter>Header Files\Filters</Filter>
    </ClInclude>
  </ItemGroup>
</Project>

================================================
FILE: PeaceMaker Kernel/RegistryFilter.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "RegistryFilter.h"

LARGE_INTEGER RegistryBlockingFilter::RegistryFilterCookie;
PDETECTION_LOGIC RegistryBlockingFilter::detector;
STACK_WALKER RegistryBlockingFilter::walker;
PSTRING_FILTERS RegistryBlockingFilter::RegistryStringFilters;

/**
	Initializes the necessary components of the registry filter.
	@param DriverObject - The object of the driver necessary for mini-filter initialization.
	@param RegistryPath - The registry path of the driver.
	@param Detector - Detection instance used to analyze untrusted operations.
	@param InitializeStatus - Status of initialization.
*/
RegistryBlockingFilter::RegistryBlockingFilter(
	_In_ PDRIVER_OBJECT DriverObject,
	_In_ PUNICODE_STRING RegistryPath,
	_In_ PDETECTION_LOGIC Detector,
	_Out_ NTSTATUS* InitializeStatus
	)
{
	UNICODE_STRING filterAltitude;

	RegistryBlockingFilter::RegistryStringFilters = new (NonPagedPool, STRING_REGISTRY_FILTERS_TAG) StringFilters(RegistryFilter, RegistryPath, L"RegistryFilterStore");
	if (RegistryBlockingFilter::RegistryStringFilters == NULL)
	{
		DBGPRINT("RegistryBlockingFilter!RegistryBlockingFilter: Failed to allocate memory for string filters.");
		*InitializeStatus = STATUS_NO_MEMORY;
		return;
	}
	//
	// Restore existing filters.
	//
	RegistryBlockingFilter::RegistryStringFilters->RestoreFilters();

	//
	// Put our altitude into a UNICODE_STRING.
	//
	RtlInitUnicodeString(&filterAltitude, FILTER_ALTITUDE);

	//
	// Register our registry callback.
	//
	*InitializeStatus = CmRegisterCallbackEx(RCAST<PEX_CALLBACK_FUNCTION>(RegistryBlockingFilter::RegistryCallback), &filterAltitude, DriverObject, NULL, &RegistryFilterCookie, NULL);

	//
	// Set the detector.
	//
	RegistryBlockingFilter::detector = Detector;
}

/**
	Free data members that were dynamically allocated.
*/
RegistryBlockingFilter::~RegistryBlockingFilter()
{
	//
	// Remove the registry callback.
	//
	CmUnRegisterCallback(this->RegistryFilterCookie);

	//
	// Make sure to deconstruct the class.
	//
	RegistryBlockingFilter::RegistryStringFilters->~StringFilters();
	ExFreePoolWithTag(RegistryBlockingFilter::RegistryStringFilters, STRING_REGISTRY_FILTERS_TAG);
}

/**
	Return the string filters used in the registry filter.
	@return String filters for registry operations.
*/
PSTRING_FILTERS RegistryBlockingFilter::GetStringFilters()
{
	return RegistryBlockingFilter::RegistryStringFilters;
}

/**
	Function that decides whether or not to block a registry operation.
	@param KeyObject - The registry key of the operation.
	@param ValueName - The name of the registry value specified by the operation.
	@param OperationFlag - The flags of the operation (i.e WRITE/DELETE).
	@return Whether or not to block the operation.
*/
BOOLEAN
RegistryBlockingFilter::BlockRegistryOperation (
	_In_ PVOID KeyObject,
	_In_ PUNICODE_STRING ValueName,
	_In_ ULONG OperationFlag
	)
{
	BOOLEAN blockOperation;
	NTSTATUS internalStatus;
	HANDLE keyHandle;
	PKEY_NAME_INFORMATION pKeyNameInformation;
	ULONG returnLength;
	ULONG fullKeyValueLength;
	PWCHAR tempValueName;
	PWCHAR fullKeyValueName;

	UNICODE_STRING registryOperationPath;
	PUNICODE_STRING callerProcessPath;
	PSTACK_RETURN_INFO registryOperationStack;
	ULONG registryOperationStackSize;

	blockOperation = FALSE;
	registryOperationStackSize = MAX_STACK_RETURN_HISTORY;
	keyHandle = NULL;
	returnLength = NULL;
	pKeyNameInformation = NULL;
	tempValueName = NULL;
	fullKeyValueName = NULL;

	if (ValueName == NULL || ValueName->Length == 0 || ValueName->Buffer == NULL || ValueName->Length > (NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR)))
	{
		DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: ValueName is NULL.");
		goto Exit;
	}

	tempValueName = RCAST<PWCHAR>(ExAllocatePoolWithTag(NonPagedPoolNx, ValueName->Length, REGISTRY_KEY_NAME_TAG));
	if (tempValueName == NULL)
	{
		DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to allocate memory for value name with size 0x%X.", ValueName->Length);
		goto Exit;
	}

	//
	// There can be some wonky exceptions with weird input,
	// just in case we don't handle something is a simple
	// catch all.
	//
	__try {
		//
		// Open the registry key.
		//
		internalStatus = ObOpenObjectByPointer(KeyObject, OBJ_KERNEL_HANDLE, NULL, GENERIC_ALL, *CmKeyObjectType, KernelMode, &keyHandle);
		if (NT_SUCCESS(internalStatus) == FALSE)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to open a handle to a key object with status 0x%X.", internalStatus);
			goto Exit;
		}

		ZwQueryKey(keyHandle, KeyNameInformation, NULL, 0, &returnLength);
		if (returnLength == 0)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to determine size of key name.");
			goto Exit;
		}

		returnLength += 1; // For null terminator.
		pKeyNameInformation = RCAST<PKEY_NAME_INFORMATION>(ExAllocatePoolWithTag(PagedPool, returnLength, REGISTRY_KEY_NAME_TAG));
		if (pKeyNameInformation == NULL)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to allocate memory for key name with size 0x%X.", returnLength);
			goto Exit;
		}

		//
		// Query the name information of the key to retrieve its name.
		//
		internalStatus = ZwQueryKey(keyHandle, KeyNameInformation, pKeyNameInformation, returnLength, &returnLength);
		if (NT_SUCCESS(internalStatus) == FALSE)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to query name of key object with status 0x%X.", internalStatus);
			goto Exit;
		}

		//
		// Allocate space for key name, a backslash, the value name, and the null-terminator.
		//
		fullKeyValueLength = pKeyNameInformation->NameLength + 2 + ValueName->Length + 1000;
		fullKeyValueName = RCAST<PWCHAR>(ExAllocatePoolWithTag(NonPagedPoolNx, fullKeyValueLength, REGISTRY_KEY_NAME_TAG));
		if (fullKeyValueName == NULL)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to allocate memory for full key/value name with size 0x%X.", fullKeyValueLength);
			goto Exit;
		}

		//
		// Copy the key name.
		//
		internalStatus = RtlStringCbCopyNW(fullKeyValueName, fullKeyValueLength, RCAST<PCWSTR>(&pKeyNameInformation->Name), pKeyNameInformation->NameLength);
		if (NT_SUCCESS(internalStatus) == FALSE)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to copy key name with status 0x%X.", internalStatus);
			goto Exit;
		}

		//
		// Concatenate the backslash.
		//
		internalStatus = RtlStringCbCatW(fullKeyValueName, fullKeyValueLength, L"\\");
		if (NT_SUCCESS(internalStatus) == FALSE)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to concatenate backslash with status 0x%X.", internalStatus);
			goto Exit;
		}

		//
		// Concatenate the value name.
		//
		internalStatus = RtlStringCbCatNW(fullKeyValueName, fullKeyValueLength, ValueName->Buffer, ValueName->Length);
		if (NT_SUCCESS(internalStatus) == FALSE)
		{
			DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Failed to concatenate value name with status 0x%X.", internalStatus);
			goto Exit;
		}

		blockOperation = RegistryBlockingFilter::RegistryStringFilters->MatchesFilter(fullKeyValueName, OperationFlag);

		//DBGPRINT("RegistryBlockingFilter!BlockRegistryOperation: Full name: %S.", fullKeyValueName);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{}

	if (blockOperation)
	{
		//
		// Grab the caller's path.
		//
		ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);

		//
		// Walk the stack.
		//
		RegistryBlockingFilter::walker.WalkAndResolveStack(&registryOperationStack, &registryOperationStackSize, STACK_HISTORY_TAG);

		NT_ASSERT(registryOperationStack);

		//
		// Only if we successfully walked the stack, report the violation.
		//
		if (registryOperationStack != NULL && registryOperationStackSize != 0)
		{
			//
			// Convert the registry path to a unicode string.
			//
			RtlInitUnicodeString(&registryOperationPath, fullKeyValueName);

			//
			// Report the violation.
			//
			RegistryBlockingFilter::detector->ReportFilterViolation(RegistryFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &registryOperationPath, registryOperationStack, registryOperationStackSize);

			//
			// Clean up.
			//
			ExFreePoolWithTag(registryOperationStack, STACK_HISTORY_TAG);
		}

		ExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);
	}
Exit:
	if (tempValueName)
	{
		ExFreePoolWithTag(tempValueName, REGISTRY_KEY_NAME_TAG);
	}
	if (fullKeyValueName)
	{
		ExFreePoolWithTag(fullKeyValueName, REGISTRY_KEY_NAME_TAG);
	}
	if (pKeyNameInformation)
	{
		ExFreePoolWithTag(pKeyNameInformation, REGISTRY_KEY_NAME_TAG);
	}
	if (keyHandle)
	{
		ZwClose(keyHandle);
	}
	return blockOperation;
}

/**
	The callback for registry operations. If necessary, blocks certain operations on protected keys/values.
	@param CallbackContext - Unreferenced parameter.
	@param OperationClass - The type of registry operation.
	@param Argument2 - A pointer to the structure associated with the operation.
	@return The status of the registry operation.
*/
NTSTATUS RegistryBlockingFilter::RegistryCallback (
	_In_ PVOID CallbackContext,
	_In_ REG_NOTIFY_CLASS OperationClass, 
	_In_ PVOID Argument2
	)
{
	UNREFERENCED_PARAMETER(CallbackContext);
	NTSTATUS returnStatus;
	PREG_SET_VALUE_KEY_INFORMATION setValueInformation;
	PREG_DELETE_VALUE_KEY_INFORMATION deleteValueInformation;

	returnStatus = STATUS_SUCCESS;

	//
	// PeaceMaker is not designed to block kernel operations.
	//
	if (ExGetPreviousMode() != KernelMode)
	{
		switch (OperationClass)
		{
		case RegNtPreSetValueKey:
			setValueInformation = RCAST<PREG_SET_VALUE_KEY_INFORMATION>(Argument2);
			if (BlockRegistryOperation(setValueInformation->Object, setValueInformation->ValueName, FILTER_FLAG_WRITE))
			{
				DBGPRINT("RegistryBlockingFilter!RegistryCallback: Detected RegNtPreSetValueKey of %wZ. Prevented set!", setValueInformation->ValueName);
				returnStatus = STATUS_ACCESS_DENIED;
			}
			break;
		case RegNtPreDeleteValueKey:
			deleteValueInformation = RCAST<PREG_DELETE_VALUE_KEY_INFORMATION>(Argument2);
			if (BlockRegistryOperation(deleteValueInformation->Object, deleteValueInformation->ValueName, FILTER_FLAG_DELETE))
			{
				DBGPRINT("RegistryBlockingFilter!RegistryCallback: Detected RegNtPreDeleteValueKey of %wZ. Prevented rewrite!", deleteValueInformation->ValueName);
				returnStatus = STATUS_ACCESS_DENIED;
			}
			break;
		}
	}

	return returnStatus;
}

================================================
FILE: PeaceMaker Kernel/RegistryFilter.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "StringFilters.h"
#include "StackWalker.h"
#include "DetectionLogic.h"
#include "ImageHistoryFilter.h"

typedef class RegistryBlockingFilter
{
	static BOOLEAN BlockRegistryOperation(_In_ PVOID KeyObject,
										  _In_ PUNICODE_STRING ValueName,
										  _In_ ULONG OperationFlag
										  );

	static NTSTATUS RegistryCallback(_In_ PVOID CallbackContext,
									 _In_ REG_NOTIFY_CLASS OperationClass,
									 _In_ PVOID Argument2
									);

	//
	// Contains strings to block various registry operations.
	//
	static PSTRING_FILTERS RegistryStringFilters;

	//
	// Cookie used to remove registry callback.
	//
	static LARGE_INTEGER RegistryFilterCookie;

	static STACK_WALKER walker;
	static PDETECTION_LOGIC detector;
public:
	RegistryBlockingFilter (
		_In_ PDRIVER_OBJECT DriverObject,
		_In_ PUNICODE_STRING RegistryPath,
		_In_ PDETECTION_LOGIC Detector,
		_Out_ NTSTATUS* Initialized
		);
	~RegistryBlockingFilter();

	static PSTRING_FILTERS GetStringFilters();
} REGISTRY_BLOCKING_FILTER, *PREGISTRY_BLOCKING_FILTER;

#define STRING_REGISTRY_FILTERS_TAG 'rFmP'
#define REGISTRY_KEY_NAME_TAG 'nKmP'

================================================
FILE: PeaceMaker Kernel/StackWalker.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "StackWalker.h"

/**
	Search the current process to see if any modules contain the address.
	@param Address - The address to search for.
	@param StackReturnInfo - The structure to be populated.
*/
VOID
StackWalker::ResolveAddressModule (
	_In_ PVOID Address,
	_Inout_ PSTACK_RETURN_INFO StackReturnInfo
	)
{
	NTSTATUS status;
	MEMORY_BASIC_INFORMATION meminfo;
	SIZE_T returnLength;
	SIZE_T mappedFilenameLength;
	PUNICODE_STRING mappedFilename;

	mappedFilenameLength = sizeof(UNICODE_STRING) + MAX_PATH * 2;

	//
	// Query the virtual memory to see if it's part of an image.
	//
	status = ZwQueryVirtualMemory(NtCurrentProcess(), Address, MemoryBasicInformation, &meminfo, sizeof(meminfo), &returnLength);
	if (NT_SUCCESS(status) && meminfo.Type == MEM_IMAGE)
	{
		StackReturnInfo->MemoryInModule = TRUE;
		StackReturnInfo->BinaryOffset = RCAST<ULONG64>(Address) - RCAST<ULONG64>(meminfo.AllocationBase);

		//
		// Allocate the filename.
		//
		mappedFilename = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, mappedFilenameLength, STACK_WALK_MAPPED_NAME));
		if (mappedFilename == NULL)
		{
			DBGPRINT("StackWalker!ResolveAddressModule: Failed to allocate module name.");
			return;
		}

		//
		// Query the filename.
		//
		status = ZwQueryVirtualMemory(NtCurrentProcess(), Address, SCAST<MEMORY_INFORMATION_CLASS>(MemoryMappedFilenameInformation), mappedFilename, mappedFilenameLength, &mappedFilenameLength);
		if (status == STATUS_BUFFER_OVERFLOW)
		{
			//
			// If we don't have a large enough buffer, allocate one!
			//
			ExFreePoolWithTag(mappedFilename, STACK_WALK_MAPPED_NAME);
			mappedFilename = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, mappedFilenameLength, STACK_WALK_MAPPED_NAME));
			if (mappedFilename == NULL)
			{
				DBGPRINT("StackWalker!ResolveAddressModule: Failed to allocate module name.");
				return;
			}
			status = ZwQueryVirtualMemory(NtCurrentProcess(), Address, SCAST<MEMORY_INFORMATION_CLASS>(MemoryMappedFilenameInformation), mappedFilename, mappedFilenameLength, &mappedFilenameLength);
		}

		if (NT_SUCCESS(status) == FALSE)
		{
			DBGPRINT("StackWalker!ResolveAddressModule: Failed to query memory module name with status 0x%X.", status);
			return;
		}

		//
		// Copy the mapped name.
		//
		RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(&StackReturnInfo->BinaryPath), sizeof(StackReturnInfo->BinaryPath), mappedFilename);

		ExFreePoolWithTag(mappedFilename, STACK_WALK_MAPPED_NAME);
	}
}

/**
	Check if the memory pointed by address is executable.
	@param Address - The address to check.
	@return Whether or not the memory is executable.
*/
BOOLEAN
StackWalker::IsAddressExecutable (
	_In_ PVOID Address
	)
{
	NTSTATUS status;
	MEMORY_BASIC_INFORMATION memoryBasicInformation;
	BOOLEAN executable;

	executable = FALSE;
	memset(&memoryBasicInformation, 0, sizeof(memoryBasicInformation));

	//
	// Query the basic information about the memory.
	//
	status = ZwQueryVirtualMemory(NtCurrentProcess(), Address, MemoryBasicInformation, &memoryBasicInformation, sizeof(memoryBasicInformation), NULL);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("StackWalker!IsAddressExecutable: Failed to query virtual memory for address 0x%llx with status 0x%X.", RCAST<ULONG64>(Address), status);
		goto Exit;
	}

	//
	// Check if the protection flags specifies executable.
	//
	executable = FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE) ||
				 FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE_READ) ||
				 FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE_READWRITE) ||
				 FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE_WRITECOPY);
Exit:
	return NT_SUCCESS(status) && executable;
}

/**
	Walk the stack of the current thread and resolve the module associated with the return addresses.
	@param ResolvedStack - Caller-supplied array of return address information that this function populates.
	@param ResolvedStackSize - The number of return addresses to resolve.
	@param ResolvedStackTag - The tag to allocate ResolvedStack with.
*/
VOID
StackWalker::WalkAndResolveStack (
	_Inout_ PSTACK_RETURN_INFO* ResolvedStack,
	_Inout_ ULONG* ResolvedStackSize,
	_In_ ULONG ResolvedStackTag
	)
{
	PVOID* stackReturnPtrs;
	ULONG capturedReturnPtrs;
	ULONG i;
	
	capturedReturnPtrs = 0;
	*ResolvedStack = NULL;

	//
	// Allocate space for the return addresses.
	//
	stackReturnPtrs = RCAST<PVOID*>(ExAllocatePoolWithTag(PagedPool, sizeof(PVOID) * *ResolvedStackSize, STACK_WALK_ARRAY_TAG));
	if (stackReturnPtrs == NULL)
	{
		DBGPRINT("StackWalker!WalkAndResolveStack: Failed to allocate space for temporary stack array.");
		goto Exit;
	}

	memset(stackReturnPtrs, 0, sizeof(PVOID) * *ResolvedStackSize);

	//
	// Get the return addresses leading up to this call.
	//
	capturedReturnPtrs = RtlWalkFrameChain(stackReturnPtrs, *ResolvedStackSize, 1);
	if (capturedReturnPtrs == 0)
	{
		DBGPRINT("StackWalker!WalkAndResolveStack: Failed to walk the stack.");
		goto Exit;
	}

	NT_ASSERT(capturedReturnPtrs < ResolvedStackSize);

	*ResolvedStackSize = capturedReturnPtrs;

	//
	// Allocate space for the stack return info array.
	//
	*ResolvedStack = RCAST<PSTACK_RETURN_INFO>(ExAllocatePoolWithTag(PagedPool, sizeof(STACK_RETURN_INFO) * *ResolvedStackSize, ResolvedStackTag));
	if (*ResolvedStack == NULL)
	{
		DBGPRINT("StackWalker!WalkAndResolveStack: Failed to allocate space for stack info array.");
		goto Exit;
	}
	memset(*ResolvedStack, 0, sizeof(STACK_RETURN_INFO) * *ResolvedStackSize);


	//
	// Iterate each return address and fill out the struct.
	//
	for (i = 0; i < capturedReturnPtrs; i++)
	{
		(*ResolvedStack)[i].RawAddress = stackReturnPtrs[i];

		//
		// If the memory isn't executable or is in kernel, it's not worth our time.
		//
		if (RCAST<ULONG64>(stackReturnPtrs[i]) < MmUserProbeAddress && this->IsAddressExecutable(stackReturnPtrs[i]))
		{
			(*ResolvedStack)[i].ExecutableMemory = TRUE;
			this->ResolveAddressModule(stackReturnPtrs[i], &(*ResolvedStack)[i]);
		}
	}
Exit:
	if (stackReturnPtrs)
	{
		ExFreePoolWithTag(stackReturnPtrs, STACK_WALK_ARRAY_TAG);
	}
}

================================================
FILE: PeaceMaker Kernel/StackWalker.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "shared.h"

typedef class StackWalker
{
	BOOLEAN IsAddressExecutable (
		_In_ PVOID Address
		);

public:
	StackWalker() {};
	
	VOID WalkAndResolveStack (
		_Inout_ PSTACK_RETURN_INFO* ResolvedStack,
		_Inout_ ULONG* ResolvedStackSize,
		_In_ ULONG ResolvedStackTag
		);

	VOID ResolveAddressModule (
		_In_ PVOID Address,
		_Inout_ PSTACK_RETURN_INFO StackReturnInfo
		);
} STACK_WALKER, *PSTACK_WALKER;

#define STACK_WALK_ARRAY_TAG 'aSmP'
#define STACK_WALK_MAPPED_NAME 'nMmP'

================================================
FILE: PeaceMaker Kernel/StringFilters.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "StringFilters.h"

/**
	Initialize the CUSTOM_FILTERS class by initializing the linked list's lock.
	@param Type - The type of filter to add (filesystem or registry).
	@param RegistryPath - The registry path of the driver.
	@param FilterStoreName - Name of the filter store.
*/
StringFilters::StringFilters (
	_In_ STRING_FILTER_TYPE FilterType,
	_In_ PUNICODE_STRING RegistryPath,
	_In_ CONST WCHAR* FilterStoreName
	)
{
	//
	// Initialize the lock for the filters.
	//
	FltInitializePushLock(&this->filtersLock);

	this->filtersHead = RCAST<PFILTER_INFO_LINKED>(ExAllocatePoolWithTag(NonPagedPool, sizeof(FILTER_INFO_LINKED), FILTER_INFO_TAG));
	InitializeListHead(RCAST<PLIST_ENTRY>(this->filtersHead));
	this->destroying = FALSE;

	this->filtersCount = 0;
	this->filterType = FilterType;

	//
	// Initialize space for the driver registry key.
	//
	this->driverRegistryPath.Buffer = RCAST<PWCH>(ExAllocatePoolWithTag(NonPagedPool, RegistryPath->MaximumLength, FILTER_INFO_TAG));
	this->driverRegistryPath.MaximumLength = RegistryPath->MaximumLength;
	RtlCopyUnicodeString(&this->driverRegistryPath, RegistryPath);

	RtlInitUnicodeString(&this->filterStoreValueName, FilterStoreName);
}

/**
	Destroy the CustomFilters class by clearing the filters linked list and deleting the associated lock.
*/
StringFilters::~StringFilters()
{
	PLIST_ENTRY currentFilter;

	//
	// Set destroying to TRUE so that no other threads can get a lock.
	//
	this->destroying = TRUE;

	//
	// Acquire an exclusive lock to push out other threads.
	//
	FltAcquirePushLockExclusive(&this->filtersLock);

	//
	// Release the lock.
	//
	FltReleasePushLock(&this->filtersLock);

	//
	// Delete the lock for the filters.
	//
	FltDeletePushLock(&this->filtersLock);

	//
	// Go through each filter and free it.
	//
	if (this->filtersHead)
	{
		while (IsListEmpty(RCAST<PLIST_ENTRY>(this->filtersHead)) == FALSE)
		{
			currentFilter = RemoveHeadList(RCAST<PLIST_ENTRY>(this->filtersHead));
			//
			// Free the filter.
			//
			ExFreePoolWithTag(SCAST<PVOID>(currentFilter), FILTER_INFO_TAG);
		}

		//
		// Finally, free the list head.
		//
		ExFreePoolWithTag(SCAST<PVOID>(this->filtersHead), FILTER_INFO_TAG);
	}

	//
	// Free the driver registy path.
	//
	ExFreePoolWithTag(this->driverRegistryPath.Buffer, FILTER_INFO_TAG);
}

/**
	Add a filter to the linked list of filters.
	@param MatchString - The string to filter with.
	@param OperationFlag - Specifies what operations this filter should be used for.
	@param SaveFilters - Whether or not to save filters.
	@return A random identifier required for future operations with the new filter.
*/
ULONG
StringFilters::AddFilter (
	_In_ WCHAR* MatchString,
	_In_ ULONG OperationFlag,
	_In_ BOOLEAN SaveFilters
	)
{
	PFILTER_INFO_LINKED newFilter;
	LARGE_INTEGER currentTime;
	ULONG epochSeconds;

	if (this == NULL || this->destroying)
	{
		return NULL;
	}

	//
	// Get an exclusive lock because we're modifying the filters linked list.
	//
	FltAcquirePushLockExclusive(&this->filtersLock);

	//
	// Allocate space for the new filter.
	//
	newFilter = RCAST<PFILTER_INFO_LINKED>(ExAllocatePoolWithTag(NonPagedPool, sizeof(FILTER_INFO_LINKED), FILTER_INFO_TAG));
	if (newFilter == NULL)
	{
		DBGPRINT("Failed to allocate space for filter info.");
		goto Exit;
	}

	memset(RCAST<PVOID>(newFilter), 0, sizeof(FILTER_INFO_LINKED));

	InsertTailList(RCAST<PLIST_ENTRY>(this->filtersHead), RCAST<PLIST_ENTRY>(newFilter));

	this->filtersCount++;

	//
	// Generate a pseudo-random ID for the filter using the system time.
	//
	KeQuerySystemTime(&currentTime);
	RtlTimeToSecondsSince1970(&currentTime, &epochSeconds);
	newFilter->Filter.Id = RtlRandomEx(&epochSeconds);
	newFilter->Filter.Type = this->filterType;

	//
	// Copy the filter string to the new filter.
	//
	wcsncpy_s(newFilter->Filter.MatchString, MatchString, MAX_PATH);

	//
	// Set the operation flags for this filter.
	//
	newFilter->Filter.Flags = OperationFlag;
Exit:
	//
	// New filter has been initialized, release the lock.
	//
	FltReleasePushLock(&this->filtersLock);
	if (SaveFilters)
	{
		this->SaveFilters();
	}

	if (newFilter)
	{
		return newFilter->Filter.Id;
	}

	//
	// The ID cannot be 0 because we add 1.
	//
	return NULL;
}

/**
	Remove a filter from the linked list of filters.
	@param FilterId - The unique filter ID of the filter to delete.
	@return Whether or not deletion was successful.
*/
BOOLEAN
StringFilters::RemoveFilter (
	_In_ ULONG FilterId
	)
{
	BOOLEAN filterDeleted;
	PFILTER_INFO_LINKED currentFilter;

	currentFilter = NULL;
	filterDeleted = FALSE;

	if (this == NULL || this->destroying)
	{
		return FALSE;
	}

	//
	// Get an exclusive lock because we're modifying the filters linked list.
	//
	FltAcquirePushLockExclusive(&this->filtersLock);

	//
	// Check if we have a single filter already.
	//
	if (this->filtersHead)
	{
		currentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);

		while (currentFilter && currentFilter != this->filtersHead)
		{
			if (currentFilter->Filter.Id == FilterId)
			{
				break;
			}
			currentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);
		}
		
		//
		// Remove the entry from the list.
		//
		if (currentFilter && currentFilter != this->filtersHead)
		{
			RemoveEntryList(RCAST<PLIST_ENTRY>(currentFilter));
			filterDeleted = TRUE;
			this->filtersCount--;
			//
			// Free the filter.
			//
			ExFreePoolWithTag(SCAST<PVOID>(currentFilter), FILTER_INFO_TAG);
		}
	}

	//
	// Release the lock.
	//
	FltReleasePushLock(&this->filtersLock);

	if (filterDeleted)
	{
		this->SaveFilters();
	}

	return filterDeleted;
}

/**
	Check if a string contains any filtered phrases.
	@param StrToCmp - The string to search.
	@param OperationFlag - Specify FILTER_FLAG_X's to match certain filters for a variety of operations.
	@return Whether or not there was a filter that matched.
*/
BOOLEAN
StringFilters::MatchesFilter (
	_In_ WCHAR* StrToCmp,
	_In_ ULONG OperationFlag
	)
{
	BOOLEAN filterMatched;
	PFILTER_INFO_LINKED currentFilter;
	WCHAR tempStrToCmp[MAX_PATH];
	INT i;

	if (this == NULL || this->destroying)
	{
		return FALSE;
	}

	filterMatched = FALSE;

	//
	// Copy the string to compare so we don't modify the original string.
	//
	wcsncpy_s(tempStrToCmp, StrToCmp, MAX_PATH);

	//
	// Make the input string lowercase.
	//
	i = 0;
	while (tempStrToCmp[i])
	{
		tempStrToCmp[i] = towlower(tempStrToCmp[i]);
		i++;
	}

	//
	// Acquire a shared lock to iterate filters.
	//
	FltAcquirePushLockShared(&this->filtersLock);

	//
	// Iterate filters for a match.
	//
	if (this->filtersHead)
	{
		currentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);
		while (currentFilter && currentFilter != this->filtersHead)
		{
			//
			// Check if the string to compare contains the filter.
			//
			if ((currentFilter->Filter.Flags & OperationFlag) &&
				(wcsstr(RCAST<CONST WCHAR*>(&tempStrToCmp), RCAST<CONST WCHAR*>(&currentFilter->Filter.MatchString)) != NULL))
			{
				filterMatched = TRUE;
				goto Exit;
			}
			currentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);
		}
	}
Exit:
	FltReleasePushLock(&this->filtersLock);
	return filterMatched;
}

/**
	Get the filters present in the linked-list.
	@param SkipFilters - The number of filters to skip.
	@param Filters - The output array.
	@param FilterSize - Maximum number of filters.
	@return The number of filters copied.
*/
ULONG
StringFilters::GetFilters (
	_In_ ULONG SkipFilters,
	_Inout_ PFILTER_INFO Filters,
	_In_ ULONG FiltersSize
	)
{
	PFILTER_INFO_LINKED currentFilter;
	ULONG skipCount;
	ULONG copyCount;

	skipCount = 0;
	copyCount = 0;

	//
	// Acquire a shared lock to iterate filters.
	//
	FltAcquirePushLockShared(&this->filtersLock);

	//
	// Iterate filters for a match.
	//
	if (this->filtersHead)
	{
		currentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);
		while (currentFilter && currentFilter != this->filtersHead && copyCount < FiltersSize)
		{
			if (skipCount >= SkipFilters)
			{
				memcpy_s(&Filters[copyCount], sizeof(FILTER_INFO), &currentFilter->Filter, sizeof(FILTER_INFO));
				DBGPRINT("StringFilters!GetFilters: Copying filter ID 0x%X.", currentFilter->Filter.Id);
				copyCount++;
			}
			skipCount++;
			currentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);
		}
	}

	FltReleasePushLock(&this->filtersLock);

	return copyCount;
}

/**
	Save the current filters to the registry for persistence.
	@return Whether or not the save was successful.
*/
BOOLEAN
StringFilters::SaveFilters (
	VOID
	)
{
	PFILTER_STORE filterStore;
	PFILTER_INFO_LINKED currentFilter;
	ULONG i;
	OBJECT_ATTRIBUTES driverRegistryAttributes;
	NTSTATUS status;
	HANDLE driverRegistryKey;
	BOOLEAN result;

	result = FALSE;
	driverRegistryKey = NULL;
	i = 0;

	//
	// Allocate space for the filter store.
	//
	filterStore = RCAST<PFILTER_STORE>(ExAllocatePoolWithTag(NonPagedPool, FILTER_STORE_SIZE(this->filtersCount), FILTER_INFO_TAG));
	if (filterStore == NULL)
	{
		DBGPRINT("StringFilters!SaveFilters: Failed to allocate space for the filter store with size %i.", this->filtersCount);
		goto Exit;
	}
	memset(filterStore, 0, sizeof(filterStore));

	//
	// Initialize basic members.
	//
	filterStore->FilterCount = this->filtersCount;

	//
	// Acquire a shared lock to iterate filters.
	//
	FltAcquirePushLockShared(&this->filtersLock);

	//
	// Iterate filters for a match.
	//
	if (this->filtersHead)
	{
		currentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);
		while (currentFilter && currentFilter != this->filtersHead)
		{
			memcpy_s(&filterStore->Filters[i], sizeof(FILTER_INFO), &currentFilter->Filter, sizeof(FILTER_INFO));
			i++;
			currentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);
		}
	}

	FltReleasePushLock(&this->filtersLock);

	//
	// Open the driver's registry key.
	//
	InitializeObjectAttributes(&driverRegistryAttributes, &this->driverRegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	status = ZwOpenKey(&driverRegistryKey, KEY_ALL_ACCESS, &driverRegistryAttributes);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("StringFilters!SaveFilters: Failed to open driver registry key with status 0x%X.", status);
		goto Exit;
	}

	//
	// Write the current filters.
	//
	status = ZwSetValueKey(driverRegistryKey, &this->filterStoreValueName, 0, REG_BINARY, filterStore, FILTER_STORE_SIZE(this->filtersCount));
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("StringFilters!SaveFilters: Failed to write filter store to driver registry key with status 0x%X.", status);
		goto Exit;
	}
	result = TRUE;
Exit:
	if (filterStore)
	{
		ExFreePoolWithTag(filterStore, FILTER_INFO_TAG);
	}
	if (driverRegistryKey)
	{
		ZwClose(driverRegistryKey);
	}
	return result;
}

/**
	Restore filters from the registry.
	@return Whether or not the restoration was successful.
*/
BOOLEAN
StringFilters::RestoreFilters (
	VOID
	)
{
	OBJECT_ATTRIBUTES driverRegistryAttributes;
	NTSTATUS status;
	HANDLE driverRegistryKey;
	ULONG filterStorePartialSize;
	PFILTER_STORE filterStore;
	PKEY_VALUE_PARTIAL_INFORMATION filterStorePartial;
	ULONG i;
	BOOLEAN result;

	result = FALSE;
	i = 0;
	filterStorePartial = NULL;
	filterStore = NULL;

	//
	// Open the driver's registry key.
	//
	InitializeObjectAttributes(&driverRegistryAttributes, &this->driverRegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	status = ZwOpenKey(&driverRegistryKey, KEY_ALL_ACCESS, &driverRegistryAttributes);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("StringFilters!RestoreFilters: Failed to open driver registry key with status 0x%X.", status);
		goto Exit;
	}
	
	//
	// Read the size of the FilterStore.
	//
	status = ZwQueryValueKey(driverRegistryKey, &this->filterStoreValueName, KeyValuePartialInformation, NULL, 0, &filterStorePartialSize);
	if (status != STATUS_BUFFER_TOO_SMALL)
	{
		DBGPRINT("StringFilters!RestoreFilters: Failed to query filter store size with status 0x%X.", status);
		goto Exit;
	}
	
	//
	// Allocate space for the FilterStore partial struct and query the actual value.
	//
	filterStorePartial = RCAST<PKEY_VALUE_PARTIAL_INFORMATION>(ExAllocatePoolWithTag(NonPagedPool, filterStorePartialSize, FILTER_INFO_TAG));
	status = ZwQueryValueKey(driverRegistryKey, &this->filterStoreValueName, KeyValuePartialInformation, filterStorePartial, filterStorePartialSize, &filterStorePartialSize);
	if (NT_SUCCESS(status) == FALSE)
	{
		DBGPRINT("StringFilters!RestoreFilters: Failed to query filter store with status 0x%X.", status);
		goto Exit;
	}
	
	//
	// Grab the filter store from the data member of the partial struct.
	//
	filterStore = RCAST<PFILTER_STORE>(filterStorePartial->Data);

	//
	// Add the filters.
	//
	for (i = 0; i < filterStore->FilterCount; i++)
	{
		this->AddFilter(filterStore->Filters[i].MatchString, filterStore->Filters[i].Flags, FALSE);
	}
	result = TRUE;
Exit:
	if (driverRegistryKey)
	{
		ZwClose(driverRegistryKey);
	}
	if (filterStorePartial)
	{
		ExFreePoolWithTag(filterStorePartial, FILTER_INFO_TAG);
	}
	return result;
}

================================================
FILE: PeaceMaker Kernel/StringFilters.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "shared.h"

typedef struct FilterInfoLinked
{
	LIST_ENTRY ListEntry;	// The list entry used to iterate multiple filters.
	FILTER_INFO Filter;		// The filter itself.
} FILTER_INFO_LINKED, *PFILTER_INFO_LINKED;

typedef struct FilterStore
{
	ULONG FilterCount;		// Number of filters in the following array.
	FILTER_INFO Filters[1];	// Dynamically-sized array based on FilterCount member.
} FILTER_STORE, *PFILTER_STORE;

#define FILTER_STORE_SIZE(filterCount) sizeof(FILTER_STORE) + (sizeof(FILTER_INFO) * (filterCount - 1))

typedef class StringFilters
{
	PFILTER_INFO_LINKED filtersHead; // The linked list of filters.
	EX_PUSH_LOCK filtersLock; // The lock protecting the linked list of filters.
	BOOLEAN destroying; // This boolean indicates to functions that a lock should not be held as we are in the process of destruction.
	UNICODE_STRING driverRegistryPath; // Used for filter persistence across reboots.
	UNICODE_STRING filterStoreValueName; // Used for filter persistence across reboots.
	STRING_FILTER_TYPE filterType; // What type of filter this class stores.
public:
	StringFilters(
		_In_ STRING_FILTER_TYPE FilterType,
		_In_ PUNICODE_STRING RegistryPath,
		_In_ CONST WCHAR* FilterStoreName
		);
	~StringFilters();

	ULONG AddFilter(
		_In_ WCHAR* MatchString,
		_In_ ULONG OperationFlag,
		_In_ BOOLEAN SaveFilters = TRUE
		);
	BOOLEAN RemoveFilter(
		_In_ ULONG FilterId
		);
	ULONG GetFilters(
		_In_ ULONG SkipFilters,
		_Inout_ PFILTER_INFO Filters,
		_In_ ULONG FiltersSize
		);

	BOOLEAN MatchesFilter(
		_In_ WCHAR* StrToCmp,
		_In_ ULONG OperationFlag
		);

	BOOLEAN SaveFilters(
		VOID
		);

	BOOLEAN RestoreFilters(
		VOID
		);

	ULONG filtersCount;	// Count of filters in the linked-list.
} STRING_FILTERS, *PSTRING_FILTERS;

#define FILTER_INFO_TAG 'iFmP'

================================================
FILE: PeaceMaker Kernel/TamperGuard.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "TamperGuard.h"

HANDLE TamperGuard::ProtectedProcessId;

/**
	Initialize tamper protection. This constructor will create appropriate callbacks.
	@param InitializeStatus - Status of initialization.
*/
TamperGuard::TamperGuard (
	_Out_ NTSTATUS* InitializeStatus
	)
{
	UNICODE_STRING CallbackAltitude;

	RtlInitUnicodeString(&CallbackAltitude, FILTER_ALTITUDE);

	ObRegistrationInformation.Version = OB_FLT_REGISTRATION_VERSION;
	ObRegistrationInformation.OperationRegistrationCount = 2;
	ObRegistrationInformation.Altitude = CallbackAltitude;
	ObRegistrationInformation.RegistrationContext = NULL;
	ObRegistrationInformation.OperationRegistration = ObOperationRegistration;

	//
	// We want to protect both the process and the threads of the protected process.
	//
	ObOperationRegistration[0].ObjectType = PsProcessType;
	ObOperationRegistration[0].Operations |= OB_OPERATION_HANDLE_CREATE;
	ObOperationRegistration[0].Operations |= OB_OPERATION_HANDLE_DUPLICATE;
	ObOperationRegistration[0].PreOperation = PreOperationCallback;

	ObOperationRegistration[1].ObjectType = PsThreadType;
	ObOperationRegistration[1].Operations |= OB_OPERATION_HANDLE_CREATE;
	ObOperationRegistration[1].Operations |= OB_OPERATION_HANDLE_DUPLICATE;
	ObOperationRegistration[1].PreOperation = PreOperationCallback;

	//
	// Actually register the callbacks.
	//
	*InitializeStatus = ObRegisterCallbacks(&ObRegistrationInformation, &RegistrationHandle);
	if (NT_SUCCESS(*InitializeStatus) == FALSE)
	{
		DBGPRINT("TamperGuard!TamperGuard: Failed to register object callbacks with status 0x%X.", *InitializeStatus);
	}
}

/**
	Destruct tamper guard members.
*/
TamperGuard::~TamperGuard (
	VOID
	)
{
	ObUnRegisterCallbacks(RegistrationHandle);
}

/**
	Update the process to protect.
	@param NewProcessId - The new process to protect from tampering.
*/
VOID
TamperGuard::UpdateProtectedProcess (
	_In_ HANDLE NewProcessId
	)
{
	TamperGuard::ProtectedProcessId = NewProcessId;
}

/**
	Filter for certain operations on a protected process.
	@param RegistrationContext - Always NULL.
	@param OperationInformation - Information about the current operation.
*/
OB_PREOP_CALLBACK_STATUS
TamperGuard::PreOperationCallback (
	_In_ PVOID RegistrationContext,
	_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
	)
{
	HANDLE callerProcessId;
	HANDLE targetProcessId;
	ACCESS_MASK targetAccessMask;

	UNREFERENCED_PARAMETER(RegistrationContext);

	callerProcessId = NULL;
	targetProcessId = NULL;
	targetAccessMask = NULL;
	callerProcessId = PsGetCurrentProcessId();

	//
	// Grab the appropriate process IDs based on the operation object type.
	//
	if (OperationInformation->ObjectType == *PsProcessType)
	{
		targetProcessId = PsGetProcessId(RCAST<PEPROCESS>(OperationInformation->Object));
		targetAccessMask = PROCESS_TERMINATE;
	}
	else if (OperationInformation->ObjectType == *PsThreadType)
	{
		targetProcessId = PsGetThreadProcessId(RCAST<PETHREAD>(OperationInformation->Object));
		targetAccessMask = THREAD_TERMINATE;
	}

	//
	// If this is an operation on your own process, ignore it.
	//
	if (callerProcessId == targetProcessId)
	{
		return OB_PREOP_SUCCESS;
	}

	//
	// If the target process isn't the process we're protecting, no issue.
	//
	if (targetProcessId != TamperGuard::ProtectedProcessId)
	{
		return OB_PREOP_SUCCESS;
	}

	//
	// Strip the proper desired access ACCESS_MASK.
	//
	switch (OperationInformation->Operation)
	{
	case OB_OPERATION_HANDLE_CREATE:
		OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~targetAccessMask;
		break;
	case OB_OPERATION_HANDLE_DUPLICATE:
		OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~targetAccessMask;
		break;
	}

	DBGPRINT("TamperGuard!PreOperationCallback: Stripped process 0x%X terminate handle on protected process.", callerProcessId);

	return OB_PREOP_SUCCESS;
}

================================================
FILE: PeaceMaker Kernel/TamperGuard.h
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#pragma once
#include "common.h"
#include "shared.h"

typedef class TamperGuard
{
	static OB_PREOP_CALLBACK_STATUS PreOperationCallback(_In_ PVOID RegistrationContext,
														 _In_ POB_PRE_OPERATION_INFORMATION OperationInformation
														 );
	OB_CALLBACK_REGISTRATION ObRegistrationInformation;
	OB_OPERATION_REGISTRATION ObOperationRegistration[2];
	PVOID RegistrationHandle;

	static HANDLE ProtectedProcessId;
public:
	TamperGuard(_Out_ NTSTATUS* InitializeStatus
				);
	~TamperGuard(VOID);

	VOID UpdateProtectedProcess(_In_ HANDLE NewProcessId
								);
} TAMPER_GUARD, *PTAMPER_GUARD;

#define PROCESS_TERMINATE                  (0x0001)  
#define THREAD_TERMINATE                 (0x0001)  

================================================
FILE: PeaceMaker Kernel/ThreadFilter.cpp
================================================
/*
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 * 
 * COPYRIGHT Bill Demirkapi 2020
 */
#include "ThreadFilter.h"

PDETECTION_LOGIC ThreadFilter::Detector;	// Detection utility.
STACK_WALKER ThreadFilter::Walker;			// 
Download .txt
gitextract_zfage812/

├── .gitignore
├── LICENSE
├── PeaceMaker CLI/
│   ├── IOCTLCommunicationUser.cpp
│   ├── IOCTLCommunicationUser.h
│   ├── PeaceMaker CLI.cpp
│   ├── PeaceMaker CLI.vcxproj
│   └── PeaceMaker CLI.vcxproj.filters
├── PeaceMaker Kernel/
│   ├── AlertQueue.cpp
│   ├── AlertQueue.h
│   ├── DetectionLogic.cpp
│   ├── DetectionLogic.h
│   ├── FSFilter.cpp
│   ├── FSFilter.h
│   ├── FilterTesting.cpp
│   ├── IOCTLCommunication.cpp
│   ├── IOCTLCommunication.h
│   ├── ImageHistoryFilter.cpp
│   ├── ImageHistoryFilter.h
│   ├── PeaceMaker Kernel.inf
│   ├── PeaceMaker Kernel.rc
│   ├── PeaceMaker Kernel.vcxproj
│   ├── PeaceMaker Kernel.vcxproj.filters
│   ├── RCa19580
│   ├── RCa38200
│   ├── RegistryFilter.cpp
│   ├── RegistryFilter.h
│   ├── StackWalker.cpp
│   ├── StackWalker.h
│   ├── StringFilters.cpp
│   ├── StringFilters.h
│   ├── TamperGuard.cpp
│   ├── TamperGuard.h
│   ├── ThreadFilter.cpp
│   ├── ThreadFilter.h
│   ├── common.cpp
│   ├── common.h
│   ├── ntdef.h
│   └── shared.h
├── PeaceMaker Kernel.vcxproj
├── PeaceMaker.sln
├── PeaceMakerGUI/
│   ├── AssetResources.qrc
│   ├── ClickableTab.cpp
│   ├── ClickableTab.h
│   ├── InvestigateProcessWindow.cpp
│   ├── InvestigateProcessWindow.h
│   ├── InvestigateProcessWindow.ui
│   ├── PeaceMakerGUI.pro
│   ├── addfilterwindow.cpp
│   ├── addfilterwindow.h
│   ├── addfilterwindow.ui
│   ├── configparser.cpp
│   ├── configparser.h
│   ├── detailedalertwindow.cpp
│   ├── detailedalertwindow.h
│   ├── detailedalertwindow.ui
│   ├── main.cpp
│   ├── mainwindow.cpp
│   ├── mainwindow.h
│   └── mainwindow.ui
└── README.md
Download .txt
SYMBOL INDEX (126 symbols across 36 files)

FILE: PeaceMaker CLI/IOCTLCommunicationUser.cpp
  function BOOLEAN (line 33) | BOOLEAN
  function BOOLEAN (line 58) | BOOLEAN
  function BOOLEAN (line 75) | BOOLEAN
  function PBASE_ALERT_INFO (line 98) | PBASE_ALERT_INFO
  function PPROCESS_SUMMARY_REQUEST (line 137) | PPROCESS_SUMMARY_REQUEST
  function PPROCESS_DETAILED_REQUEST (line 184) | PPROCESS_DETAILED_REQUEST
  function ULONG (line 254) | ULONG
  function LIST_FILTERS_REQUEST (line 291) | LIST_FILTERS_REQUEST
  function PROCESS_SIZES_REQUEST (line 319) | PROCESS_SIZES_REQUEST
  function PIMAGE_DETAILED_REQUEST (line 348) | PIMAGE_DETAILED_REQUEST
  function GLOBAL_SIZES (line 395) | GLOBAL_SIZES
  function BOOLEAN (line 418) | BOOLEAN

FILE: PeaceMaker CLI/IOCTLCommunicationUser.h
  function class (line 12) | class IOCTLCommunication

FILE: PeaceMaker CLI/PeaceMaker CLI.cpp
  function VOID (line 17) | VOID
  function VOID (line 43) | VOID
  function main (line 98) | int main()

FILE: PeaceMaker Kernel/AlertQueue.cpp
  function VOID (line 54) | VOID
  function PBASE_ALERT_INFO (line 90) | PBASE_ALERT_INFO
  function BOOLEAN (line 106) | BOOLEAN
  function VOID (line 126) | VOID

FILE: PeaceMaker Kernel/AlertQueue.h
  type class (line 11) | typedef class AlertQueue

FILE: PeaceMaker Kernel/DetectionLogic.cpp
  function PALERT_QUEUE (line 30) | PALERT_QUEUE
  function VOID (line 47) | VOID
  function VOID (line 102) | VOID
  function VOID (line 173) | VOID
  function VOID (line 216) | VOID
  function VOID (line 302) | VOID

FILE: PeaceMaker Kernel/DetectionLogic.h
  type class (line 13) | typedef class DetectionLogic

FILE: PeaceMaker Kernel/FSFilter.cpp
  function PSTRING_FILTERS (line 113) | PSTRING_FILTERS FSBlockingFilter::GetStringFilters()
  function FLT_PREOP_CALLBACK_STATUS (line 124) | FLT_PREOP_CALLBACK_STATUS
  function FLT_PREOP_CALLBACK_STATUS (line 235) | FLT_PREOP_CALLBACK_STATUS
  function FLT_PREOP_CALLBACK_STATUS (line 326) | FLT_PREOP_CALLBACK_STATUS
  function NTSTATUS (line 422) | NTSTATUS
  function NTSTATUS (line 477) | NTSTATUS
  function VOID (line 494) | VOID
  function VOID (line 509) | VOID

FILE: PeaceMaker Kernel/FSFilter.h
  type class (line 13) | typedef class FSBlockingFilter

FILE: PeaceMaker Kernel/FilterTesting.cpp
  function NTSTATUS (line 52) | NTSTATUS
  function NTSTATUS (line 77) | NTSTATUS

FILE: PeaceMaker Kernel/IOCTLCommunication.cpp
  function NTSTATUS (line 132) | NTSTATUS
  function NTSTATUS (line 157) | NTSTATUS
  function NTSTATUS (line 505) | NTSTATUS
  function VOID (line 552) | VOID

FILE: PeaceMaker Kernel/IOCTLCommunication.h
  type class (line 16) | typedef class IOCTLCommunication

FILE: PeaceMaker Kernel/ImageHistoryFilter.cpp
  function VOID (line 189) | VOID
  function VOID (line 354) | VOID
  function VOID (line 403) | VOID
  function BOOLEAN (line 434) | BOOLEAN
  function VOID (line 517) | VOID
  function ULONG (line 680) | ULONG
  function VOID (line 753) | VOID
  function VOID (line 890) | VOID
  function BOOLEAN (line 935) | BOOLEAN
  function VOID (line 981) | VOID

FILE: PeaceMaker Kernel/ImageHistoryFilter.h
  type IMAGE_LOAD_HISTORY_ENTRY (line 19) | typedef struct ImageLoadHistoryEntry
  type PROCESS_HISTORY_ENTRY (line 30) | typedef struct ProcessHistoryEntry
  type class (line 58) | typedef class ImageHistoryFilter

FILE: PeaceMaker Kernel/RegistryFilter.cpp
  function PSTRING_FILTERS (line 79) | PSTRING_FILTERS RegistryBlockingFilter::GetStringFilters()
  function BOOLEAN (line 91) | BOOLEAN
  function NTSTATUS (line 286) | NTSTATUS RegistryBlockingFilter::RegistryCallback (

FILE: PeaceMaker Kernel/RegistryFilter.h
  type class (line 14) | typedef class RegistryBlockingFilter

FILE: PeaceMaker Kernel/StackWalker.cpp
  function VOID (line 14) | VOID
  function BOOLEAN (line 86) | BOOLEAN
  function VOID (line 125) | VOID

FILE: PeaceMaker Kernel/StackWalker.h
  type class (line 11) | typedef class StackWalker

FILE: PeaceMaker Kernel/StringFilters.cpp
  function ULONG (line 103) | ULONG
  function BOOLEAN (line 183) | BOOLEAN
  function BOOLEAN (line 254) | BOOLEAN
  function ULONG (line 324) | ULONG
  function BOOLEAN (line 371) | BOOLEAN
  function BOOLEAN (line 462) | BOOLEAN

FILE: PeaceMaker Kernel/StringFilters.h
  type FILTER_INFO_LINKED (line 11) | typedef struct FilterInfoLinked
  type FILTER_STORE (line 17) | typedef struct FilterStore
  type class (line 25) | typedef class StringFilters

FILE: PeaceMaker Kernel/TamperGuard.cpp
  function VOID (line 66) | VOID
  function OB_PREOP_CALLBACK_STATUS (line 79) | OB_PREOP_CALLBACK_STATUS

FILE: PeaceMaker Kernel/TamperGuard.h
  type class (line 11) | typedef class TamperGuard

FILE: PeaceMaker Kernel/ThreadFilter.cpp
  function PVOID (line 49) | PVOID
  function VOID (line 106) | VOID

FILE: PeaceMaker Kernel/ThreadFilter.h
  type class (line 13) | typedef class ThreadFilter

FILE: PeaceMaker Kernel/common.cpp
  function PPEB (line 26) | PPEB PsGetProcessPeb(IN PEPROCESS Process)
  function NTSTATUS (line 41) | NTSTATUS NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLAS...
  function NTSTATUS (line 56) | NTSTATUS NtQueryInformationThread(_In_ HANDLE ThreadHandle, _In_ THREADI...

FILE: PeaceMaker Kernel/ntdef.h
  type LDR_MODULE (line 12) | typedef struct _LDR_MODULE {
  type PEB_LDR_DATA (line 28) | typedef struct _PEB_LDR_DATA
  type PEB (line 39) | typedef struct _PEB
  type KNONVOLATILE_CONTEXT_POINTERS (line 128) | typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
  type SCOPE_TABLE_AMD64 (line 178) | typedef struct _SCOPE_TABLE_AMD64 {
  type RUNTIME_FUNCTION (line 188) | typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY RUNTIME_FUNCTION, * PRUNTIM...
  type SCOPE_TABLE_AMD64 (line 189) | typedef SCOPE_TABLE_AMD64 SCOPE_TABLE, * PSCOPE_TABLE;
  type UNWIND_HISTORY_TABLE_ENTRY (line 193) | typedef struct _UNWIND_HISTORY_TABLE_ENTRY {
  type UNWIND_HISTORY_TABLE (line 198) | typedef struct _UNWIND_HISTORY_TABLE {

FILE: PeaceMaker Kernel/shared.h
  type PROCESS_SUMMARY_ENTRY (line 40) | typedef struct ProcessSummaryEntry
  type STACK_RETURN_INFO (line 48) | typedef struct StackReturnInfo
  type PROCESS_SUMMARY_REQUEST (line 57) | typedef struct ProcessSummaryRequest
  type IMAGE_SUMMARY (line 67) | typedef struct ImageSummary
  type PROCESS_DETAILED_REQUEST (line 73) | typedef struct ProcessDetailedRequest
  type IMAGE_DETAILED_REQUEST (line 96) | typedef struct ImageDetailedRequest
  type PROCESS_SIZES_REQUEST (line 111) | typedef struct ProcessSizesRequest
  type STRING_FILTER_TYPE (line 120) | typedef enum FilterType
  type FILTER_INFO (line 137) | typedef struct FilterInfo
  type STRING_FILTER_REQUEST (line 146) | typedef struct StringFilterRequest
  type LIST_FILTERS_REQUEST (line 152) | typedef struct ListFiltersRequest
  type ALERT_TYPE (line 161) | typedef enum AlertType
  type DETECTION_SOURCE (line 169) | typedef enum DetectionSource
  type BASE_ALERT_INFO (line 178) | typedef struct BaseAlertInfo
  type STACK_VIOLATION_ALERT (line 189) | typedef struct StackViolationAlert
  type FILTER_VIOLATION_ALERT (line 202) | typedef struct FilterViolationAlert
  type REMOTE_OPERATION_ALERT (line 214) | typedef struct RemoteOperationAlert
  type GLOBAL_SIZES (line 227) | typedef struct GlobalSizes
  type DELETE_FILTER_REQUEST (line 234) | typedef struct DeleteFilterRequest

FILE: PeaceMakerGUI/ClickableTab.h
  type TabType (line 12) | enum TabType
  function class (line 20) | class ClickableTab : public QLabel {

FILE: PeaceMakerGUI/InvestigateProcessWindow.h
  function namespace (line 16) | namespace Ui {
  function class (line 20) | class InvestigateProcessWindow : public QWidget

FILE: PeaceMakerGUI/addfilterwindow.h
  function namespace (line 10) | namespace Ui {
  function class (line 14) | class AddFilterWindow : public QWidget

FILE: PeaceMakerGUI/configparser.cpp
  function FALSE_POSITIVES (line 50) | FALSE_POSITIVES ConfigParser::GetConfigFalsePositives()

FILE: PeaceMakerGUI/configparser.h
  type FALSE_POSITIVES (line 12) | typedef struct FalsePositives
  function class (line 19) | class ConfigParser

FILE: PeaceMakerGUI/detailedalertwindow.h
  function namespace (line 12) | namespace Ui {
  function class (line 16) | class DetailedAlertWindow : public QWidget

FILE: PeaceMakerGUI/main.cpp
  function main (line 6) | int main(int argc, char *argv[])

FILE: PeaceMakerGUI/mainwindow.cpp
  function VOID (line 4) | VOID

FILE: PeaceMakerGUI/mainwindow.h
  function QT_BEGIN_NAMESPACE (line 22) | QT_BEGIN_NAMESPACE
  function class (line 32) | class MainWindow : public QMainWindow
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (347K chars).
[
  {
    "path": ".gitignore",
    "chars": 6002,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2020 Bill Demirkapi\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "PeaceMaker CLI/IOCTLCommunicationUser.cpp",
    "chars": 12258,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker CLI/IOCTLCommunicationUser.h",
    "chars": 1469,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker CLI/PeaceMaker CLI.cpp",
    "chars": 11585,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker CLI/PeaceMaker CLI.vcxproj",
    "chars": 7664,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msb"
  },
  {
    "path": "PeaceMaker CLI/PeaceMaker CLI.vcxproj.filters",
    "chars": 1186,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "PeaceMaker Kernel/AlertQueue.cpp",
    "chars": 2843,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/AlertQueue.h",
    "chars": 865,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/DetectionLogic.cpp",
    "chars": 11227,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/DetectionLogic.h",
    "chars": 1868,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/FSFilter.cpp",
    "chars": 14916,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/FSFilter.h",
    "chars": 2709,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/FilterTesting.cpp",
    "chars": 2174,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/IOCTLCommunication.cpp",
    "chars": 19418,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/IOCTLCommunication.h",
    "chars": 1479,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/ImageHistoryFilter.cpp",
    "chars": 34842,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/ImageHistoryFilter.h",
    "chars": 4496,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.inf",
    "chars": 2985,
    "preview": ";;;\n;;; FilterTesting\n;;;\n\n[Version]\nSignature   = \"$Windows NT$\"\n; TODO - Change the Class and ClassGuid to match the L"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.rc",
    "chars": 484,
    "preview": "#include <windows.h>\n\n#include <ntverp.h>\n\n#define VER_FILETYPE    VFT_DRV\n#define VER_FILESUBTYPE VFT2_DRV_SYSTEM\n#defi"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.vcxproj",
    "chars": 10055,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.vcxproj.filters",
    "chars": 4691,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "PeaceMaker Kernel/RegistryFilter.cpp",
    "chars": 10554,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/RegistryFilter.h",
    "chars": 1328,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/StackWalker.cpp",
    "chars": 6281,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/StackWalker.h",
    "chars": 690,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/StringFilters.cpp",
    "chars": 13270,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/StringFilters.h",
    "chars": 1994,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/TamperGuard.cpp",
    "chars": 4036,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/TamperGuard.h",
    "chars": 883,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/ThreadFilter.cpp",
    "chars": 5424,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/ThreadFilter.h",
    "chars": 755,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/common.cpp",
    "chars": 2637,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/common.h",
    "chars": 1141,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/ntdef.h",
    "chars": 6121,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel/shared.h",
    "chars": 10463,
    "preview": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code p"
  },
  {
    "path": "PeaceMaker Kernel.vcxproj",
    "chars": 9469,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "PeaceMaker.sln",
    "chars": 3838,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.2921"
  },
  {
    "path": "PeaceMakerGUI/AssetResources.qrc",
    "chars": 1106,
    "preview": "<RCC>\n    <qresource prefix=\"/\">\n        <file>assets/PeaceMakerLogo.png</file>\n        <file>assets/AlertsTabActive.png"
  },
  {
    "path": "PeaceMakerGUI/ClickableTab.cpp",
    "chars": 2984,
    "preview": "#include \"ClickableTab.h\"\n#include \"mainwindow.h\"\n\nClickableTab::ClickableTab(QWidget* parent, Qt::WindowFlags f)\n    : "
  },
  {
    "path": "PeaceMakerGUI/ClickableTab.h",
    "chars": 822,
    "preview": "#ifndef CLICKABLETAB_H\n#define CLICKABLETAB_H\n\n#include <QLabel>\n#include <QWidget>\n#include <Qt>\n#include <vector>\n\n//\n"
  },
  {
    "path": "PeaceMakerGUI/InvestigateProcessWindow.cpp",
    "chars": 13600,
    "preview": "#include \"InvestigateProcessWindow.h\"\n#include \"ui_InvestigateProcessWindow.h\"\n\n/**\n * @brief InvestigateProcessWindow::"
  },
  {
    "path": "PeaceMakerGUI/InvestigateProcessWindow.h",
    "chars": 1244,
    "preview": "#ifndef INVESTIGATEPROCESSWINDOW_H\n#define INVESTIGATEPROCESSWINDOW_H\n\n#include <QWidget>\n#include <QTableWidget>\n#inclu"
  },
  {
    "path": "PeaceMakerGUI/InvestigateProcessWindow.ui",
    "chars": 4531,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>InvestigateProcessWindow</class>\n <widget class=\"QWidg"
  },
  {
    "path": "PeaceMakerGUI/PeaceMakerGUI.pro",
    "chars": 1537,
    "preview": "QT       += core gui\n\ngreaterThan(QT_MAJOR_VERSION, 4): QT += widgets\n\nCONFIG += c++11\n\n# The following define makes you"
  },
  {
    "path": "PeaceMakerGUI/addfilterwindow.cpp",
    "chars": 1789,
    "preview": "#include \"addfilterwindow.h\"\n#include \"ui_addfilterwindow.h\"\n\nAddFilterWindow::AddFilterWindow(QWidget *parent) :\n    QW"
  },
  {
    "path": "PeaceMakerGUI/addfilterwindow.h",
    "chars": 517,
    "preview": "#ifndef ADDFILTERWINDOW_H\n#define ADDFILTERWINDOW_H\n\n#include <QWidget>\n\n#include <string>\n#include \"shared.h\"\n#include "
  },
  {
    "path": "PeaceMakerGUI/addfilterwindow.ui",
    "chars": 4273,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>AddFilterWindow</class>\n <widget class=\"QWidget\" name="
  },
  {
    "path": "PeaceMakerGUI/configparser.cpp",
    "chars": 7403,
    "preview": "#include \"configparser.h\"\n\n/**\n * @brief ConfigParser::ConfigParser - Read the config file.\n * @param ConfigFile - The c"
  },
  {
    "path": "PeaceMakerGUI/configparser.h",
    "chars": 639,
    "preview": "#ifndef CONFIGPARSER_H\n#define CONFIGPARSER_H\n#include \"shared.h\"\n#include <fstream>\n#include <vector>\n#include <map>\n#i"
  },
  {
    "path": "PeaceMakerGUI/detailedalertwindow.cpp",
    "chars": 8980,
    "preview": "#include \"detailedalertwindow.h\"\n#include \"ui_detailedalertwindow.h\"\n\n/**\n * @brief DetailedAlertWindow::InitializeCommo"
  },
  {
    "path": "PeaceMakerGUI/detailedalertwindow.h",
    "chars": 581,
    "preview": "#ifndef DETAILEDALERTWINDOW_H\n#define DETAILEDALERTWINDOW_H\n\n#include <QWidget>\n#include <QTableWidget>\n#include <QScrol"
  },
  {
    "path": "PeaceMakerGUI/detailedalertwindow.ui",
    "chars": 2232,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>DetailedAlertWindow</class>\n <widget class=\"QWidget\" n"
  },
  {
    "path": "PeaceMakerGUI/main.cpp",
    "chars": 250,
    "preview": "#include \"mainwindow.h\"\n\n#include <Windows.h>\n#include <QApplication>\n\nint main(int argc, char *argv[])\n{\n    AllocConso"
  },
  {
    "path": "PeaceMakerGUI/mainwindow.cpp",
    "chars": 22164,
    "preview": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nVOID\npmlog (\n    const char* format,\n    ...\n    )\n{\n    va_list var"
  },
  {
    "path": "PeaceMakerGUI/mainwindow.h",
    "chars": 2233,
    "preview": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <QMainWindow>\n#include <QTableWidgetItem>\n#include <QScrollBar>\n#inc"
  },
  {
    "path": "PeaceMakerGUI/mainwindow.ui",
    "chars": 7811,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\""
  },
  {
    "path": "README.md",
    "chars": 2976,
    "preview": "# PeaceMaker Threat Detection\nPeaceMaker Threat Detection is a kernel-mode utility designed to detect a variety of metho"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the D4stiny/PeaceMaker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (315.3 KB), approximately 83.0k tokens, and a symbol index with 126 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!