[
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Bill Demirkapi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "PeaceMaker CLI/IOCTLCommunicationUser.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"IOCTLCommunicationUser.h\"\n\n/**\n\tDefault constructor.\n*/\nIOCTLCommunication::IOCTLCommunication(\n\tVOID\n\t)\n{\n\t\n}\n\n/**\n\tDisconnect from the driver.\n*/\nIOCTLCommunication::~IOCTLCommunication(\n\tVOID\n\t)\n{\n\tCloseHandle(this->device);\n}\n\n/**\n\tEstablish communication with the driver.\n\t@return Whether or not we successfully connected to the driver.\n*/\nBOOLEAN\nIOCTLCommunication::ConnectDevice(\n\tVOID\n\t)\n{\n\tthis->device = CreateFile(GLOBAL_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n\tif (this->device == INVALID_HANDLE_VALUE)\n\t{\n\t\tprintf(\"IOCTLCommunication!IOCTLCommunication: Failed to connect to driver device with error %i.\\n\", GetLastError());\n\t\treturn FALSE;\n\t}\n\n\tprintf(\"IOCTLCommunication!IOCTLCommunication: Established communication with driver.\\n\");\n\treturn TRUE;\n}\n\n/**\n\tSmall wrapper around the DeviceIoControl call to the driver.\n\t@param IOCTLCode - The IOCTL code to pass to the driver.\n\t@param Input - The input buffer.\n\t@param InputLength - Size of the input buffer.\n\t@param Output - The output buffer.\n\t@param OutputLength - Size of the output buffer.\n\t@return Whether or not the call succeeded.\n*/\nBOOLEAN\nIOCTLCommunication::GenericQueryDriver (\n\t_In_ DWORD IOCTLCode,\n\t_In_ PVOID Input,\n\t_In_ DWORD InputLength,\n\t_Out_ PVOID Output,\n\t_In_ DWORD OutputLength\n\t)\n{\n\tDWORD bytesReturned;\n\treturn DeviceIoControl(this->device, IOCTLCode, Input, InputLength, Output, OutputLength, &bytesReturned, NULL);\n}\n\n/**\n\tQuery if there are alerts queued.\n\t@return Whether or not alerts are queued.\n*/\nBOOLEAN\nIOCTLCommunication::QueuedAlerts (\n\tVOID\n\t)\n{\n\tBOOLEAN queued;\n\n\t//\n\t// Query the driver passing in an output boolean.\n\t//\n\tif (this->GenericQueryDriver(IOCTL_ALERTS_QUEUED, NULL, 0, &queued, sizeof(queued)) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!QueuedAlerts: Failed to query driver with error code %i.\\n\", GetLastError());\n\t\treturn FALSE;\n\t}\n\n\treturn queued;\n}\n\n/**\n\tPop a queued alert from the Alerts queue.\n\t@return An allocated pointer to the alert or NULL if unable to pop an alert. Caller must free to prevent leak.\n*/\nPBASE_ALERT_INFO\nIOCTLCommunication::PopAlert(\n\tVOID\n\t)\n{\n\tBOOLEAN success;\n\tPBASE_ALERT_INFO alert;\n\n\tsuccess = FALSE;\n\n\talert = RCAST<PBASE_ALERT_INFO>(malloc(MAX_STACK_VIOLATION_ALERT_SIZE));\n\tif (alert == NULL)\n\t{\n\t\tprintf(\"IOCTLCommunication!PopAlert: Failed to allocate space for alert.\\n\");\n\t\tgoto Exit;\n\t}\n\tmemset(alert, 0, MAX_STACK_VIOLATION_ALERT_SIZE);\n\n\tif (this->GenericQueryDriver(IOCTL_POP_ALERT, NULL, 0, alert, MAX_STACK_VIOLATION_ALERT_SIZE) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!PopAlert: Failed to query driver with error code %i.\\n\", GetLastError());\n\t\tgoto Exit;\n\t}\n\tsuccess = TRUE;\nExit:\n\tif (success == FALSE && alert)\n\t{\n\t\tfree(alert);\n\t\talert = NULL;\n\t}\n\treturn alert;\n}\n\n/**\n\tRequest a summary of the most recent processes up to RequestCount.\n\t@param SkipCount - How many processes to \"skip\" in iteration.\n\t@param RequestCount - How many proocesses to get the summary of.\n\t@return The response to the summary request if any, otherwise NULL. Caller must free to prevent leak.\n*/\nPPROCESS_SUMMARY_REQUEST\nIOCTLCommunication::RequestProcessSummary (\n\t_In_ ULONG SkipCount,\n\t_In_ ULONG RequestCount\n\t)\n{\n\tBOOLEAN success;\n\tPPROCESS_SUMMARY_REQUEST summaryRequest;\n\tULONG summaryRequestSize;\n\n\tsuccess = FALSE;\n\tsummaryRequestSize = MAX_PROCESS_SUMMARY_REQUEST_SIZE_RAW(RequestCount);\n\n\tsummaryRequest = RCAST<PPROCESS_SUMMARY_REQUEST>(malloc(summaryRequestSize));\n\tif (summaryRequest == NULL)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestProcessSummary: Failed to allocate space for summaryRequest.\\n\");\n\t\tgoto Exit;\n\t}\n\tmemset(summaryRequest, 0, summaryRequestSize);\n\n\tsummaryRequest->SkipCount = SkipCount;\n\tsummaryRequest->ProcessHistorySize = RequestCount;\n\n\tif (this->GenericQueryDriver(IOCTL_GET_PROCESSES, summaryRequest, summaryRequestSize, summaryRequest, summaryRequestSize) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestProcessSummary: Failed to query driver with error code %i.\\n\", GetLastError());\n\t\tgoto Exit;\n\t}\n\tsuccess = TRUE;\nExit:\n\tif (success == FALSE && summaryRequest)\n\t{\n\t\tfree(summaryRequest);\n\t\tsummaryRequest = NULL;\n\t}\n\treturn summaryRequest;\n}\n\n/**\n\tRequest detailed information on a process.\n\t@param ProcessId - The subject process.\n\t@param EpochExecutionTime - The time the process was executed (in seconds since epoch).\n\t@param MaxImageSize - The maximum number of image entries to copy.\n\t@param MaxStackSize - The maximum number of stack entries to copy.\n\t@return The response to the detailed request if any, otherwise NULL. Caller must free to prevent leak.\n*/\nPPROCESS_DETAILED_REQUEST\nIOCTLCommunication::RequestDetailedProcess (\n\t_In_ HANDLE ProcessId,\n\t_In_ ULONG EpochExecutionTime,\n\t_In_ ULONG MaxImageSize,\n\t_In_ ULONG MaxStackSize\n\t)\n{\n\tBOOLEAN success;\n\tPPROCESS_DETAILED_REQUEST detailedRequest;\n\tULONG detailedRequestSize;\n\n\tsuccess = FALSE;\n\tdetailedRequestSize = sizeof(PROCESS_DETAILED_REQUEST);\n\n\t//\n\t// Allocate the necessary members.\n\t//\n\tdetailedRequest = RCAST<PPROCESS_DETAILED_REQUEST>(malloc(detailedRequestSize));\n\tif (detailedRequest == NULL)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestDetailedProcess: Failed to allocate space for detailedRequest.\\n\");\n\t\tgoto Exit;\n\t}\n\tmemset(detailedRequest, 0, detailedRequestSize);\n\n\tdetailedRequest->ImageSummary = RCAST<PIMAGE_SUMMARY>(malloc(MaxImageSize * sizeof(IMAGE_SUMMARY)));\n\tif (detailedRequest->ImageSummary == NULL)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestDetailedProcess: Failed to allocate space for detailedRequest->ImageSummary.\\n\");\n\t\tgoto Exit;\n\t}\n\tmemset(detailedRequest->ImageSummary, 0, MaxImageSize * sizeof(IMAGE_SUMMARY));\n\n\tdetailedRequest->StackHistory = RCAST<PSTACK_RETURN_INFO>(malloc(MaxStackSize * sizeof(STACK_RETURN_INFO)));\n\tif (detailedRequest->StackHistory == NULL)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestDetailedProcess: Failed to allocate space for detailedRequest->StackHistory.\\n\");\n\t\tgoto Exit;\n\t}\n\tmemset(detailedRequest->StackHistory, 0, MaxStackSize * sizeof(STACK_RETURN_INFO));\n\n\tdetailedRequest->ProcessId = ProcessId;\n\tdetailedRequest->EpochExecutionTime = EpochExecutionTime;\n\tdetailedRequest->ImageSummarySize = MaxImageSize;\n\tdetailedRequest->StackHistorySize = MaxStackSize;\n\n\tif (this->GenericQueryDriver(IOCTL_GET_PROCESS_DETAILED, detailedRequest, detailedRequestSize, detailedRequest, detailedRequestSize) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestDetailedProcess: Failed to query driver with error code %i.\\n\", GetLastError());\n\t\tgoto Exit;\n\t}\n\tsuccess = TRUE;\nExit:\n\tif (success == FALSE && detailedRequest)\n\t{\n\t\tfree(detailedRequest);\n\t\tdetailedRequest = NULL;\n\t}\n\treturn detailedRequest;\n}\n\n/**\n\tRegister a filter with the driver.\n\t@param Type - The filter type.\n\t@param Flags - The filter flags (EXECUTE/DELETE/WRITE/ETC).\n\t@param Content - The content of the filter.\n\t@param ContentLength - The size of the content.\n\t@return The filter ID (if added successfully), otherwise 0.\n*/\nULONG\nIOCTLCommunication::AddFilter (\n\t_In_ STRING_FILTER_TYPE Type,\n\t_In_ ULONG Flags,\n\t_In_ PWCHAR Content,\n\t_In_ ULONG ContentLength\n\t)\n{\n\n\tSTRING_FILTER_REQUEST filterRequest;\n\n\t//\n\t// Fill out the struct.\n\t//\n\tfilterRequest.FilterType = Type;\n\tfilterRequest.Filter.Flags = Flags;\n\tmemcpy_s(filterRequest.Filter.MatchString, sizeof(filterRequest.Filter.MatchString), Content, ContentLength * sizeof(WCHAR));\n\tfilterRequest.Filter.MatchStringSize = ContentLength;\n\n\t//\n\t// Query the driver passing in the filter request.\n\t//\n\tif (this->GenericQueryDriver(IOCTL_ADD_FILTER, &filterRequest, sizeof(filterRequest), &filterRequest, sizeof(filterRequest)) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!AddFilter: Failed to query driver with error code %i.\\n\", GetLastError());\n\t\treturn 0;\n\t}\n\n\treturn filterRequest.Filter.Id;\n}\n\n/**\n\tRequest a list of filters with a constant size of 10. Grab more by using the SkipCount argument.\n\t@param Type - The type of filters to grab.\n\t@param SkipCount - The number of filters to skip during iteration.\n\t@return The response to the request.\n*/\nLIST_FILTERS_REQUEST\nIOCTLCommunication::RequestFilters(\n\t_In_ STRING_FILTER_TYPE Type,\n\t_In_ ULONG SkipCount\n\t)\n{\n\tLIST_FILTERS_REQUEST listRequest;\n\n\tlistRequest.FilterType = Type;\n\tlistRequest.SkipFilters = SkipCount;\n\n\t//\n\t// Query the driver passing in the list request.\n\t//\n\tif (this->GenericQueryDriver(IOCTL_LIST_FILTERS, &listRequest, sizeof(listRequest), &listRequest, sizeof(listRequest)) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestFilters: Failed to query driver with error code %i.\\n\", GetLastError());\n\t}\n\n\treturn listRequest;\n}\n\n/**\n\tGet the dynamic sizes in a process entry from the driver.\n\t@param ProcessId - The target process ID.\n\t@param EpochExecutionTime - The time the target process was executed.\n\t@return The response.\n*/\nPROCESS_SIZES_REQUEST\nIOCTLCommunication::GetProcessSizes(\n\t_In_ HANDLE ProcessId,\n\t_In_ ULONG EpochExecutionTime\n\t)\n{\n\tPROCESS_SIZES_REQUEST sizeRequest;\n\n\tsizeRequest.ProcessId = ProcessId;\n\tsizeRequest.EpochExecutionTime = EpochExecutionTime;\n\n\t//\n\t// Query the driver passing in the list request.\n\t//\n\tif (this->GenericQueryDriver(IOCTL_GET_PROCESS_SIZES, &sizeRequest, sizeof(sizeRequest), &sizeRequest, sizeof(sizeRequest)) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!GetProcessSizes: Failed to query driver with error code %i.\\n\", GetLastError());\n\t}\n\n\treturn sizeRequest;\n}\n\n/**\n\tRequest detailed information on an image.\n\t@param ProcessId - The subject process.\n\t@param EpochExecutionTime - The time the process was executed (in seconds since epoch).\n\t@param MaxStackSize - The maximum number of stack entries to copy.\n\t@return The response to the detailed request if any, otherwise NULL. Caller must free to prevent leak.\n*/\nPIMAGE_DETAILED_REQUEST\nIOCTLCommunication::RequestDetailedImage (\n\t_In_ HANDLE ProcessId,\n\t_In_ ULONG EpochExecutionTime,\n\t_In_ ULONG ImageIndex,\n\t_In_ ULONG MaxStackSize\n\t)\n{\n\tBOOLEAN success;\n\tPIMAGE_DETAILED_REQUEST imageRequest;\n\tULONG imageRequestSize;\n\n\tsuccess = FALSE;\n\timageRequestSize = MAX_IMAGE_DETAILED_REQUEST_SIZE_RAW(MaxStackSize);\n\n\timageRequest = RCAST<PIMAGE_DETAILED_REQUEST>(malloc(imageRequestSize));\n\tif (imageRequest == NULL)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestDetailedImage: Failed to allocate space for imageRequest.\\n\");\n\t\tgoto Exit;\n\t}\n\tmemset(imageRequest, 0, imageRequestSize);\n\n\timageRequest->ProcessId = ProcessId;\n\timageRequest->EpochExecutionTime = EpochExecutionTime;\n\timageRequest->ImageIndex = ImageIndex;\n\timageRequest->StackHistorySize = MaxStackSize;\n\n\tif (this->GenericQueryDriver(IOCTL_GET_IMAGE_DETAILED, imageRequest, imageRequestSize, imageRequest, imageRequestSize) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!RequestDetailedImage: Failed to query driver with error code %i.\\n\", GetLastError());\n\t\tgoto Exit;\n\t}\n\tsuccess = TRUE;\nExit:\n\tif (success == FALSE && imageRequest)\n\t{\n\t\tfree(imageRequest);\n\t\timageRequest = NULL;\n\t}\n\treturn imageRequest;\n}\n\n/**\n\tGet global sizes from the kernel\n\t@return The various sizes of data stored in the kernel.\n*/\nGLOBAL_SIZES\nIOCTLCommunication::GetGlobalSizes (\n\tVOID\n\t)\n{\n\tGLOBAL_SIZES sizes;\n\n\t//\n\t// Query the driver passing in the size request.\n\t//\n\tif (this->GenericQueryDriver(IOCTL_GET_GLOBAL_SIZES, NULL, 0, &sizes, sizeof(sizes)) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!GetProcessSizes: Failed to query driver with error code %i.\\n\", GetLastError());\n\t}\n\n\treturn sizes;\n}\n\n/**\n\tDelete a filter.\n\t@param Filter - The filter to delete.\n\t@return Whether or not the filter was deleted.\n*/\nBOOLEAN\nIOCTLCommunication::DeleteFilter (\n\t_In_ FILTER_INFO Filter\n\t)\n{\n\tDELETE_FILTER_REQUEST deleteFilterRequest;\n\n\tdeleteFilterRequest.FilterId = Filter.Id;\n\tdeleteFilterRequest.FilterType = Filter.Type;\n\n\t//\n\t// Query the driver passing in the delete request.\n\t//\n\tif (this->GenericQueryDriver(IOCTL_DELETE_FILTER, &deleteFilterRequest, sizeof(deleteFilterRequest), &deleteFilterRequest, sizeof(deleteFilterRequest)) == FALSE)\n\t{\n\t\tprintf(\"IOCTLCommunication!DeleteFilter: Failed to query driver with error code %i.\\n\", GetLastError());\n\t}\n\n\treturn deleteFilterRequest.Deleted;\n}"
  },
  {
    "path": "PeaceMaker CLI/IOCTLCommunicationUser.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include <Windows.h>\n#include <cstdio>\n#include \"shared.h\"\n\nclass IOCTLCommunication\n{\n\tHANDLE device;\n\n\tBOOLEAN GenericQueryDriver(\n\t\t_In_ DWORD IOCTLCode,\n\t\t_In_ PVOID Input,\n\t\t_In_ DWORD InputLength,\n\t\t_Out_ PVOID Output,\n\t\t_In_ DWORD OutputLength\n\t\t);\n\npublic:\n\tIOCTLCommunication(VOID);\n\t~IOCTLCommunication(VOID);\n\n\tBOOLEAN ConnectDevice(\n\t\tVOID\n\t\t);\n\tBOOLEAN QueuedAlerts(\n\t\tVOID\n\t\t);\n\tPBASE_ALERT_INFO PopAlert(\n\t\tVOID\n\t\t);\n\tPPROCESS_SUMMARY_REQUEST RequestProcessSummary(\n\t\t_In_ ULONG SkipCount,\n\t\t_In_ ULONG RequestCount\n\t\t);\n\tPPROCESS_DETAILED_REQUEST RequestDetailedProcess(\n\t\t_In_ HANDLE ProcessId,\n\t\t_In_ ULONG EpochExecutionTime,\n\t\t_In_ ULONG MaxImageSize,\n\t\t_In_ ULONG MaxStackSize\n\t\t);\n\tULONG AddFilter(\n\t\t_In_ STRING_FILTER_TYPE Type,\n\t\t_In_ ULONG Flags,\n\t\t_In_ PWCHAR Content,\n\t\t_In_ ULONG ContentLength\n\t\t);\n\tLIST_FILTERS_REQUEST RequestFilters(\n\t\t_In_ STRING_FILTER_TYPE Type,\n\t\t_In_ ULONG SkipCount\n\t\t);\n\tPROCESS_SIZES_REQUEST GetProcessSizes(\n\t\t_In_ HANDLE ProcessId,\n\t\t_In_ ULONG EpochExecutionTime\n\t\t);\n\tPIMAGE_DETAILED_REQUEST RequestDetailedImage(\n\t\t_In_ HANDLE ProcessId,\n\t\t_In_ ULONG EpochExecutionTime,\n\t\t_In_ ULONG ImageIndex,\n\t\t_In_ ULONG MaxStackSize\n\t\t);\n\tGLOBAL_SIZES GetGlobalSizes(\n\t\tVOID\n\t\t);\n\tBOOLEAN DeleteFilter(\n\t\t_In_ FILTER_INFO Filter\n\t\t);\n};"
  },
  {
    "path": "PeaceMaker CLI/PeaceMaker CLI.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include <Windows.h>\n#include <iostream>\n#include <string>\n#include \"IOCTLCommunicationUser.h\"\n\n/**\n\tPrint stack history.\n\t@param StackHistory - The history to display.\n\t@param StackHistorySize - The size of the StackHistory array.\n*/\nVOID\nDisplayStackHistory(\n\t_In_ PSTACK_RETURN_INFO StackHistory,\n\t_In_ ULONG StackHistorySize\n\t)\n{\n\tULONG i;\n\n\tprintf(\"DisplayStackHistory: \\tStack History:\\n\");\n\tfor (i = 0; i < StackHistorySize; i++)\n\t{\n\t\tif (StackHistory[i].MemoryInModule)\n\t\t{\n\t\t\tprintf(\"DisplayStackHistory: \\t\\t%ws+0x%X\\n\", StackHistory[i].BinaryPath, StackHistory[i].BinaryOffset);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprintf(\"DisplayStackHistory: \\t\\t0x%llx (Manual Mapped)\\n\", StackHistory[i].RawAddress);\n\t\t}\n\t}\n}\n\n/**\n\tDisplay an alert. Supports the various alert types.\n\t@param Alert - Alert to display.\n*/\nVOID\nDisplayAlert (\n\tPBASE_ALERT_INFO Alert\n\t)\n{\n\tPSTACK_VIOLATION_ALERT stackViolationAlert;\n\tPFILTER_VIOLATION_ALERT filterViolationAlert;\n\n\t//\n\t// Sanity check.\n\t//\n\tif (Alert == NULL)\n\t{\n\t\tprintf(\"DisplayAlert: No alert found.\\n\");\n\t\treturn;\n\t}\n\n\tprintf(\"DisplayAlert: Alert dump:\\n\");\n\tswitch (Alert->AlertSource)\n\t{\n\tcase ProcessCreate:\n\t\tprintf(\"DisplayAlert: \\tSource: Process creation callback\\n\");\n\t\tbreak;\n\tcase ImageLoad:\n\t\tprintf(\"DisplayAlert: \\tSource: Image load callback\\n\");\n\t\tbreak;\n\tcase RegistryFilterMatch:\n\t\tprintf(\"DisplayAlert: \\tSource: Registry filter match\\n\");\n\t\tbreak;\n\tcase FileFilterMatch:\n\t\tprintf(\"DisplayAlert: \\tSource: File filter match\\n\");\n\t\tbreak;\n\tcase ThreadCreate:\n\t\tprintf(\"DisplayAlert: \\tSource: Thread creation callback\\n\");\n\t\tbreak;\n\t}\n\t\n\tswitch (Alert->AlertType)\n\t{\n\tcase StackViolation:\n\t\tstackViolationAlert = RCAST<PSTACK_VIOLATION_ALERT>(Alert);\n\t\tprintf(\"DisplayAlert: \\tAlert Type: Stack walk violation\\n\");\n\t\tprintf(\"DisplayAlert: \\tViolating Address: 0x%llx\\n\", stackViolationAlert->ViolatingAddress);\n\t\tDisplayStackHistory(stackViolationAlert->StackHistory, stackViolationAlert->StackHistorySize);\n\t\tbreak;\n\tcase FilterViolation:\n\t\tfilterViolationAlert = RCAST<PFILTER_VIOLATION_ALERT>(Alert);\n\t\tprintf(\"DisplayAlert: \\tAlert Type: Filter violation\\n\");\n\t\tprintf(\"DisplayAlert: \\tFilter content: %ws\\n\", filterViolationAlert->ViolatedFilter.MatchString);\n\t\tprintf(\"DisplayAlert: \\tFilter flags: 0x%X\\n\", filterViolationAlert->ViolatedFilter.Flags);\n\t\tDisplayStackHistory(filterViolationAlert->StackHistory, filterViolationAlert->StackHistorySize);\n\t\tbreak;\n\t}\n}\n\nint main()\n{\n\tIOCTLCommunication communicator;\n\tstd::string input;\n\tint choice;\n\n\tPBASE_ALERT_INFO alert;\n\tPPROCESS_SUMMARY_REQUEST processSummaries;\n\tPPROCESS_DETAILED_REQUEST processDetailed;\n\tPROCESS_SIZES_REQUEST processSizes;\n\tLIST_FILTERS_REQUEST filters;\n\tPIMAGE_DETAILED_REQUEST imageDetailed;\n\n\tULONG i;\n\tint skipCount;\n\tint requestCount;\n\tHANDLE processID;\n\tULONG executionTime;\n\tSTRING_FILTER_TYPE filterType;\n\tULONG filterFlags;\n\tstd::wstring filterContent;\n\tULONG filterId;\n\tULONG imageIndex;\n\n\tchoice = 7;\n\n\tprintf(\"main: Initiating communication with the driver.\\n\");\n\tif (communicator.ConnectDevice() == FALSE)\n\t{\n\t\tprintf(\"main: Failed to connect to the device.\\n\");\n\t\tgoto Exit;\n\t}\n\n\tprintf(\"main: Communication initiated.\\n\");\n\tdo\n\t{\n\t\tprintf(\"main: PeaceMaker basic CLI utility\\n\");\n\t\tprintf(\"main: 1. Check if there are alerts queued.\\n\");\n\t\tprintf(\"main: 2. Pop an alert from the list of alerts.\\n\");\n\t\tprintf(\"main: 3. Request a list of process summaries.\\n\");\n\t\tprintf(\"main: 4. Request detailed information on a process.\\n\");\n\t\tprintf(\"main: 5. Request to add a filter.\\n\");\n\t\tprintf(\"main: 6. Request a list of filters.\\n\");\n\t\tprintf(\"main: 7. Request detailed information on an image in a process.\\n\");\n\t\tprintf(\"main: 8. Exit.\\n\");\n\n\t\tstd::cin >> input;\n\t\tchoice = std::stoi(input);\n\n\t\t//\n\t\t// Depending on the user's choice, dispatch to the correct function.\n\t\t//\n\t\tswitch (choice)\n\t\t{\n\t\tcase 1:\n\t\t\tif (communicator.QueuedAlerts())\n\t\t\t{\n\t\t\t\tprintf(\"main: There are alerts queued.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tprintf(\"main: There are no alerts queued.\\n\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\talert = communicator.PopAlert();\n\t\t\tDisplayAlert(alert);\n\t\t\tfree(alert);\n\t\t\talert = NULL;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\t//\n\t\t\t// Ask for the necessary information.\n\t\t\t//\n\t\t\tprintf(\"main: How many processes should we skip?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tskipCount = std::stoi(input);\n\n\t\t\tprintf(\"main: How many processes should we request?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\trequestCount = std::stoi(input);\n\n\t\t\t//\n\t\t\t// Get the summamries.\n\t\t\t//\n\t\t\tprocessSummaries = communicator.RequestProcessSummary(skipCount, requestCount);\n\t\t\tif (processSummaries == NULL)\n\t\t\t{\n\t\t\t\tprintf(\"main: Failed to retrieve process summaries.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Print the processes in a \"table\" format.\n\t\t\t//\n\t\t\tprintf(\"main: %-10s\\t%-50s\\t%-12s\\n\", \"Process ID\", \"Path\", \"Execution Time\");\n\t\t\tfor (i = 0; i < processSummaries->ProcessHistorySize; i++)\n\t\t\t{\n\t\t\t\tif (processSummaries->ProcessHistory[i].ProcessId == 0)\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tprintf(\"main: %-10i\\t%-50ws\\t%-12i\\n\", processSummaries->ProcessHistory[i].ProcessId, processSummaries->ProcessHistory[i].ImageFileName, processSummaries->ProcessHistory[i].EpochExecutionTime);\n\t\t\t}\n\n\t\t\tfree(processSummaries);\n\t\t\tprocessSummaries = NULL;\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\t//\n\t\t\t// Ask for the necessary information.\n\t\t\t//\n\t\t\tprintf(\"main: What is the target process ID?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tprocessID = RCAST<HANDLE>(std::stoi(input));\n\n\t\t\tprintf(\"main: What is the processes execution time in epoch?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\texecutionTime = std::stoi(input);\n\n\t\t\tprocessSizes = communicator.GetProcessSizes(processID, executionTime);\n\t\t\tprintf(\"main: ImageSize = %i, StackSize = %i\\n\", processSizes.ImageSize, processSizes.StackSize);\n\n\t\t\t//\n\t\t\t// Request a detailed report on the process.\n\t\t\t//\n\t\t\tprocessDetailed = communicator.RequestDetailedProcess(processID, executionTime, processSizes.ImageSize, processSizes.StackSize);\n\t\t\tif (processDetailed == NULL || processDetailed->Populated == FALSE)\n\t\t\t{\n\t\t\t\tprintf(\"main: Failed to retrieve a detailed process report.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintf(\"main: Process 0x%X:\\n\", processID);\n\t\t\tprintf(\"main: \\tProcess Path: %ws\\n\", processDetailed->ProcessPath);\n\t\t\tprintf(\"main: \\tCaller Process ID: 0x%X\\n\", processDetailed->CallerProcessId);\n\t\t\tprintf(\"main: \\tCaller Process Path: %ws\\n\", processDetailed->CallerProcessPath);\n\t\t\tprintf(\"main: \\tParent Process ID: 0x%X\\n\", processDetailed->ParentProcessId);\n\t\t\tprintf(\"main: \\tParent Process Path: %ws\\n\", processDetailed->ParentProcessPath);\n\t\t\tDisplayStackHistory(processDetailed->StackHistory, processDetailed->StackHistorySize);\n\n\t\t\tprintf(\"main: \\t%-3s\\t%-100s:\\n\", \"ID\", \"IMAGE PATH\");\n\t\t\tfor (i = 0; i < processDetailed->ImageSummarySize; i++)\n\t\t\t{\n\t\t\t\tprintf(\"main: \\t\\t%-3i\\t%-100ws\\n\", i, processDetailed->ImageSummary[i].ImagePath);\n\t\t\t}\n\n\t\t\tfree(processDetailed->ImageSummary);\n\t\t\tfree(processDetailed->StackHistory);\n\t\t\tfree(processDetailed);\n\t\t\tprocessDetailed = NULL;\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\t//\n\t\t\t// Ask for the necessary information.\n\t\t\t//\n\t\t\tprintf(\"main: What type of filter to add (R/F)?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tswitch (input[0])\n\t\t\t{\n\t\t\tcase 'R':\n\t\t\tcase 'r':\n\t\t\t\tfilterType = RegistryFilter;\n\t\t\t\tbreak;\n\t\t\tcase 'F':\n\t\t\tcase 'f':\n\t\t\t\tfilterType = FilesystemFilter;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintf(\"main: What flags should the filter have (D/W/E, can enter multiple)?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tfilterFlags = 0;\n\t\t\tfor (char c : input)\n\t\t\t{\n\t\t\t\tswitch (c)\n\t\t\t\t{\n\t\t\t\tcase 'D':\n\t\t\t\tcase 'd':\n\t\t\t\t\tfilterFlags |= FILTER_FLAG_DELETE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'W':\n\t\t\t\tcase 'w':\n\t\t\t\t\tfilterFlags |= FILTER_FLAG_WRITE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'E':\n\t\t\t\tcase 'e':\n\t\t\t\t\tfilterFlags |= FILTER_FLAG_DELETE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprintf(\"main: What should the filter content be?\\n\");\n\t\t\tstd::wcin >> filterContent;\n\n\t\t\tfilterId = communicator.AddFilter(filterType, filterFlags, CCAST<PWCHAR>(filterContent.c_str()), filterContent.length());\n\t\t\tif (filterId)\n\t\t\t{\n\t\t\t\tprintf(\"main: Filter added with ID 0x%X.\\n\", filterId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tprintf(\"main: Failed to add filter.\\n\");\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\t//\n\t\t\t// Ask for the necessary information.\n\t\t\t//\n\t\t\tprintf(\"main: What type of filter to list (R/F)?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tswitch (input[0])\n\t\t\t{\n\t\t\tcase 'R':\n\t\t\tcase 'r':\n\t\t\t\tfilterType = RegistryFilter;\n\t\t\t\tbreak;\n\t\t\tcase 'F':\n\t\t\tcase 'f':\n\t\t\t\tfilterType = FilesystemFilter;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintf(\"main: How many filters should we skip?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tskipCount = std::stoi(input);\n\n\t\t\tfilters = communicator.RequestFilters(filterType, skipCount);\n\t\t\tfor (i = 0; i < filters.CopiedFilters; i++)\n\t\t\t{\n\t\t\t\tprintf(\"main: Filter 0x%X:\\n\");\n\t\t\t\tswitch (filters.Filters[i].Type)\n\t\t\t\t{\n\t\t\t\tcase RegistryFilter:\n\t\t\t\t\tprintf(\"main: \\tFilter Type: Registry filter\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FilesystemFilter:\n\t\t\t\t\tprintf(\"main: \\tFilter Type: Filesystem filter\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tprintf(\"main: \\tFilter Flags: \");\n\n\t\t\t\tif (FlagOn(filters.Filters[i].Flags, FILTER_FLAG_DELETE))\n\t\t\t\t{\n\t\t\t\t\tprintf(\"main: \\t\\tDELETE\\n\");\n\t\t\t\t}\n\t\t\t\tif (FlagOn(filters.Filters[i].Flags, FILTER_FLAG_WRITE))\n\t\t\t\t{\n\t\t\t\t\tprintf(\"main: \\t\\tWRITE\\n\");\n\t\t\t\t}\n\t\t\t\tif (FlagOn(filters.Filters[i].Flags, FILTER_FLAG_EXECUTE))\n\t\t\t\t{\n\t\t\t\t\tprintf(\"main: \\t\\tDELETE\\n\");\n\t\t\t\t}\n\n\t\t\t\tprintf(\"main: \\tFilter Content: %ws\\n\", filters.Filters[i].MatchString);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\t//\n\t\t\t// Ask for the necessary information.\n\t\t\t//\n\t\t\tprintf(\"main: What is the target process ID?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\tprocessID = RCAST<HANDLE>(std::stoi(input));\n\n\t\t\tprintf(\"main: What is the processes execution time in epoch?\\n\");\n\t\t\tstd::cin >> input;\n\t\t\texecutionTime = std::stoi(input);\n\n\t\t\tprocessSizes = communicator.GetProcessSizes(processID, executionTime);\n\t\t\tprintf(\"main: ImageSize = %i, StackSize = %i\\n\", processSizes.ImageSize, processSizes.StackSize);\n\n\t\t\t//\n\t\t\t// Request a detailed report on the process.\n\t\t\t//\n\t\t\tprocessDetailed = communicator.RequestDetailedProcess(processID, executionTime, processSizes.ImageSize, processSizes.StackSize);\n\t\t\tif (processDetailed == NULL || processDetailed->Populated == FALSE)\n\t\t\t{\n\t\t\t\tprintf(\"main: Failed to retrieve a detailed process report.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintf(\"main: \\t%-3s\\t%-50s\\n\", \"ID\", \"IMAGE PATH\");\n\t\t\tfor (i = 0; i < processDetailed->ImageSummarySize; i++)\n\t\t\t{\n\t\t\t\tprintf(\"main: \\t%-3i\\t%-50ws\\n\", i, processDetailed->ImageSummary[i].ImagePath);\n\t\t\t}\n\n\t\t\tprintf(\"main: Enter the ID of the image to query.\\n\");\n\t\t\tstd::cin >> input;\n\t\t\timageIndex = std::stoi(input);\n\n\t\t\tprintf(\"main: Image stack size: %i\\n\", processDetailed->ImageSummary[imageIndex].StackSize);\n\n\t\t\timageDetailed = communicator.RequestDetailedImage(processID, executionTime, imageIndex, processDetailed->ImageSummary[imageIndex].StackSize);\n\t\t\tif (imageDetailed == NULL || imageDetailed->Populated == FALSE)\n\t\t\t{\n\t\t\t\tprintf(\"main: Failed to retrieve a detailed image report.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintf(\"main: Image %i:\\n\", imageIndex);\n\t\t\tprintf(\"main: \\tPath: %ws\\n\", imageDetailed->ImagePath);\n\t\t\tDisplayStackHistory(imageDetailed->StackHistory, imageDetailed->StackHistorySize);\n\n\t\t\tfree(processDetailed);\n\t\t\tfree(imageDetailed);\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\t//\n\t\t\t// No handling required, will exit when the while condition is checked.\n\t\t\t//\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintf(\"main: Unrecognized option %i.\\n\", choice);\n\t\t\tbreak;\n\t\t}\n\t} while (input != \"8\");\nExit:\n\t_fgetchar();\n\treturn 0;\n}"
  },
  {
    "path": "PeaceMaker CLI/PeaceMaker CLI.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <ProjectGuid>{A287D40E-AB7B-4FE9-AA84-44114766C79D}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>PeaceMakerCLI</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>$(SolutionDir)\\PeaceMaker Kernel;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"IOCTLCommunicationUser.cpp\" />\n    <ClCompile Include=\"PeaceMaker CLI.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"IOCTLCommunicationUser.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "PeaceMaker CLI/PeaceMaker CLI.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"PeaceMaker CLI.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"IOCTLCommunicationUser.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"IOCTLCommunicationUser.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "PeaceMaker Kernel/AlertQueue.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"AlertQueue.h\"\n\n/**\n\tInitialize basic members of the AlertQueue class.\n*/\nAlertQueue::AlertQueue()\n{\n\tthis->alertsLock = RCAST<PKSPIN_LOCK>(ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK), ALERT_LOCK_TAG));\n\tNT_ASSERT(this->alertsLock);\n\tthis->destroying = FALSE;\n\tKeInitializeSpinLock(this->alertsLock);\n\tInitializeListHead(RCAST<PLIST_ENTRY>(&this->alertsHead));\n}\n\n/**\n\tClear the queue of alerts.\n*/\nAlertQueue::~AlertQueue()\n{\n\tPLIST_ENTRY currentEntry;\n\tKIRQL oldIRQL;\n\n\t//\n\t// Make sure no one is doing operations on the AlertQueue.\n\t//\n\tthis->destroying = TRUE;\n\n\tKeAcquireSpinLock(this->alertsLock, &oldIRQL);\n\tKeReleaseSpinLock(this->alertsLock, oldIRQL);\n\n\twhile (IsListEmpty(RCAST<PLIST_ENTRY>(&this->alertsHead)) == FALSE)\n\t{\n\t\tcurrentEntry = RemoveHeadList(RCAST<PLIST_ENTRY>(&this->alertsHead));\n\t\t//\n\t\t// Free the entry.\n\t\t//\n\t\tExFreePoolWithTag(SCAST<PVOID>(currentEntry), ALERT_QUEUE_ENTRY_TAG);\n\t}\n\n\tExFreePoolWithTag(this->alertsLock, ALERT_LOCK_TAG);\n}\n\n/**\n\tPush an alert to the queue.\n\t@param Alert - The alert to push.\n\t@return Whether or not pushing the alert was successful.\n*/\nVOID\nAlertQueue::PushAlert (\n\t_In_ PBASE_ALERT_INFO Alert,\n\t_In_ ULONG AlertSize\n\t)\n{\n\tPBASE_ALERT_INFO newAlert;\n\n\tif (this->destroying)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Allocate space for the new alert and copy the details.\n\t//\n\tnewAlert = RCAST<PBASE_ALERT_INFO>(ExAllocatePoolWithTag(NonPagedPool, AlertSize, ALERT_QUEUE_ENTRY_TAG));\n\tif (newAlert == NULL)\n\t{\n\t\tDBGPRINT(\"AlertQueue!PushAlert: Failed to allocate space for new alert.\");\n\t\treturn;\n\t}\n\tmemset(newAlert, 0, AlertSize);\n\tmemcpy(newAlert, Alert, AlertSize);\n\tnewAlert->AlertSize = AlertSize;\n\n\t//\n\t// Queue the alert.\n\t//\n\tExInterlockedInsertTailList(RCAST<PLIST_ENTRY>(&this->alertsHead), RCAST<PLIST_ENTRY>(newAlert), this->alertsLock);\n}\n\n/**\n\tPop an alert from the queue of alerts. Follows FI-FO.\n\t@return The first in queued alert.\n*/\nPBASE_ALERT_INFO\nAlertQueue::PopAlert (\n\tVOID\n\t)\n{\n\tif (this->destroying)\n\t{\n\t\treturn NULL;\n\t}\n\treturn RCAST<PBASE_ALERT_INFO>(ExInterlockedRemoveHeadList(RCAST<PLIST_ENTRY>(&this->alertsHead), this->alertsLock));\n}\n\n/**\n\tCheck if the queue of alerts is empty.\n\t@return Whether or not the alerts queue is empty.\n*/\nBOOLEAN\nAlertQueue::IsQueueEmpty (\n\tVOID\n\t)\n{\n\tBOOLEAN empty;\n\tKIRQL oldIrql;\n\n\tExAcquireSpinLock(this->alertsLock, &oldIrql);\n\tempty = IsListEmpty(RCAST<PLIST_ENTRY>(&this->alertsHead));\n\tExReleaseSpinLock(this->alertsLock, oldIrql);\n\n\treturn empty;\n}\n\n\n/**\n\tFree a previously pop'd alert.\n\t@param Alert - The alert to free.\n*/\nVOID\nAlertQueue::FreeAlert(\n\t_In_ PBASE_ALERT_INFO Alert\n\t)\n{\n\tExFreePoolWithTag(Alert, ALERT_QUEUE_ENTRY_TAG);\n}"
  },
  {
    "path": "PeaceMaker Kernel/AlertQueue.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"shared.h\"\n\ntypedef class AlertQueue\n{\n\tBASE_ALERT_INFO alertsHead; // The linked list of alerts.\n\tPKSPIN_LOCK alertsLock; // The lock protecting the linked-list of alerts.\n\tBOOLEAN destroying; // This boolean indicates to functions that a lock should not be held as we are in the process of destruction.\n\npublic:\n\tAlertQueue();\n\t~AlertQueue();\n\n\tVOID PushAlert (\n\t\t_In_ PBASE_ALERT_INFO Alert,\n\t\t_In_ ULONG AlertSize\n\t\t);\n\n\tPBASE_ALERT_INFO PopAlert (\n\t\tVOID\n\t\t);\n\n\tBOOLEAN IsQueueEmpty (\n\t\tVOID\n\t\t);\n\n\tVOID FreeAlert (\n\t\t_In_ PBASE_ALERT_INFO Alert\n\t\t);\n\n} ALERT_QUEUE, *PALERT_QUEUE;\n\n#define ALERT_LOCK_TAG 'lAmP'\n#define ALERT_QUEUE_ENTRY_TAG 'eAmP'"
  },
  {
    "path": "PeaceMaker Kernel/DetectionLogic.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"DetectionLogic.h\"\n\n/**\n\tInitialize class members.\n*/\nDetectionLogic::DetectionLogic()\n{\n\talerts = new (NonPagedPool, ALERT_QUEUE_TAG) AlertQueue();\n}\n\n/**\n\tDeconstruct class members.\n*/\nDetectionLogic::~DetectionLogic()\n{\n\talerts->~AlertQueue();\n\tExFreePoolWithTag(alerts, ALERT_QUEUE_TAG);\n}\n\n/**\n\tGet the alert queue for this detection logic instance.\n\t@return The Alert Queue.\n*/\nPALERT_QUEUE\nDetectionLogic::GetAlertQueue (\n\tVOID\n\t)\n{\n\treturn this->alerts;\n}\n\n/**\n\tAudit a stack history for invalid code.\n\t@param DetectionSource - The filter we are checking the stack of.\n\t@param SourceProcessId - The source of the audit.\n\t@param SourcePath - The source path.\n\t@param TargetPath - The target path.\n\t@param StackHistory - A variable-length array of stack return history.\n\t@param StackHistorySize - Size of the StackHistory array.\n*/\nVOID\nDetectionLogic::AuditUserStackWalk (\n\t_In_ DETECTION_SOURCE DetectionSource,\n\t_In_ HANDLE SourceProcessId,\n\t_In_ PUNICODE_STRING SourcePath,\n\t_In_ PUNICODE_STRING TargetPath,\n\t_In_ STACK_RETURN_INFO StackHistory[],\n\t_In_ ULONG StackHistorySize\n\t)\n{\n\tULONG i;\n\tBOOLEAN stackViolation;\n\tPVOID firstViolatingAddress;\n\n\tstackViolation = FALSE;\n\tfirstViolatingAddress = NULL;\n\n\t//\n\t// Check if any of the stack returns are to unmapped code.\n\t//\n\tfor (i = 0; i < StackHistorySize; i++)\n\t{\n\t\tif (StackHistory[i].MemoryInModule == FALSE &&\n\t\t\tStackHistory[i].ExecutableMemory &&\n\t\t\tStackHistory[i].RawAddress != 0x0 &&\n\t\t\tRCAST<ULONG64>(StackHistory[i].RawAddress) < MmUserProbeAddress)\n\t\t{\n\t\t\tDBGPRINT(\"DetectionLogic!AuditUserStackWalk: Alert pid 0x%X, Violate 0x%llx, Source %i\", PsGetCurrentProcessId(), StackHistory[i].RawAddress, DetectionSource);\n\t\t\tstackViolation = TRUE;\n\t\t\tfirstViolatingAddress = StackHistory[i].RawAddress;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (stackViolation == FALSE)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Push the alert.\n\t//\n\tthis->PushStackViolationAlert(DetectionSource, firstViolatingAddress, SourceProcessId, SourcePath, TargetPath, StackHistory, StackHistorySize);\n}\n\n/**\n\tCreate and push a stack violation alert.\n\t@param DetectionSource - The filter we are checking the stack of.\n\t@param ViolatingAddress - If the origin of this alert is from an audit address operation, log the specific address.\n\t@param SourceProcessId - The source of the audit.\n\t@param SourcePath - The source path.\n\t@param TargetPath - The target path.\n\t@param StackHistory - A variable-length array of stack return history.\n\t@param StackHistorySize - Size of the StackHistory array.\n*/\nVOID\nDetectionLogic::PushStackViolationAlert(\n\t_In_ DETECTION_SOURCE DetectionSource,\n\t_In_ PVOID ViolatingAddress,\n\t_In_ HANDLE SourceProcessId,\n\t_In_ PUNICODE_STRING SourcePath,\n\t_In_ PUNICODE_STRING TargetPath,\n\t_In_ STACK_RETURN_INFO StackHistory[],\n\t_In_ ULONG StackHistorySize\n\t)\n{\n\tULONG stackHistoryBytes;\n\tPSTACK_VIOLATION_ALERT stackViolationAlert;\n\n\t//\n\t// Calculate the size of the StackHistory array in bytes.\n\t//\n\tstackHistoryBytes = sizeof(STACK_RETURN_INFO) * (StackHistorySize-1);\n\n\t//\n\t// Allocate space for the alert depending on the size of StackHistory.\n\t//\n\tstackViolationAlert = RCAST<PSTACK_VIOLATION_ALERT>(ExAllocatePoolWithTag(PagedPool, sizeof(STACK_VIOLATION_ALERT) + stackHistoryBytes, STACK_VIOLATION_TAG));\n\tif (stackViolationAlert == NULL)\n\t{\n\t\tDBGPRINT(\"DetectionLogic!PushStackViolationAlert: Failed to allocate space for the alert.\");\n\t\treturn;\n\t}\n\tmemset(stackViolationAlert, 0, sizeof(STACK_VIOLATION_ALERT) + stackHistoryBytes);\n\n\t//\n\t// Fill the fields of the alert.\n\t//\n\tstackViolationAlert->AlertInformation.AlertType = StackViolation;\n\tstackViolationAlert->AlertInformation.AlertSource = DetectionSource;\n\tstackViolationAlert->ViolatingAddress = ViolatingAddress;\n\tstackViolationAlert->AlertInformation.SourceId = SourceProcessId;\n\n\tif (SourcePath)\n\t{\n\t\tRtlStringCbCopyUnicodeString(stackViolationAlert->AlertInformation.SourcePath, MAX_PATH, SourcePath);\n\t}\n\tif (TargetPath)\n\t{\n\t\tRtlStringCbCopyUnicodeString(stackViolationAlert->AlertInformation.TargetPath, MAX_PATH, TargetPath);\n\t}\n\n\tstackViolationAlert->StackHistorySize = StackHistorySize;\n\tmemcpy(&stackViolationAlert->StackHistory, StackHistory, sizeof(STACK_RETURN_INFO) * StackHistorySize);\n\n\t//\n\t// Push the alert.\n\t//\n\tthis->alerts->PushAlert(RCAST<PBASE_ALERT_INFO>(stackViolationAlert), sizeof(STACK_VIOLATION_ALERT) + stackHistoryBytes);\n\n\t//\n\t// PushAlert copies the alert, so we can free our copy.\n\t//\n\tExFreePoolWithTag(stackViolationAlert, STACK_VIOLATION_TAG);\n}\n\n/**\n\tValidate a user-mode pointer.\n\t@param DetectionSource - The filter we are checking the stack of.\n\t@param UserPtr - The pointer to check.\n\t@param SourceProcessId - The source of the audit.\n\t@param SourcePath - The source path.\n\t@param TargetPath - The target path.\n\t@param StackHistory - A variable-length array of stack return history.\n\t@param StackHistorySize - Size of the StackHistory array.\n*/\nVOID\nDetectionLogic::AuditUserPointer (\n\t_In_ DETECTION_SOURCE DetectionSource,\n\t_In_ PVOID UserPtr,\n\t_In_ HANDLE SourceProcessId,\n\t_In_ PUNICODE_STRING SourcePath,\n\t_In_ PUNICODE_STRING TargetPath,\n\t_In_ STACK_RETURN_INFO StackHistory[],\n\t_In_ ULONG StackHistorySize\n\t)\n{\n\tSTACK_RETURN_INFO info;\n\n\tinfo.RawAddress = UserPtr;\n\n\t//\n\t// Resolve basic information about the module.\n\t//\n\tresolver.ResolveAddressModule(UserPtr, &info);\n\n\t//\n\t// If the user pointer isn't mapped, something's wrong.\n\t//\n\tif (info.MemoryInModule == FALSE &&\n\t\tinfo.ExecutableMemory &&\n\t\tinfo.RawAddress != 0x0 &&\n\t\tRCAST<ULONG64>(info.RawAddress) < MmUserProbeAddress)\n\t{\n\t\tthis->PushStackViolationAlert(DetectionSource, UserPtr, SourceProcessId, SourcePath, TargetPath, StackHistory, StackHistorySize);\n\t}\n}\n\n/**\n\tCheck if an operation is on a remote process. This is called by suspicious operation callbacks such as Thread Creation.\n\t@param DetectionSource - The filter we are checking the stack of.\n\t@param UserPtr - The pointer to check.\n\t@param SourceProcessId - The source of the audit.\n\t@param SourceProcessId - The target of the operation.\n\t@param SourcePath - The source path.\n\t@param TargetPath - The target path.\n\t@param StackHistory - A variable-length array of stack return history.\n\t@param StackHistorySize - Size of the StackHistory array.\n*/\nVOID\nDetectionLogic::AuditCallerProcessId(\n\t_In_ DETECTION_SOURCE DetectionSource,\n\t_In_ HANDLE CallerProcessId,\n\t_In_ HANDLE TargetProcessId,\n\t_In_ PUNICODE_STRING SourcePath,\n\t_In_ PUNICODE_STRING TargetPath,\n\t_In_ STACK_RETURN_INFO StackHistory[],\n\t_In_ ULONG StackHistorySize\n\t)\n{\n\tULONG stackHistoryBytes;\n\tPREMOTE_OPERATION_ALERT remoteOperationAlert;\n\n\t//\n\t// If the operation is on the current process, no problems!\n\t//\n\tif (CallerProcessId == TargetProcessId)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Calculate the size of the StackHistory array in bytes.\n\t//\n\tstackHistoryBytes = sizeof(STACK_RETURN_INFO) * (StackHistorySize - 1);\n\n\t//\n\t// Allocate space for the alert depending on the size of StackHistory.\n\t//\n\tremoteOperationAlert = RCAST<PREMOTE_OPERATION_ALERT>(ExAllocatePoolWithTag(PagedPool, sizeof(REMOTE_OPERATION_ALERT) + stackHistoryBytes, STACK_VIOLATION_TAG));\n\tif (remoteOperationAlert == NULL)\n\t{\n\t\tDBGPRINT(\"DetectionLogic!PushStackViolationAlert: Failed to allocate space for the alert.\");\n\t\treturn;\n\t}\n\tmemset(remoteOperationAlert, 0, sizeof(REMOTE_OPERATION_ALERT) + stackHistoryBytes);\n\n\t//\n\t// Fill the fields of the alert.\n\t//\n\tswitch (DetectionSource)\n\t{\n\tcase ProcessCreate:\n\t\tremoteOperationAlert->AlertInformation.AlertType = ParentProcessIdSpoofing;\n\t\tbreak;\n\tcase ThreadCreate:\n\t\tremoteOperationAlert->AlertInformation.AlertType = RemoteThreadCreation;\n\t\tbreak;\n\t}\n\tremoteOperationAlert->AlertInformation.AlertSource = DetectionSource;\n\tremoteOperationAlert->AlertInformation.SourceId = CallerProcessId;\n\tremoteOperationAlert->RemoteTargetId = TargetProcessId;\n\n\tif (SourcePath)\n\t{\n\t\tRtlStringCbCopyUnicodeString(remoteOperationAlert->AlertInformation.SourcePath, MAX_PATH, SourcePath);\n\t}\n\tif (TargetPath)\n\t{\n\t\tRtlStringCbCopyUnicodeString(remoteOperationAlert->AlertInformation.TargetPath, MAX_PATH, TargetPath);\n\t}\n\n\tremoteOperationAlert->StackHistorySize = StackHistorySize;\n\tmemcpy(&remoteOperationAlert->StackHistory, StackHistory, sizeof(STACK_RETURN_INFO) * StackHistorySize);\n\n\t//\n\t// Push the alert.\n\t//\n\tthis->alerts->PushAlert(RCAST<PBASE_ALERT_INFO>(remoteOperationAlert), sizeof(REMOTE_OPERATION_ALERT) + stackHistoryBytes);\n\n\t//\n\t// PushAlert copies the alert, so we can free our copy.\n\t//\n\tExFreePoolWithTag(remoteOperationAlert, STACK_VIOLATION_TAG);\n}\n\n/**\n\tReport a filter violation.\n\t@param DetectionSource - The filter type that was violated.\n\t@param CallerProcessId - The process ID of the caller that violated the filter.\n\t@param CallerPath - The path of the caller process.\n\t@param ViolatingPath - The path that triggered the filter violation.\n\t@param StackHistory - A variable-length array of stack return history.\n\t@param StackHistorySize - Size of the StackHistory array.\n*/\nVOID\nDetectionLogic::ReportFilterViolation (\n\t_In_ DETECTION_SOURCE DetectionSource,\n\t_In_ HANDLE CallerProcessId,\n\t_In_ PUNICODE_STRING CallerPath,\n\t_In_ PUNICODE_STRING ViolatingPath,\n\t_In_ STACK_RETURN_INFO StackHistory[],\n\t_In_ ULONG StackHistorySize\n\t)\n{\n\tULONG stackHistoryBytes;\n\tPFILTER_VIOLATION_ALERT filterViolationAlert;\n\n\t//\n\t// Sanity check, sometimes stack history can be NULL if the stackwalk failed.\n\t//\n\tif (StackHistory == NULL || StackHistorySize == 0)\n\t{\n\t\tDBGPRINT(\"DetectionLogic!ReportFilterViolation: StackHistory was invalid!\");\n\t\treturn;\n\t}\n\n\t//\n\t// Calculate the size of the StackHistory array in bytes.\n\t//\n\tstackHistoryBytes = sizeof(STACK_RETURN_INFO) * (StackHistorySize - 1);\n\n\t//\n\t// Allocate space for the alert depending on the size of StackHistory.\n\t//\n\tfilterViolationAlert = RCAST<PFILTER_VIOLATION_ALERT>(ExAllocatePoolWithTag(PagedPool, sizeof(FILTER_VIOLATION_ALERT) + stackHistoryBytes, STACK_VIOLATION_TAG));\n\tif (filterViolationAlert == NULL)\n\t{\n\t\tDBGPRINT(\"DetectionLogic!ReportFilterViolation: Failed to allocate space for the alert.\");\n\t\treturn;\n\t}\n\tmemset(filterViolationAlert, 0, sizeof(FILTER_VIOLATION_ALERT) + stackHistoryBytes);\n\n\tfilterViolationAlert->AlertInformation.AlertType = FilterViolation;\n\tfilterViolationAlert->AlertInformation.AlertSource = DetectionSource;\n\tfilterViolationAlert->AlertInformation.SourceId = CallerProcessId;\n\n\tif (CallerPath)\n\t{\n\t\tRtlStringCbCopyUnicodeString(filterViolationAlert->AlertInformation.SourcePath, MAX_PATH, CallerPath);\n\t}\n\tif (ViolatingPath)\n\t{\n\t\tRtlStringCbCopyUnicodeString(filterViolationAlert->AlertInformation.TargetPath, MAX_PATH, ViolatingPath);\n\t}\n\n\tfilterViolationAlert->StackHistorySize = StackHistorySize;\n\tmemcpy(&filterViolationAlert->StackHistory, StackHistory, sizeof(STACK_RETURN_INFO) * StackHistorySize);\n\n\t//\n\t// Push the alert.\n\t//\n\tthis->alerts->PushAlert(RCAST<PBASE_ALERT_INFO>(filterViolationAlert), sizeof(FILTER_VIOLATION_ALERT) + stackHistoryBytes);\n\n\t//\n\t// PushAlert copies the alert, so we can free our copy.\n\t//\n\tExFreePoolWithTag(filterViolationAlert, STACK_VIOLATION_TAG);\n}"
  },
  {
    "path": "PeaceMaker Kernel/DetectionLogic.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"AlertQueue.h\"\n#include \"StackWalker.h\"\n#include \"shared.h\"\n\ntypedef class DetectionLogic\n{\n\tPALERT_QUEUE alerts;\n\tStackWalker resolver;\n\n\tVOID PushStackViolationAlert (\n\t\t_In_ DETECTION_SOURCE DetectionSource,\n\t\t_In_ PVOID ViolatingAddress,\n\t\t_In_ HANDLE SourceProcessId,\n\t\t_In_ PUNICODE_STRING SourcePath,\n\t\t_In_ PUNICODE_STRING TargetPath,\n\t\t_In_ STACK_RETURN_INFO StackHistory[],\n\t\t_In_ ULONG StackHistorySize\n\t\t);\n\npublic:\n\tDetectionLogic();\n\t~DetectionLogic();\n\n\tPALERT_QUEUE GetAlertQueue (\n\t\tVOID\n\t\t);\n\n\tVOID AuditUserStackWalk (\n\t\t_In_ DETECTION_SOURCE DetectionSource,\n\t\t_In_ HANDLE SourceProcessId,\n\t\t_In_ PUNICODE_STRING SourcePath,\n\t\t_In_ PUNICODE_STRING TargetPath,\n\t\t_In_ STACK_RETURN_INFO StackHistory[],\n\t\t_In_ ULONG StackHistorySize\n\t\t);\n\n\tVOID AuditUserPointer (\n\t\t_In_ DETECTION_SOURCE DetectionSource,\n\t\t_In_ PVOID UserPtr,\n\t\t_In_ HANDLE SourceProcessId,\n\t\t_In_ PUNICODE_STRING SourcePath,\n\t\t_In_ PUNICODE_STRING TargetPath,\n\t\t_In_ STACK_RETURN_INFO StackHistory[],\n\t\t_In_ ULONG StackHistorySize\n\t\t);\n\n\tVOID AuditCallerProcessId (\n\t\t_In_ DETECTION_SOURCE DetectionSource,\n\t\t_In_ HANDLE CallerProcessId,\n\t\t_In_ HANDLE TargetProcessId,\n\t\t_In_ PUNICODE_STRING SourcePath,\n\t\t_In_ PUNICODE_STRING TargetPath,\n\t\t_In_ STACK_RETURN_INFO StackHistory[],\n\t\t_In_ ULONG StackHistorySize\n\t\t);\n\n\tVOID ReportFilterViolation (\n\t\t_In_ DETECTION_SOURCE DetectionSource,\n\t\t_In_ HANDLE CallerProcessId,\n\t\t_In_ PUNICODE_STRING CallerPath,\n\t\t_In_ PUNICODE_STRING ViolatingPath,\n\t\t_In_ STACK_RETURN_INFO StackHistory[],\n\t\t_In_ ULONG StackHistorySize\n\t\t);\n} DETECTION_LOGIC, *PDETECTION_LOGIC;\n\n#define ALERT_QUEUE_TAG 'qAmP'\n#define STACK_VIOLATION_TAG 'vSmP'"
  },
  {
    "path": "PeaceMaker Kernel/FSFilter.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"FSFilter.h\"\n\nFLT_REGISTRATION FSBlockingFilter::FilterRegistration;\nPSTRING_FILTERS FSBlockingFilter::FileStringFilters;\nSTACK_WALKER FSBlockingFilter::walker;\nPDETECTION_LOGIC FSBlockingFilter::detector;\n\n/**\n\tInitializes the necessary components of the filesystem filter.\n\t@param DriverObject - The object of the driver necessary for mini-filter initialization.\n\t@param RegistryPath - The registry path of the driver.\n\t@param UnloadRoutine - The function to call on the unload of the mini-filter.\n\t@param Detector - Detection instance used to analyze untrusted operations.\n\t@param InitializeStatus - Status of initialization.\n\t@param FilterHandle - The pointer to place the handle for the filter to.\n*/\nFSBlockingFilter::FSBlockingFilter (\n\t_In_ PDRIVER_OBJECT DriverObject,\n\t_In_ PUNICODE_STRING RegistryPath,\n\t_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,\n\t_In_ PDETECTION_LOGIC Detector,\n\t_Out_ NTSTATUS* InitializeStatus,\n\t_Out_ PFLT_FILTER* FilterHandle\n\t)\n{\n\n\tFSBlockingFilter::FileStringFilters = new (PagedPool, STRING_FILE_FILTERS_TAG) StringFilters(FilesystemFilter, RegistryPath, L\"FileFilterStore\");\n\tif (FSBlockingFilter::FileStringFilters == NULL)\n\t{\n\t\tDBGPRINT(\"FSBlockingFilter!FSBlockingFilter: Failed to allocate memory for string filters.\");\n\t\t*InitializeStatus = STATUS_NO_MEMORY;\n\t\treturn;\n\t}\n\t//\n\t// Restore existing filters.\n\t//\n\tFSBlockingFilter::FileStringFilters->RestoreFilters();\n\n\t//\n\t// This isn't a constant because the unload routine changes.\n\t//\n\tFSBlockingFilter::FilterRegistration = {\n\t\tsizeof(FLT_REGISTRATION),           //  Size\n\t\tFLT_REGISTRATION_VERSION,           //  Version\n\t\t0,                                  //  Flags\n\n\t\tNULL,                               //  Context\n\t\tCallbacks,                          //  Operation callbacks\n\t\tUnloadRoutine,\n\n\t\tFSBlockingFilter::HandleInstanceSetup,\n\t\tFSBlockingFilter::HandleInstanceQueryTeardown,\n\t\tFSBlockingFilter::HandleInstanceTeardownStart,\n\t\tFSBlockingFilter::HandleInstanceTeardownComplete,\n\n\t\tNULL,                               //  GenerateFileName\n\t\tNULL,                               //  GenerateDestinationFileName\n\t\tNULL                                //  NormalizeNameComponent\n\t};\n\n\t//\n\t//  Register with FltMgr to tell it our callback routines.\n\t//\n\t*InitializeStatus = FltRegisterFilter(DriverObject, &FilterRegistration, FilterHandle);\n\n\tFLT_ASSERT(NT_SUCCESS(*InitializeStatus));\n\n\t//\n\t// Start filtering.\n\t//\n\t*InitializeStatus = FltStartFiltering(*FilterHandle);\n\n\t//\n\t// If we can't start filtering, unregister the filter.\n\t//\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE) {\n\n\t\tFltUnregisterFilter(*FilterHandle);\n\t}\n\n\t//\n\t// Set the detector.\n\t//\n\tFSBlockingFilter::detector = Detector;\n}\n\n/**\n\tFree data members that were dynamically allocated.\n*/\nFSBlockingFilter::~FSBlockingFilter()\n{\n\tDBGPRINT(\"FSBlockingFilter!~FSBlockingFilter: Deconstructing class.\");\n\t//\n\t// Make sure to deconstruct the class.\n\t//\n\tif (FSBlockingFilter::FileStringFilters)\n\t{\n\t\tFSBlockingFilter::FileStringFilters->~StringFilters();\n\t\tExFreePoolWithTag(FSBlockingFilter::FileStringFilters, STRING_FILE_FILTERS_TAG);\n\t\tFSBlockingFilter::FileStringFilters = NULL;\n\t}\n}\n\n/**\n\tGet the pointer to the filters used by this filesystem filter. Useful if you want to add/remove filters.\n*/\nPSTRING_FILTERS FSBlockingFilter::GetStringFilters()\n{\n\treturn FSBlockingFilter::FileStringFilters;\n}\n\n/**\n\tThis function is called prior to a create operation.\n\tData - The data associated with the current operation.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tCompletionContext - Optional context to be passed to post operation callbacks.\n*/\nFLT_PREOP_CALLBACK_STATUS\nFSBlockingFilter::HandlePreCreateOperation(\n\t_Inout_ PFLT_CALLBACK_DATA Data,\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_Flt_CompletionContext_Outptr_ PVOID* CompletionContext\n\t)\n{\n\tFLT_PREOP_CALLBACK_STATUS callbackStatus;\n\tPFLT_FILE_NAME_INFORMATION fileNameInfo;\n\n\tPUNICODE_STRING callerProcessPath;\n\tPSTACK_RETURN_INFO fileOperationStack;\n\tULONG fileOperationStackSize;\n\tBOOLEAN reportOperation;\n\n\tUNREFERENCED_PARAMETER(FltObjects);\n\tUNREFERENCED_PARAMETER(CompletionContext);\n\n\treportOperation = FALSE;\n\tfileOperationStackSize = MAX_STACK_RETURN_HISTORY;\n\tfileNameInfo = NULL;\n\tcallbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;\n\n\t//\n\t// PeaceMaker is not designed to block kernel operations.\n\t//\n\tif (ExGetPreviousMode() == KernelMode)\n\t{\n\t\treturn callbackStatus;\n\t}\n\n\tif (FlagOn(Data->Iopb->Parameters.Create.Options, FILE_DELETE_ON_CLOSE))\n\t{\n\t\tif (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))\n\t\t{\n\t\t\tif (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_DELETE) != FALSE)\n\t\t\t{\n\t\t\t\tDBGPRINT(\"FSBlockingFilter!HandlePreCreateOperation: Detected FILE_DELETE_ON_CLOSE of %wZ. Prevented deletion!\", fileNameInfo->Name);\n\n\t\t\t\tData->Iopb->TargetFileObject->DeletePending = FALSE;\n\t\t\t\tData->IoStatus.Information = 0;\n\t\t\t\tData->IoStatus.Status = STATUS_ACCESS_DENIED;\n\t\t\t\tcallbackStatus = FLT_PREOP_COMPLETE;\n\t\t\t\treportOperation = TRUE;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (Data->Iopb->Parameters.Create.SecurityContext && FlagOn(Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess, FILE_EXECUTE))\n\t{\n\t\tif (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))\n\t\t{\n\t\t\tif (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_EXECUTE) != FALSE)\n\t\t\t{\n\t\t\t\tDBGPRINT(\"FSBlockingFilter!HandlePreCreateOperation: Detected FILE_EXECUTE desired access of %wZ. Prevented execute access!\", fileNameInfo->Name);\n\t\t\t\tData->Iopb->TargetFileObject->DeletePending = FALSE;\n\t\t\t\tData->IoStatus.Information = 0;\n\t\t\t\tData->IoStatus.Status = STATUS_ACCESS_DENIED;\n\t\t\t\tcallbackStatus = FLT_PREOP_COMPLETE;\n\t\t\t\treportOperation = TRUE;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (reportOperation)\n\t{\n\t\t//\n\t\t// Grab the caller's path.\n\t\t//\n\t\tImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);\n\n\t\t//\n\t\t// Walk the stack.\n\t\t//\n\t\tFSBlockingFilter::walker.WalkAndResolveStack(&fileOperationStack, &fileOperationStackSize, STACK_HISTORY_TAG);\n\n\t\tNT_ASSERT(fileOperationStack);\n\n\t\t//\n\t\t// Only if we successfully walked the stack, report the violation.\n\t\t//\n\t\tif (fileOperationStack != NULL && fileOperationStackSize != 0)\n\t\t{\n\t\t\t//\n\t\t\t// Report the violation.\n\t\t\t//\n\t\t\tFSBlockingFilter::detector->ReportFilterViolation(FileFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &fileNameInfo->Name, fileOperationStack, fileOperationStackSize);\n\n\t\t\t//\n\t\t\t// Clean up.\n\t\t\t//\n\t\t\tExFreePoolWithTag(fileOperationStack, STACK_HISTORY_TAG);\n\t\t}\n\n\t\tExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);\n\t}\n\n\tif (fileNameInfo)\n\t{\n\t\tFltReleaseFileNameInformation(fileNameInfo);\n\t}\n\n    return callbackStatus;\n}\n\n/**\n\tThis function is called prior to a write operation.\n\tData - The data associated with the current operation.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tCompletionContext - Optional context to be passed to post operation callbacks.\n*/\nFLT_PREOP_CALLBACK_STATUS\nFSBlockingFilter::HandlePreWriteOperation(\n\t_Inout_ PFLT_CALLBACK_DATA Data,\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_Flt_CompletionContext_Outptr_ PVOID* CompletionContext\n\t)\n{\n\tFLT_PREOP_CALLBACK_STATUS callbackStatus;\n\tPFLT_FILE_NAME_INFORMATION fileNameInfo;\n\n\tPUNICODE_STRING callerProcessPath;\n\tPSTACK_RETURN_INFO fileOperationStack;\n\tULONG fileOperationStackSize;\n\tBOOLEAN reportOperation;\n\n\tUNREFERENCED_PARAMETER(FltObjects);\n\tUNREFERENCED_PARAMETER(CompletionContext);\n\n\treportOperation = FALSE;\n\tfileOperationStackSize = MAX_STACK_RETURN_HISTORY;\n\tfileNameInfo = NULL;\n\tcallbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;\n\n\t//\n\t// PeaceMaker is not designed to block kernel operations.\n\t//\n\tif (ExGetPreviousMode() == KernelMode)\n\t{\n\t\treturn callbackStatus;\n\t}\n\n\tif (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))\n\t{\n\t\tif (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_WRITE) != FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"FSBlockingFilter!HandlePreWriteOperation: Detected write on %wZ. Prevented write!\", fileNameInfo->Name);\n\t\t\tData->Iopb->TargetFileObject->DeletePending = FALSE;\n\t\t\tData->IoStatus.Information = 0;\n\t\t\tData->IoStatus.Status = STATUS_ACCESS_DENIED;\n\t\t\tcallbackStatus = FLT_PREOP_COMPLETE;\n\t\t\treportOperation = TRUE;\n\t\t}\n\t}\n\n\tif (reportOperation)\n\t{\n\t\t//\n\t\t// Grab the caller's path.\n\t\t//\n\t\tImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);\n\n\t\t//\n\t\t// Walk the stack.\n\t\t//\n\t\tFSBlockingFilter::walker.WalkAndResolveStack(&fileOperationStack, &fileOperationStackSize, STACK_HISTORY_TAG);\n\n\t\tNT_ASSERT(fileOperationStack);\n\n\t\t//\n\t\t// Only if we successfully walked the stack, report the violation.\n\t\t//\n\t\tif (fileOperationStack != NULL && fileOperationStackSize != 0)\n\t\t{\n\t\t\t//\n\t\t\t// Report the violation.\n\t\t\t//\n\t\t\tFSBlockingFilter::detector->ReportFilterViolation(FileFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &fileNameInfo->Name, fileOperationStack, fileOperationStackSize);\n\n\t\t\t//\n\t\t\t// Clean up.\n\t\t\t//\n\t\t\tExFreePoolWithTag(fileOperationStack, STACK_HISTORY_TAG);\n\t\t}\n\n\t\tExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);\n\t}\n\n\tif (fileNameInfo)\n\t{\n\t\tFltReleaseFileNameInformation(fileNameInfo);\n\t}\n\n\treturn callbackStatus;\n}\n\n/**\n\tThis function is called prior to a set information operation.\n\tData - The data associated with the current operation.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tCompletionContext - Optional context to be passed to post operation callbacks.\n*/\nFLT_PREOP_CALLBACK_STATUS\nFSBlockingFilter::HandlePreSetInfoOperation(\n\t_Inout_ PFLT_CALLBACK_DATA Data,\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_Flt_CompletionContext_Outptr_ PVOID* CompletionContext\n\t)\n{\n\tFLT_PREOP_CALLBACK_STATUS callbackStatus;\n\tPFLT_FILE_NAME_INFORMATION fileNameInfo;\n\n\tPUNICODE_STRING callerProcessPath;\n\tPSTACK_RETURN_INFO fileOperationStack;\n\tULONG fileOperationStackSize;\n\tBOOLEAN reportOperation;\n\n\tUNREFERENCED_PARAMETER(FltObjects);\n\tUNREFERENCED_PARAMETER(CompletionContext);\n\n\treportOperation = FALSE;\n\tfileOperationStackSize = MAX_STACK_RETURN_HISTORY;\n\tfileNameInfo = NULL;\n\tcallbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;\n\n\t//\n\t// PeaceMaker is not designed to block kernel operations.\n\t//\n\tif (ExGetPreviousMode() == KernelMode)\n\t{\n\t\treturn callbackStatus;\n\t}\n\n\tswitch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass) {\n\tcase FileDispositionInformation:\n\tcase FileDispositionInformationEx:\n\t\tif (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &fileNameInfo)))\n\t\t{\n\t\t\tif (FSBlockingFilter::FileStringFilters->MatchesFilter(fileNameInfo->Name.Buffer, FILTER_FLAG_DELETE) != FALSE)\n\t\t\t{\n\t\t\t\tDBGPRINT(\"FSBlockingFilter!HandlePreSetInfoOperation: Detected attempted file deletion of %wZ. Prevented deletion!\", fileNameInfo->Name);\n\t\t\t\tData->IoStatus.Information = 0;\n\t\t\t\tData->IoStatus.Status = STATUS_ACCESS_DENIED;\n\t\t\t\tcallbackStatus = FLT_PREOP_COMPLETE;\n\t\t\t\treportOperation = TRUE;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\n\tif (reportOperation)\n\t{\n\t\t//\n\t\t// Grab the caller's path.\n\t\t//\n\t\tImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);\n\n\t\t//\n\t\t// Walk the stack.\n\t\t//\n\t\tFSBlockingFilter::walker.WalkAndResolveStack(&fileOperationStack, &fileOperationStackSize, STACK_HISTORY_TAG);\n\n\t\tNT_ASSERT(fileOperationStack);\n\n\t\t//\n\t\t// Only if we successfully walked the stack, report the violation.\n\t\t//\n\t\tif (fileOperationStack != NULL && fileOperationStackSize != 0)\n\t\t{\n\t\t\t//\n\t\t\t// Report the violation.\n\t\t\t//\n\t\t\tFSBlockingFilter::detector->ReportFilterViolation(FileFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &fileNameInfo->Name, fileOperationStack, fileOperationStackSize);\n\n\t\t\t//\n\t\t\t// Clean up.\n\t\t\t//\n\t\t\tExFreePoolWithTag(fileOperationStack, STACK_HISTORY_TAG);\n\t\t}\n\n\t\tExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);\n\t}\n\n\tif (fileNameInfo)\n\t{\n\t\tFltReleaseFileNameInformation(fileNameInfo);\n\t}\n\n\treturn callbackStatus;\n}\n\n/**\n\tThis function determines whether or not the mini-filter should attach to the volume.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tFlags - Flags that indicate the reason for the volume attach request.\n\tVolumeDeviceType - The device type of the specified volume.\n\tVolumeFilesystemType - The filesystem type of the specified volume.\n*/\nNTSTATUS\nFSBlockingFilter::HandleInstanceSetup(\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_In_ FLT_INSTANCE_SETUP_FLAGS Flags,\n\t_In_ DEVICE_TYPE VolumeDeviceType,\n\t_In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType\n\t)\n{\n\tNTSTATUS status = STATUS_SUCCESS;\n\tBOOLEAN isWritable = FALSE;\n\n\tUNREFERENCED_PARAMETER(Flags);\n\tUNREFERENCED_PARAMETER(VolumeDeviceType);\n\n\tstatus = FltIsVolumeWritable(FltObjects->Volume,\n\t\t&isWritable);\n\n\tif (!NT_SUCCESS(status)) {\n\n\t\treturn STATUS_FLT_DO_NOT_ATTACH;\n\t}\n\n\t//\n\t// If you can't write to a volume... how can you delete a file in it?\n\t//\n\tif (isWritable) {\n\n\t\tswitch (VolumeFilesystemType) {\n\n\t\tcase FLT_FSTYPE_NTFS:\n\t\tcase FLT_FSTYPE_REFS:\n\n\t\t\tstatus = STATUS_SUCCESS;\n\t\t\tbreak;\n\n\t\tdefault:\n\n\t\t\treturn STATUS_FLT_DO_NOT_ATTACH;\n\t\t}\n\n\t}\n\telse {\n\n\t\treturn STATUS_FLT_DO_NOT_ATTACH;\n\t}\n\n\treturn status;\n}\n\n\n/**\n\tThis function is called when an instance is being deleted.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tFlags - Flags that indicate the reason for the detach request.\n*/\nNTSTATUS\nFSBlockingFilter::HandleInstanceQueryTeardown(\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags\n\t)\n{\n\tUNREFERENCED_PARAMETER(FltObjects);\n\tUNREFERENCED_PARAMETER(Flags);\n\n\treturn STATUS_SUCCESS;\n}\n\n/**\n\tThis function is called at the start of an instance teardown.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tFlags - Flags that indicate the reason for the deletion.\n*/\nVOID\nFSBlockingFilter::HandleInstanceTeardownStart(\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags\n\t)\n{\n\tUNREFERENCED_PARAMETER(FltObjects);\n\tUNREFERENCED_PARAMETER(Flags);\n}\n\n/**\n\tThis function is called at the end of an instance teardown.\n\tFltObjects - Objects related to the filter, instance, and its associated volume.\n\tFlags - Flags that indicate the reason for the deletion.\n*/\nVOID\nFSBlockingFilter::HandleInstanceTeardownComplete(\n\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags\n\t)\n{\n\tUNREFERENCED_PARAMETER(FltObjects);\n\tUNREFERENCED_PARAMETER(Flags);\n}"
  },
  {
    "path": "PeaceMaker Kernel/FSFilter.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"StringFilters.h\"\n#include \"StackWalker.h\"\n#include \"ImageHistoryFilter.h\"\n\ntypedef class FSBlockingFilter\n{\n\tstatic FLT_PREOP_CALLBACK_STATUS\n\tHandlePreCreateOperation (\n\t\t_Inout_ PFLT_CALLBACK_DATA Data,\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_Flt_CompletionContext_Outptr_ PVOID* CompletionContext\n\t\t);\n\n\tstatic FLT_PREOP_CALLBACK_STATUS\n\tHandlePreWriteOperation (\n\t\t_Inout_ PFLT_CALLBACK_DATA Data,\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_Flt_CompletionContext_Outptr_ PVOID* CompletionContext\n\t\t);\n\n\tstatic FLT_PREOP_CALLBACK_STATUS\n\tHandlePreSetInfoOperation (\n\t\t_Inout_ PFLT_CALLBACK_DATA Data,\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_Flt_CompletionContext_Outptr_ PVOID* CompletionContext\n\t\t);\n\n\tstatic NTSTATUS\n\tHandleInstanceSetup (\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_In_ FLT_INSTANCE_SETUP_FLAGS Flags,\n\t\t_In_ DEVICE_TYPE VolumeDeviceType,\n\t\t_In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType\n\t\t);\n\n\tstatic NTSTATUS\n\tHandleInstanceQueryTeardown (\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags\n\t\t);\n\n\tstatic VOID\n\tHandleInstanceTeardownStart (\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags\n\t\t);\n\n\tstatic VOID\n\tHandleInstanceTeardownComplete (\n\t\t_In_ PCFLT_RELATED_OBJECTS FltObjects,\n\t\t_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags\n\t\t);\n\n\t//\n\t// Class callbacks for necessary filesystem operations.\n\t//\n\tstatic constexpr FLT_OPERATION_REGISTRATION Callbacks[] = {\n\n\t\t{ IRP_MJ_CREATE,\n\t\t  0,\n\t\t  FSBlockingFilter::HandlePreCreateOperation,\n\t\t  NULL },\n\n\t\t{ IRP_MJ_WRITE,\n\t\t  0,\n\t\t  FSBlockingFilter::HandlePreWriteOperation,\n\t\t  NULL },\n\n\t\t{ IRP_MJ_SET_INFORMATION,\n\t\t  FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,\n\t\t  FSBlockingFilter::HandlePreSetInfoOperation,\n\t\t  NULL },\n\n\t\t{ IRP_MJ_OPERATION_END }\n\t};\n\n\t//\n\t// The registration context for the mini-filter.\n\t//\n\tstatic FLT_REGISTRATION FilterRegistration;\n\n\t//\n\t// Contains strings to block various filesystem operations.\n\t//\n\tstatic PSTRING_FILTERS FileStringFilters;\n\n\tstatic STACK_WALKER walker;\n\tstatic PDETECTION_LOGIC detector;\npublic:\n\tFSBlockingFilter (\n\t\t_In_ PDRIVER_OBJECT DriverObject,\n\t\t_In_ PUNICODE_STRING RegistryPath,\n\t\t_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,\n\t\t_In_ PDETECTION_LOGIC Detector,\n\t\t_Out_ NTSTATUS* InitializeStatus,\n\t\t_Out_ PFLT_FILTER* FilterHandle\n\t\t);\n\t~FSBlockingFilter();\n\n\tstatic PSTRING_FILTERS GetStringFilters();\n\t\n} FS_BLOCKING_FILTER, *PFS_BLOCKING_FILTER;\n\n#define STRING_FILE_FILTERS_TAG 'fFmP'"
  },
  {
    "path": "PeaceMaker Kernel/FilterTesting.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"common.h\"\n#include \"IOCTLCommunication.h\"\n\nPIOCTL_COMMUNICATION Communicator;\n\n#pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, \"Not valid for kernel mode drivers\")\n\n/*************************************************************************\n    Prototypes\n*************************************************************************/\n\nEXTERN_C_START\n\nDRIVER_INITIALIZE DriverEntry;\nNTSTATUS\nDriverEntry (\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PUNICODE_STRING RegistryPath\n    );\n\nNTSTATUS\nFilterUnload(\n    _In_ FLT_FILTER_UNLOAD_FLAGS Flags\n    );\n\nEXTERN_C_END\n\n//\n//  Assign text sections for each routine.\n//\n\n#ifdef ALLOC_PRAGMA\n#pragma alloc_text(INIT, DriverEntry)\n#pragma alloc_text(PAGE, FilterUnload)\n#endif\n\n/*************************************************************************\n    MiniFilter initialization and unload routines.\n*************************************************************************/\n\n/**\n\tInitialize the mini-filter driver.\n\tDriverObject - The driver's object.\n\tRegistryPath - The path to the driver's registry entry.\n*/\nNTSTATUS\nDriverEntry (\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PUNICODE_STRING RegistryPath\n    )\n{\n    NTSTATUS status;\n\n\tstatus = STATUS_SUCCESS;\n\n\tDBGPRINT(\"FilterTesting!DriverEntry: Hello world.\");\n\n\tCommunicator = new (NonPagedPool, 'cImP') IOCTLCommunication(DriverObject, RegistryPath, NULL, &status);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"FilterTesting!DriverEntry: Failed to initialize communication with status 0x%X.\", status);\n\t}\n\n    return status;\n}\n\n/**\n\tThis function handles unloading the mini-filter.\n\t@param Flags - Flags indicating whether or not this is a mandatory unload.\n*/\nNTSTATUS\nFilterUnload (\n    _In_ FLT_FILTER_UNLOAD_FLAGS Flags\n    )\n{\n    UNREFERENCED_PARAMETER( Flags );\n\n    PAGED_CODE();\n\n\tDBGPRINT(\"FilterTesting!FilterUnload: Unloading filter.\");\n\n\tCommunicator->~IOCTLCommunication();\n\tExFreePoolWithTag(Communicator, 'cImP');\n\n    return STATUS_SUCCESS;\n}"
  },
  {
    "path": "PeaceMaker Kernel/IOCTLCommunication.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"IOCTLCommunication.h\"\n\nPDRIVER_OBJECT IOCTLCommunication::DriverObject;\nPDETECTION_LOGIC IOCTLCommunication::Detector;\nPIMAGE_HISTORY_FILTER IOCTLCommunication::ImageProcessFilter;\nPFLT_FILTER IOCTLCommunication::FileFilterHandle;\nPFS_BLOCKING_FILTER IOCTLCommunication::FilesystemMonitor;\nPREGISTRY_BLOCKING_FILTER IOCTLCommunication::RegistryMonitor;\nPTHREAD_FILTER IOCTLCommunication::ThreadOperationFilter;\nPTAMPER_GUARD IOCTLCommunication::TamperGuardFilter;\n\n/**\n\tConstruct the IOCTLCommunication class by initializing the driver object and detector.\n\t@param DriverObject - The driver's object.\n\t@param RegistryPath - The registry path of the driver.\n\t@param UnloadRoutine - The routine to call when the filter is unloading.\n\t@param InitializeStatus - Status of initialization.\n*/\nIOCTLCommunication::IOCTLCommunication (\n\t_In_ PDRIVER_OBJECT Driver,\n\t_In_ PUNICODE_STRING RegistryPath,\n\t_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,\n\t_Inout_ NTSTATUS* InitializeStatus\n\t)\n{\n\tthis->DriverObject = Driver;\n\n\t*InitializeStatus = STATUS_SUCCESS;\n\n\t//\n\t// Initialize the class members.\n\t//\n\tthis->Detector = new (NonPagedPool, DETECTION_LOGIC_TAG) DetectionLogic();\n\tif (this->Detector == NULL)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to allocate space for detection logic.\");\n\t\t*InitializeStatus = STATUS_NO_MEMORY;\n\t\treturn;\n\t}\n\n\tthis->ImageProcessFilter = new (NonPagedPool, IMAGE_HISTORY_FILTER_TAG) ImageHistoryFilter(this->Detector, InitializeStatus);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to initialize image process history filter with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\tif (this->ImageProcessFilter == NULL)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to allocate space for image process history filter.\");\n\t\t*InitializeStatus = STATUS_NO_MEMORY;\n\t\treturn;\n\t}\n\n\tFilesystemMonitor = new (NonPagedPool, FILE_MONITOR_TAG) FSBlockingFilter(DriverObject, RegistryPath, UnloadRoutine, this->Detector, InitializeStatus, &FileFilterHandle);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to initialize the filesystem blocking filter with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\n\tRegistryMonitor = new (NonPagedPool, REGISTRY_MONITOR_TAG) RegistryBlockingFilter(DriverObject, RegistryPath, this->Detector, InitializeStatus);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to initialize the registry blocking filter with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\n\tthis->ThreadOperationFilter = new (NonPagedPool, THREAD_FILTER_TAG) ThreadFilter(this->Detector, InitializeStatus);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to initialize thread operation filters with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\tif (this->ThreadOperationFilter == NULL)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to allocate space for thread operation filters.\");\n\t\t*InitializeStatus = STATUS_NO_MEMORY;\n\t\treturn;\n\t}\n\n\tthis->TamperGuardFilter = new (NonPagedPool, TAMPER_GUARD_TAG) TamperGuard(InitializeStatus);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLCommunication: Failed to initialize tamper guard with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\n\tInitializeDriverIOCTL();\n}\n\n/**\n\tDeconstruct the IOCTLCommunication class.\n*/\nIOCTLCommunication::~IOCTLCommunication\t(\n\tVOID\n\t)\n{\n\tthis->Detector->~DetectionLogic();\n\tExFreePoolWithTag(this->Detector, DETECTION_LOGIC_TAG);\n\n\tthis->ImageProcessFilter->~ImageHistoryFilter();\n\tExFreePoolWithTag(this->ImageProcessFilter, IMAGE_HISTORY_FILTER_TAG);\n\n\tFltUnregisterFilter(FileFilterHandle);\n\n\tthis->FilesystemMonitor->~FSBlockingFilter();\n\tExFreePoolWithTag(this->FilesystemMonitor, FILE_MONITOR_TAG);\n\n\tthis->RegistryMonitor->~RegistryBlockingFilter();\n\tExFreePoolWithTag(this->RegistryMonitor, REGISTRY_MONITOR_TAG);\n\n\tthis->ThreadOperationFilter->~ThreadFilter();\n\tExFreePoolWithTag(this->ThreadOperationFilter, THREAD_FILTER_TAG);\n\n\tthis->TamperGuardFilter->~TamperGuard();\n\tExFreePoolWithTag(this->TamperGuardFilter, TAMPER_GUARD_TAG);\n\n\tUninitializeDriverIOCTL();\n}\n\n/**\n\tHandle basic create / close of device, always return success with no change.\n\t@param DeviceObject - The driver's device object.\n\t@param Irp - The current IRP.\n*/\nNTSTATUS\nIOCTLCommunication::IOCTLCreateClose (\n\t_In_ PDEVICE_OBJECT DeviceObject,\n\t_In_ PIRP Irp\n\t)\n{\n\tUNREFERENCED_PARAMETER(DeviceObject);\n\n\t//\n\t// Just accept everyone for now.\n\t// TODO: Implement some sort of authentication?\n\t//\n\tIrp->IoStatus.Status = STATUS_SUCCESS;\n\tIrp->IoStatus.Information = 0;\n\n\tIoCompleteRequest(Irp, IO_NO_INCREMENT);\n\n\treturn STATUS_SUCCESS;\n}\n\n/**\n\tHandle IO controls for communication with the PeaceMaker user-mode interface.\n\t@param DeviceObject - The driver's device object.\n\t@param Irp - The current IRP.\n*/\nNTSTATUS\nIOCTLCommunication::IOCTLDeviceControl (\n\t_In_ PDEVICE_OBJECT DeviceObject,\n\t_In_ PIRP Irp\n\t)\n{\n\tNTSTATUS status;\n\tPIO_STACK_LOCATION irpStackLocation;\n\tULONG ioctlCode;\n\tULONG inputLength;\n\tULONG outputLength;\n\tULONG minimumLength;\n\tULONG writtenLength;\n\n\tPBASE_ALERT_INFO poppedAlert;\n\tPPROCESS_SUMMARY_REQUEST processSummaryRequest;\n\tPPROCESS_DETAILED_REQUEST processDetailedRequest;\n\tPSTRING_FILTER_REQUEST filterAddRequest;\n\tPLIST_FILTERS_REQUEST listFiltersRequest;\n\tPIMAGE_DETAILED_REQUEST imageDetailedRequest;\n\tPDELETE_FILTER_REQUEST deleteFilterRequest;\n\tPGLOBAL_SIZES globalSizes;\n\n\tWCHAR temporaryFilterBuffer[MAX_PATH];\n\n\tUNREFERENCED_PARAMETER(DeviceObject);\n\n\tstatus = STATUS_SUCCESS;\n\tirpStackLocation = IoGetCurrentIrpStackLocation(Irp);\n\n\t//\n\t// Grab basic information about the request.\n\t//\n\tioctlCode = irpStackLocation->Parameters.DeviceIoControl.IoControlCode;\n\tinputLength = irpStackLocation->Parameters.DeviceIoControl.InputBufferLength;\n\toutputLength = irpStackLocation->Parameters.DeviceIoControl.OutputBufferLength;\n\twrittenLength = 0;\n\t\n\t//\n\t// Update the tamper guard.\n\t//\n\tIOCTLCommunication::TamperGuardFilter->UpdateProtectedProcess(PsGetCurrentProcessId());\n\n\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: ioctlCode = 0x%X, inputLength = 0x%X, outputLength = 0x%X\", ioctlCode, inputLength, outputLength);\n\n\t//\n\t// Handle the different IOCTL request types.\n\t//\n\tswitch (ioctlCode)\n\t{\n\tcase IOCTL_ALERTS_QUEUED:\n\t\tif (outputLength >= sizeof(BOOLEAN))\n\t\t{\n\t\t\t//\n\t\t\t// Return the status of the Queue.\n\t\t\t//\n\t\t\t*RCAST<BOOLEAN*>(Irp->AssociatedIrp.SystemBuffer) = !IOCTLCommunication::Detector->GetAlertQueue()->IsQueueEmpty();\n\t\t\twrittenLength = sizeof(BOOLEAN);\n\t\t}\n\t\tbreak;\n\tcase IOCTL_POP_ALERT:\n\t\tif (outputLength < MAX_STACK_VIOLATION_ALERT_SIZE)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_POP_ALERT but output buffer with size 0x%X smaller then minimum 0x%X.\", outputLength, MAX_STACK_VIOLATION_ALERT_SIZE);\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\t\t//\n\t\t// Pop an alert from the queue.\n\t\t//\n\t\tpoppedAlert = IOCTLCommunication::Detector->GetAlertQueue()->PopAlert();\n\t\tif (poppedAlert == NULL)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_POP_ALERT but no alert to pop.\");\n\t\t\tstatus = STATUS_NOT_FOUND;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Got alert 0x%llx for IOCTL_POP_ALERT with size 0x%llx.\\n\", poppedAlert, poppedAlert->AlertSize);\n\n\t\t//\n\t\t// Copy the alert.\n\t\t//\n\t\tmemcpy_s(Irp->AssociatedIrp.SystemBuffer, outputLength, poppedAlert, poppedAlert->AlertSize);\n\n\t\twrittenLength = poppedAlert->AlertSize;\n\n\t\t//\n\t\t// Free the alert entry.\n\t\t//\n\t\tIOCTLCommunication::Detector->GetAlertQueue()->FreeAlert(poppedAlert);\n\t\tbreak;\n\tcase IOCTL_GET_PROCESSES:\n\t\tif (inputLength < sizeof(PROCESS_SUMMARY_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESSES but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Verify the specified array size.\n\t\t//\n\t\tprocessSummaryRequest = RCAST<PPROCESS_SUMMARY_REQUEST>(Irp->AssociatedIrp.SystemBuffer);\n\t\tif (processSummaryRequest->ProcessHistorySize <= 0 || outputLength < MAX_PROCESS_SUMMARY_REQUEST_SIZE(processSummaryRequest))\n\t\t{\n\t\t\tDBGPRINT(\"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));\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Grab the history summaries.\n\t\t//\n\t\tprocessSummaryRequest->ProcessHistorySize = IOCTLCommunication::ImageProcessFilter->GetProcessHistorySummary(processSummaryRequest->SkipCount, RCAST<PPROCESS_SUMMARY_ENTRY>(&processSummaryRequest->ProcessHistory[0]), processSummaryRequest->ProcessHistorySize);\n\t\twrittenLength = MAX_PROCESS_SUMMARY_REQUEST_SIZE(processSummaryRequest);\n\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: IOCTL_GET_PROCESSES found %i processes.\", processSummaryRequest->ProcessHistorySize);\n\t\tbreak;\n\tcase IOCTL_GET_PROCESS_DETAILED:\n\t\tif (inputLength < sizeof(PROCESS_DETAILED_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_DETAILED but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tprocessDetailedRequest = RCAST<PPROCESS_DETAILED_REQUEST>(Irp->AssociatedIrp.SystemBuffer);\n\n\t\tminimumLength = sizeof(PROCESS_DETAILED_REQUEST);\n\t\t//\n\t\t// Verify the specified array size.\n\t\t//\n\t\tif (outputLength < minimumLength)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_DETAILED but output buffer with size 0x%X smaller then minimum 0x%X.\", outputLength, minimumLength);\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Verify the user buffers.\n\t\t//\n\t\t__try\n\t\t{\n\t\t\tProbeForWrite(processDetailedRequest->ImageSummary, processDetailedRequest->ImageSummarySize * sizeof(IMAGE_SUMMARY), sizeof(ULONG));\n\t\t\tProbeForWrite(processDetailedRequest->StackHistory, processDetailedRequest->StackHistorySize * sizeof(STACK_RETURN_INFO), sizeof(ULONG));\n\t\t}\n\t\t__except (1)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_DETAILED but user buffers were invalid.\");\n\t\t\tstatus = STATUS_BAD_DATA;\n\t\t\tgoto Exit;\n\t\t}\n\t\t\n\t\t//\n\t\t// Populate the detailed request.\n\t\t//\n\t\tIOCTLCommunication::ImageProcessFilter->PopulateProcessDetailedRequest(processDetailedRequest);\n\t\twrittenLength = minimumLength;\n\t\tbreak;\n\tcase IOCTL_ADD_FILTER:\n\t\t//\n\t\t// Validate the size of the input and output buffers.\n\t\t//\n\t\tif (inputLength < sizeof(STRING_FILTER_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_ADD_FILTER but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\t\tif (outputLength < sizeof(STRING_FILTER_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_ADD_FILTER but output buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tfilterAddRequest = RCAST<PSTRING_FILTER_REQUEST>(Irp->AssociatedIrp.SystemBuffer);\n\n\t\t//\n\t\t// Copy the filter content to a temporary string (ensures null-terminator).\n\t\t//\n\t\tstatus = RtlStringCchCopyNW(temporaryFilterBuffer, MAX_PATH, filterAddRequest->Filter.MatchString, MAX_PATH);\n\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Failed to copy filter content to temporary buffer with status 0x%X.\", status);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Sanity check.\n\t\t//\n\t\tif (wcsnlen_s(temporaryFilterBuffer, MAX_PATH) == 0)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Blocked empty filter.\");\n\t\t\tgoto Exit;\n\t\t}\n\t\t\n\t\t//\n\t\t// Depending on the type of filter, add the string.\n\t\t//\n\t\tswitch (filterAddRequest->FilterType)\n\t\t{\n\t\tcase FilesystemFilter:\n\t\t\tfilterAddRequest->Filter.Id = FilesystemMonitor->GetStringFilters()->AddFilter(temporaryFilterBuffer, filterAddRequest->Filter.Flags);\n\t\t\tbreak;\n\t\tcase RegistryFilter:\n\t\t\tfilterAddRequest->Filter.Id = RegistryMonitor->GetStringFilters()->AddFilter(temporaryFilterBuffer, filterAddRequest->Filter.Flags);\n\t\t\tbreak;\n\t\t}\n\t\twrittenLength = sizeof(STRING_FILTER_REQUEST);\n\t\tbreak;\n\tcase IOCTL_LIST_FILTERS:\n\t\t//\n\t\t// Validate the size of the input and output buffers.\n\t\t//\n\t\tif (inputLength < sizeof(LIST_FILTERS_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_LIST_FILTERS but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\t\tif (outputLength < sizeof(LIST_FILTERS_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_LIST_FILTERS but output buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tlistFiltersRequest = RCAST<PLIST_FILTERS_REQUEST>(Irp->AssociatedIrp.SystemBuffer);\n\t\tswitch (listFiltersRequest->FilterType)\n\t\t{\n\t\tcase FilesystemFilter:\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Retrieving filesystem filters.\");\n\t\t\tlistFiltersRequest->CopiedFilters = FilesystemMonitor->GetStringFilters()->GetFilters(listFiltersRequest->SkipFilters, RCAST<PFILTER_INFO>(&listFiltersRequest->Filters), 10);\n\t\t\tbreak;\n\t\tcase RegistryFilter:\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Retrieving registry filters.\");\n\t\t\tlistFiltersRequest->CopiedFilters = RegistryMonitor->GetStringFilters()->GetFilters(listFiltersRequest->SkipFilters, RCAST<PFILTER_INFO>(&listFiltersRequest->Filters), 10);\n\t\t\tbreak;\n\t\t}\n\t\twrittenLength = sizeof(LIST_FILTERS_REQUEST);\n\t\tbreak;\n\tcase IOCTL_GET_PROCESS_SIZES:\n\t\t//\n\t\t// Validate the size of the input and output buffers.\n\t\t//\n\t\tif (inputLength < sizeof(PROCESS_SIZES_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_SIZES but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\t\tif (outputLength < sizeof(PROCESS_SIZES_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_PROCESS_SIZES but output buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tIOCTLCommunication::ImageProcessFilter->PopulateProcessSizes(RCAST<PPROCESS_SIZES_REQUEST>(Irp->AssociatedIrp.SystemBuffer));\n\t\twrittenLength = sizeof(PROCESS_SIZES_REQUEST);\n\t\tbreak;\n\tcase IOCTL_GET_IMAGE_DETAILED:\n\t\t//\n\t\t// Validate the size of the input and output buffers.\n\t\t//\n\t\tif (inputLength < sizeof(IMAGE_DETAILED_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_IMAGE_DETAILED but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\timageDetailedRequest = RCAST<PIMAGE_DETAILED_REQUEST>(Irp->AssociatedIrp.SystemBuffer);\n\t\tminimumLength = MAX_IMAGE_DETAILED_REQUEST_SIZE(imageDetailedRequest);\n\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: IOCTL_GET_IMAGE_DETAILED minimumLength = 0x%X.\", minimumLength);\n\n\t\tif (inputLength < minimumLength)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_IMAGE_DETAILED but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\t\tif (outputLength < minimumLength)\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_IMAGE_DETAILED but output buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\t\tIOCTLCommunication::ImageProcessFilter->PopulateImageDetailedRequest(imageDetailedRequest);\n\t\twrittenLength = MAX_IMAGE_DETAILED_REQUEST_SIZE(imageDetailedRequest);\n\t\tbreak;\n\tcase IOCTL_GET_GLOBAL_SIZES:\n\t\t//\n\t\t// Validate the size of the output buffer.\n\t\t//\n\t\tif (outputLength < sizeof(GLOBAL_SIZES))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_GET_GLOBAL_SIZES but output buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tglobalSizes = RCAST<PGLOBAL_SIZES>(Irp->AssociatedIrp.SystemBuffer);\n\t\tglobalSizes->ProcessHistorySize = ImageHistoryFilter::ProcessHistorySize;\n\t\tglobalSizes->FilesystemFilterSize = FilesystemMonitor->GetStringFilters()->filtersCount;\n\t\tglobalSizes->RegistryFilterSize = RegistryMonitor->GetStringFilters()->filtersCount;\n\t\twrittenLength = sizeof(GLOBAL_SIZES);\n\t\tbreak;\n\tcase IOCTL_DELETE_FILTER:\n\t\t//\n\t\t// Validate the size of the input buffer.\n\t\t//\n\t\tif (inputLength < sizeof(DELETE_FILTER_REQUEST))\n\t\t{\n\t\t\tDBGPRINT(\"IOCTLCommunication!IOCTLDeviceControl: Received IOCTL_DELETE_FILTER but input buffer is too small.\");\n\t\t\tstatus = STATUS_INSUFFICIENT_RESOURCES;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tdeleteFilterRequest = RCAST<PDELETE_FILTER_REQUEST>(Irp->AssociatedIrp.SystemBuffer);\n\t\tswitch (deleteFilterRequest->FilterType)\n\t\t{\n\t\tcase FilesystemFilter:\n\t\t\tdeleteFilterRequest->Deleted = FilesystemMonitor->GetStringFilters()->RemoveFilter(deleteFilterRequest->FilterId);\n\t\t\tbreak;\n\t\tcase RegistryFilter:\n\t\t\tdeleteFilterRequest->Deleted = RegistryMonitor->GetStringFilters()->RemoveFilter(deleteFilterRequest->FilterId);\n\t\t\tbreak;\n\t\t}\n\t\twrittenLength = sizeof(DELETE_FILTER_REQUEST);\n\t\tbreak;\n\t}\n\nExit:\n\tIrp->IoStatus.Status = status;\n\tIrp->IoStatus.Information = writtenLength;\n\n\tIoCompleteRequest(Irp, IO_NO_INCREMENT);\n\n\treturn status;\n}\n\n/**\n\tInitialize the driver object to support IOCTL communication.\n*/\nNTSTATUS\nIOCTLCommunication::InitializeDriverIOCTL (\n\tVOID\n\t)\n{\n\tNTSTATUS status;\n\tUNICODE_STRING ioctlDeviceName;\n\tUNICODE_STRING ioctlDosDevicesName;\n\tPDEVICE_OBJECT ioctlDevice;\n\n\tRtlInitUnicodeString(&ioctlDeviceName, NT_DEVICE_NAME);\n\n\t//\n\t// Create IO Device Object.\n\t// TODO: Implement secure device creation (with secure DACL).\n\t//\n\tstatus = IoCreateDevice(DriverObject, NULL, &ioctlDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, TRUE, &ioctlDevice);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!InitializeDriverIOCTL: Failed to create kernel device object with error 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Set the handlers for our IOCTL.\n\t//\n\tDriverObject->MajorFunction[IRP_MJ_CREATE] = IOCTLCreateClose;\n\tDriverObject->MajorFunction[IRP_MJ_CLOSE] = IOCTLCreateClose;\n\tDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOCTLDeviceControl;\n\n\tRtlInitUnicodeString(&ioctlDosDevicesName, DOS_DEVICE_NAME);\n\n\tstatus = IoCreateSymbolicLink(&ioctlDosDevicesName, &ioctlDeviceName);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"IOCTLCommunication!InitializeDriverIOCTL: Failed to create symbolic link to device with error 0x%X.\", status);\n\t\tIoDeleteDevice(ioctlDevice);\n\t\tgoto Exit;\n\t}\nExit:\n\treturn status;\n}\n\n/**\n\tUndo everything done in InitializeDriverObject.\n\t@return The status of uninitialization.\n*/\nVOID\nIOCTLCommunication::UninitializeDriverIOCTL (\n\tVOID\n\t)\n{\n\tPDEVICE_OBJECT deviceObject;\n\tUNICODE_STRING ioctlDosDevicesName;\n\n\tdeviceObject = DriverObject->DeviceObject;\n\n\t//\n\t// Initialize the unicode string of our DosDevices symlink.\n\t//\n\tRtlInitUnicodeString(&ioctlDosDevicesName, DOS_DEVICE_NAME);\n\n\t//\n\t// Delete IOCTL symlink because we're unloading.\n\t//\n\tIoDeleteSymbolicLink(&ioctlDosDevicesName);\n\tif (deviceObject != NULL)\n\t{\n\t\t//\n\t\t// Delete the device while unloading.\n\t\t//\n\t\tIoDeleteDevice(deviceObject);\n\t}\n}"
  },
  {
    "path": "PeaceMaker Kernel/IOCTLCommunication.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"DetectionLogic.h\"\n#include \"ImageHistoryFilter.h\"\n#include \"ThreadFilter.h\"\n#include \"FSFilter.h\"\n#include \"RegistryFilter.h\"\n#include \"TamperGuard.h\"\n\ntypedef class IOCTLCommunication\n{\n\tstatic PDRIVER_OBJECT DriverObject;\n\tstatic PDETECTION_LOGIC Detector;\n\tstatic PIMAGE_HISTORY_FILTER ImageProcessFilter;\n\tstatic PFLT_FILTER FileFilterHandle;\n\tstatic PFS_BLOCKING_FILTER FilesystemMonitor;\n\tstatic PREGISTRY_BLOCKING_FILTER RegistryMonitor;\n\tstatic PTHREAD_FILTER ThreadOperationFilter;\n\tstatic PTAMPER_GUARD TamperGuardFilter;\n\n\tNTSTATUS InitializeDriverIOCTL(VOID);\n\tVOID UninitializeDriverIOCTL(VOID);\n\n\tstatic NTSTATUS IOCTLCreateClose(\n\t\t_In_ PDEVICE_OBJECT DeviceObject,\n\t\t_In_ PIRP Irp\n\t\t);\n\tstatic NTSTATUS IOCTLDeviceControl(\n\t\t_In_ PDEVICE_OBJECT DeviceObject,\n\t\t_In_ PIRP Irp\n\t\t);\n\npublic:\n\tIOCTLCommunication(\n\t\t_In_ PDRIVER_OBJECT Driver,\n\t\t_In_ PUNICODE_STRING RegistryPath,\n\t\t_In_ PFLT_FILTER_UNLOAD_CALLBACK UnloadRoutine,\n\t\t_Inout_ NTSTATUS* InitializeStatus\n\t\t);\n\t~IOCTLCommunication(VOID);\n} IOCTL_COMMUNICATION, *PIOCTL_COMMUNICATION;\n\n#define DETECTION_LOGIC_TAG 'lDmP'\n#define IMAGE_HISTORY_FILTER_TAG 'fImP'\n#define FILE_MONITOR_TAG 'mFmP'\n#define REGISTRY_MONITOR_TAG 'mRmP'\n#define THREAD_FILTER_TAG 'fTmP'\n#define TAMPER_GUARD_TAG 'gTmP'"
  },
  {
    "path": "PeaceMaker Kernel/ImageHistoryFilter.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"ImageHistoryFilter.h\"\n\nStackWalker ImageHistoryFilter::walker;\nPPROCESS_HISTORY_ENTRY ImageHistoryFilter::ProcessHistoryHead;\nEX_PUSH_LOCK ImageHistoryFilter::ProcessHistoryLock;\nBOOLEAN ImageHistoryFilter::destroying;\nULONG64 ImageHistoryFilter::ProcessHistorySize;\nPDETECTION_LOGIC ImageHistoryFilter::detector;\n\n/**\n\tRegister the necessary notify routines.\n\t@param Detector - Detection instance used to analyze untrusted operations.\n\t@param InitializeStatus - Status of initialization.\n*/\nImageHistoryFilter::ImageHistoryFilter (\n\t_In_ PDETECTION_LOGIC Detector,\n\t_Out_ NTSTATUS* InitializeStatus\n\t)\n{\n\t//\n\t// Set the create process notify routine.\n\t//\n\t*InitializeStatus = PsSetCreateProcessNotifyRoutineEx(ImageHistoryFilter::CreateProcessNotifyRoutine, FALSE);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!ImageHistoryFilter: Failed to register create process notify routine with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\t\n\t//\n\t// Set the load image notify routine.\n\t//\n\t*InitializeStatus = PsSetLoadImageNotifyRoutine(ImageHistoryFilter::LoadImageNotifyRoutine);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!ImageHistoryFilter: Failed to register load image notify routine with status 0x%X.\", *InitializeStatus);\n\t\treturn;\n\t}\n\n\tFltInitializePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\tImageHistoryFilter::ProcessHistoryHead = RCAST<PPROCESS_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(PROCESS_HISTORY_ENTRY), PROCESS_HISTORY_TAG));\n\tif (ImageHistoryFilter::ProcessHistoryHead == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!ImageHistoryFilter: Failed to allocate the process history head.\");\n\t\t*InitializeStatus = STATUS_NO_MEMORY;\n\t\treturn;\n\t}\n\tmemset(ImageHistoryFilter::ProcessHistoryHead, 0, sizeof(PROCESS_HISTORY_ENTRY));\n\tInitializeListHead(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead));\n\tthis->ProcessHistorySize = 0;\n\n\t//\n\t// Set the detector.\n\t//\n\tImageHistoryFilter::detector = Detector;\n}\n\n/**\n\tClean up the process history linked-list.\n*/\nImageHistoryFilter::~ImageHistoryFilter (\n\tVOID\n\t)\n{\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\tPIMAGE_LOAD_HISTORY_ENTRY currentImageEntry;\n\n\t//\n\t// Set destroying to TRUE so that no other threads can get a lock.\n\t//\n\tImageHistoryFilter::destroying = TRUE;\n\n\t//\n\t// Remove the notify routines.\n\t//\n\tPsSetCreateProcessNotifyRoutineEx(ImageHistoryFilter::CreateProcessNotifyRoutine, TRUE);\n\tPsRemoveLoadImageNotifyRoutine(ImageHistoryFilter::LoadImageNotifyRoutine);\n\n\t//\n\t// Acquire an exclusive lock to push out other threads.\n\t//\n\tFltAcquirePushLockExclusive(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Delete the lock for the process history linked-list.\n\t//\n\tFltDeletePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Go through each process history and free it.\n\t//\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\twhile (IsListEmpty(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead)) == FALSE)\n\t\t{\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(RemoveHeadList(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead)));\n\t\t\t//\n\t\t\t// Clear the images linked-list.\n\t\t\t//\n\t\t\tFltDeletePushLock(&currentProcessHistory->ImageLoadHistoryLock);\n\t\t\tif (currentProcessHistory->ImageLoadHistory)\n\t\t\t{\n\t\t\t\twhile (IsListEmpty(RCAST<PLIST_ENTRY>(currentProcessHistory->ImageLoadHistory)) == FALSE)\n\t\t\t\t{\n\t\t\t\t\tcurrentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(RemoveHeadList(RCAST<PLIST_ENTRY>(currentProcessHistory->ImageLoadHistory)));\n\n\t\t\t\t\t//\n\t\t\t\t\t// Free the image name.\n\t\t\t\t\t//\n\t\t\t\t\tif (currentImageEntry->ImageFileName.Buffer)\n\t\t\t\t\t{\n\t\t\t\t\t\tExFreePoolWithTag(currentImageEntry->ImageFileName.Buffer, IMAGE_NAME_TAG);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (currentImageEntry->CallerImageFileName)\n\t\t\t\t\t{\n\t\t\t\t\t\tExFreePoolWithTag(currentImageEntry->CallerImageFileName, IMAGE_NAME_TAG);\n\t\t\t\t\t}\n\n\t\t\t\t\t//\n\t\t\t\t\t// Free the stack history.\n\t\t\t\t\t//\n\t\t\t\t\tExFreePoolWithTag(currentImageEntry->CallerStackHistory, STACK_HISTORY_TAG);\n\n\t\t\t\t\tExFreePoolWithTag(currentImageEntry, IMAGE_HISTORY_TAG);\n\t\t\t\t}\n\n\t\t\t\t//\n\t\t\t\t// Finally, free the list head.\n\t\t\t\t//\n\t\t\t\tExFreePoolWithTag(currentProcessHistory->ImageLoadHistory, IMAGE_HISTORY_TAG);\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Free the names.\n\t\t\t//\n\t\t\tif (currentProcessHistory->ProcessImageFileName)\n\t\t\t{\n\t\t\t\tExFreePoolWithTag(currentProcessHistory->ProcessImageFileName, IMAGE_NAME_TAG);\n\t\t\t}\n\t\t\tif (currentProcessHistory->CallerImageFileName)\n\t\t\t{\n\t\t\t\tExFreePoolWithTag(currentProcessHistory->CallerImageFileName, IMAGE_NAME_TAG);\n\t\t\t}\n\t\t\tif (currentProcessHistory->ParentImageFileName)\n\t\t\t{\n\t\t\t\tExFreePoolWithTag(currentProcessHistory->ParentImageFileName, IMAGE_NAME_TAG);\n\t\t\t}\n\t\t\tif (currentProcessHistory->ProcessCommandLine)\n\t\t\t{\n\t\t\t\tExFreePoolWithTag(currentProcessHistory->ProcessCommandLine, IMAGE_COMMMAND_TAG);\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Free the stack history.\n\t\t\t//\n\t\t\tExFreePoolWithTag(currentProcessHistory->CallerStackHistory, STACK_HISTORY_TAG);\n\n\t\t\t//\n\t\t\t// Free the process history.\n\t\t\t//\n\t\t\tExFreePoolWithTag(currentProcessHistory, PROCESS_HISTORY_TAG);\n\t\t}\n\n\t\t//\n\t\t// Finally, free the list head.\n\t\t//\n\t\tExFreePoolWithTag(ImageHistoryFilter::ProcessHistoryHead, PROCESS_HISTORY_TAG);\n\t}\n}\n\n/**\n\tAdd a process to the linked-list of process history objects. This function attempts to add a history object regardless of failures.\n\t@param ProcessId - The process ID of the process to add.\n\t@param CreateInfo - Information about the process being created.\n*/\nVOID\nImageHistoryFilter::AddProcessToHistory (\n\t_In_ HANDLE ProcessId,\n\t_In_ PPS_CREATE_NOTIFY_INFO CreateInfo\n\t)\n{\n\tNTSTATUS status;\n\tPPROCESS_HISTORY_ENTRY newProcessHistory;\n\tLARGE_INTEGER systemTime;\n\tLARGE_INTEGER localSystemTime;\n\tBOOLEAN processHistoryLockHeld;\n\n\tprocessHistoryLockHeld = FALSE;\n\tstatus = STATUS_SUCCESS;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn;\n\t}\n\n\tnewProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(PROCESS_HISTORY_ENTRY), PROCESS_HISTORY_TAG));\n\tif (newProcessHistory == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for the process history.\");\n\t\tstatus = STATUS_NO_MEMORY;\n\t\tgoto Exit;\n\t}\n\n\tmemset(newProcessHistory, 0, sizeof(PROCESS_HISTORY_ENTRY));\n\n\t//\n\t// Basic fields.\n\t//\n\tnewProcessHistory->ProcessId = ProcessId;\n\tnewProcessHistory->ParentId = CreateInfo->ParentProcessId;\n\tnewProcessHistory->CallerId = PsGetCurrentProcessId();\n\tnewProcessHistory->ProcessTerminated = FALSE;\n\tnewProcessHistory->ImageLoadHistorySize = 0;\n\tKeQuerySystemTime(&systemTime);\n\tExSystemTimeToLocalTime(&systemTime, &localSystemTime);\n\tnewProcessHistory->EpochExecutionTime = localSystemTime.QuadPart / TICKSPERSEC - SECS_1601_TO_1970;\n\t//\n\t// Image file name fields.\n\t//\n\n\t\n\t//\n\t// Allocate the necessary space.\n\t//\n\tnewProcessHistory->ProcessImageFileName = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, sizeof(UNICODE_STRING) + CreateInfo->ImageFileName->Length, IMAGE_NAME_TAG));\n\tif (newProcessHistory->ProcessImageFileName == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for process ImageFileName.\");\n\t\tgoto Exit;\n\t}\n\n\tnewProcessHistory->ProcessImageFileName->Buffer = RCAST<PWCH>(RCAST<ULONG_PTR>(newProcessHistory->ProcessImageFileName) + sizeof(UNICODE_STRING));\n\tnewProcessHistory->ProcessImageFileName->Length = CreateInfo->ImageFileName->Length;\n\tnewProcessHistory->ProcessImageFileName->MaximumLength = CreateInfo->ImageFileName->Length;\n\n\t//\n\t// Copy the image file name string.\n\t//\n\tRtlCopyUnicodeString(newProcessHistory->ProcessImageFileName, CreateInfo->ImageFileName);\n\n\t//\n\t// Allocate the necessary space.\n\t//\n\tif (CreateInfo->CommandLine)\n\t{\n\t\tnewProcessHistory->ProcessCommandLine = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, sizeof(UNICODE_STRING) + CreateInfo->CommandLine->Length, IMAGE_COMMMAND_TAG));\n\t\tif (newProcessHistory->ProcessCommandLine == NULL)\n\t\t{\n\t\t\tDBGPRINT(\"ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for process command line.\");\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tnewProcessHistory->ProcessCommandLine->Buffer = RCAST<PWCH>(RCAST<ULONG_PTR>(newProcessHistory->ProcessCommandLine) + sizeof(UNICODE_STRING));\n\t\tnewProcessHistory->ProcessCommandLine->Length = CreateInfo->CommandLine->Length;\n\t\tnewProcessHistory->ProcessCommandLine->MaximumLength = CreateInfo->CommandLine->Length;\n\n\t\t//\n\t\t// Copy the command line string.\n\t\t//\n\t\tRtlCopyUnicodeString(newProcessHistory->ProcessCommandLine, CreateInfo->CommandLine);\n\t}\n\t//\n\t// These fields are optional.\n\t//\n\tImageHistoryFilter::GetProcessImageFileName(CreateInfo->ParentProcessId, &newProcessHistory->ParentImageFileName);\n\n\tif (PsGetCurrentProcessId() != CreateInfo->ParentProcessId)\n\t{\n\t\tImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &newProcessHistory->CallerImageFileName);\n\t}\n\n\t//\n\t// Grab the user-mode stack.\n\t//\n\tnewProcessHistory->CallerStackHistorySize = MAX_STACK_RETURN_HISTORY; // Will be updated in the resolve function.\n\twalker.WalkAndResolveStack(&newProcessHistory->CallerStackHistory, &newProcessHistory->CallerStackHistorySize, STACK_HISTORY_TAG);\n\tif (newProcessHistory->CallerStackHistory == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for the stack history.\");\n\t\tstatus = STATUS_NO_MEMORY;\n\t\tgoto Exit;\n\t}\n\n\tnewProcessHistory->ImageLoadHistory = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(IMAGE_LOAD_HISTORY_ENTRY), IMAGE_HISTORY_TAG));\n\tif (newProcessHistory->ImageLoadHistory == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!AddProcessToHistory: Failed to allocate space for the image load history.\");\n\t\tstatus = STATUS_NO_MEMORY;\n\t\tgoto Exit;\n\t}\n\tmemset(newProcessHistory->ImageLoadHistory, 0, sizeof(IMAGE_LOAD_HISTORY_ENTRY));\n\n\tInitializeListHead(RCAST<PLIST_ENTRY>(newProcessHistory->ImageLoadHistory));\n\n\t//\n\t// Initialize this last so we don't have to delete it if anything failed.\n\t//\n\tFltInitializePushLock(&newProcessHistory->ImageLoadHistoryLock);\n\n\t//\n\t// Grab a lock to add an entry.\n\t//\n\tFltAcquirePushLockExclusive(&ImageHistoryFilter::ProcessHistoryLock);\n\n\tInsertTailList(RCAST<PLIST_ENTRY>(ImageHistoryFilter::ProcessHistoryHead), RCAST<PLIST_ENTRY>(newProcessHistory));\n\tImageHistoryFilter::ProcessHistorySize++;\n\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Audit the stack.\n\t//\n\tImageHistoryFilter::detector->AuditUserStackWalk(ProcessCreate,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newProcessHistory->ProcessId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newProcessHistory->ParentImageFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newProcessHistory->ProcessImageFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newProcessHistory->CallerStackHistory,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newProcessHistory->CallerStackHistorySize);\n\n\t//\n\t// Check for parent process ID spoofing.\n\t//\n\tImageHistoryFilter::detector->AuditCallerProcessId(ProcessCreate,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   PsGetCurrentProcessId(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t   CreateInfo->ParentProcessId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   newProcessHistory->ParentImageFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   newProcessHistory->ProcessImageFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   newProcessHistory->CallerStackHistory,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   newProcessHistory->CallerStackHistorySize);\nExit:\n\tif (newProcessHistory && NT_SUCCESS(status) == FALSE)\n\t{\n\t\tExFreePoolWithTag(newProcessHistory, PROCESS_HISTORY_TAG);\n\t}\n}\n\n/**\n\tSet a process to terminated, still maintain the history.\n\t@param ProcessId - The process ID of the process being terminated.\n*/\nVOID\nImageHistoryFilter::TerminateProcessInHistory (\n\t_In_ HANDLE ProcessId\n\t)\n{\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Iterate histories for a match.\n\t//\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = ImageHistoryFilter::ProcessHistoryHead;\n\t\tdo\n\t\t{\n\t\t\t//\n\t\t\t// Find the process history with the same PID and then set it to terminated.\n\t\t\t//\n\t\t\tif (currentProcessHistory->ProcessId == ProcessId)\n\t\t\t{\n\t\t\t\tcurrentProcessHistory->ProcessTerminated = TRUE;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);\n\t\t} while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead);\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n}\n\n/**\n\tNotify routine called on new process execution.\n\t@param Process - The EPROCESS structure of the new/terminating process.\n\t@param ProcessId - The new child's process ID.\n\t@param CreateInfo - Information about the process being created.\n*/\nVOID\nImageHistoryFilter::CreateProcessNotifyRoutine (\n\t_In_ PEPROCESS Process,\n\t_In_ HANDLE ProcessId,\n\t_In_ PPS_CREATE_NOTIFY_INFO CreateInfo\n\t)\n{\n\tUNREFERENCED_PARAMETER(Process);\n\t//\n\t// If a new process is being created, add it to the history of processes.\n\t//\n\tif (CreateInfo)\n\t{\n\t\tImageHistoryFilter::AddProcessToHistory(ProcessId, CreateInfo);\n\t\tDBGPRINT(\"ImageHistoryFilter!CreateProcessNotifyRoutine: Registered process 0x%X.\", ProcessId);\n\t}\n\telse\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!CreateProcessNotifyRoutine: Terminating process 0x%X.\", ProcessId);\n\t\t//\n\t\t// Set the process as \"terminated\".\n\t\t//\n\t\tImageHistoryFilter::TerminateProcessInHistory(ProcessId);\n\t}\n}\n\n/**\n\tRetrieve the full image file name for a process.\n\t@param ProcessId - The process to get the name of.\n\t@param ProcessImageFileName - PUNICODE_STRING to fill with the image file name of the process.\n*/\nBOOLEAN\nImageHistoryFilter::GetProcessImageFileName (\n\t_In_ HANDLE ProcessId,\n\t_Inout_ PUNICODE_STRING* ImageFileName\n\t)\n{\n\tNTSTATUS status;\n\tPEPROCESS processObject;\n\tHANDLE processHandle;\n\tULONG returnLength;\n\n\tprocessHandle = NULL;\n\t*ImageFileName = NULL;\n\treturnLength = 0;\n\n\t//\n\t// Before we can open a handle to the process, we need its PEPROCESS object.\n\t//\n\tstatus = PsLookupProcessByProcessId(ProcessId, &processObject);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!GetProcessImageFileName: Failed to find process object with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Open a handle to the process.\n\t//\n\tstatus = ObOpenObjectByPointer(processObject, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, *PsProcessType, KernelMode, &processHandle);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!GetProcessImageFileName: Failed to open handle to process with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Query for the size of the UNICODE_STRING.\n\t//\n\tstatus = NtQueryInformationProcess(processHandle, ProcessImageFileName, NULL, 0, &returnLength);\n\tif (status != STATUS_INFO_LENGTH_MISMATCH && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_BUFFER_OVERFLOW)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!GetProcessImageFileName: Failed to query size of process ImageFileName with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Allocate the necessary space.\n\t//\n\t*ImageFileName = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, returnLength, IMAGE_NAME_TAG));\n\tif (*ImageFileName == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!GetProcessImageFileName: Failed to allocate space for process ImageFileName.\");\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Query the image file name.\n\t//\n\tstatus = NtQueryInformationProcess(processHandle, ProcessImageFileName, *ImageFileName, returnLength, &returnLength);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!GetProcessImageFileName: Failed to query process ImageFileName with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\nExit:\n\tif (processHandle)\n\t{\n\t\tZwClose(processHandle);\n\t}\n\tif (NT_SUCCESS(status) == FALSE && *ImageFileName)\n\t{\n\t\tExFreePoolWithTag(*ImageFileName, IMAGE_NAME_TAG);\n\t\t*ImageFileName = NULL;\n\t}\n\treturn NT_SUCCESS(status);\n}\n\n/**\n\tNotify routine called when a new image is loaded into a process. Adds the image to the corresponding process history element.\n\t@param FullImageName - A PUNICODE_STRING that identifies the executable image file. Might be NULL.\n\t@param ProcessId - The process ID where this image is being mapped.\n\t@param ImageInfo - Structure containing a variety of properties about the image being loaded.\n*/\nVOID\nImageHistoryFilter::LoadImageNotifyRoutine(\n\t_In_ PUNICODE_STRING FullImageName,\n\t_In_ HANDLE ProcessId,\n\t_In_ PIMAGE_INFO ImageInfo\n\t)\n{\n\tNTSTATUS status;\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\tPIMAGE_LOAD_HISTORY_ENTRY newImageLoadHistory;\n\n\tUNREFERENCED_PARAMETER(ImageInfo);\n\n\tcurrentProcessHistory = NULL;\n\tnewImageLoadHistory = NULL;\n\tstatus = STATUS_SUCCESS;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Iterate histories for a match.\n\t//\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = ImageHistoryFilter::ProcessHistoryHead;\n\t\tdo\n\t\t{\n\t\t\tif (currentProcessHistory->ProcessId == ProcessId && currentProcessHistory->ProcessTerminated == FALSE)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);\n\t\t} while (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead);\n\t}\n\n\t//\n\t// This might happen if we load on a running machine that already has processes.\n\t//\n\tif (currentProcessHistory == NULL || currentProcessHistory == ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!LoadImageNotifyRoutine: Failed to find PID 0x%X in history.\", ProcessId);\n\t\tstatus = STATUS_NOT_FOUND;\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Allocate space for the new image history entry.\n\t//\n\tnewImageLoadHistory = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(ExAllocatePoolWithTag(PagedPool, sizeof(IMAGE_LOAD_HISTORY_ENTRY), IMAGE_HISTORY_TAG));\n\tif (newImageLoadHistory == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!LoadImageNotifyRoutine: Failed to allocate space for the image history entry.\");\n\t\tstatus = STATUS_NO_MEMORY;\n\t\tgoto Exit;\n\t}\n\tmemset(newImageLoadHistory, 0, sizeof(IMAGE_LOAD_HISTORY_ENTRY));\n\n\tnewImageLoadHistory->CallerProcessId = PsGetCurrentProcessId();\n\tif (PsGetCurrentProcessId() != ProcessId)\n\t{\n\t\tnewImageLoadHistory->RemoteImage = TRUE;\n\t\tImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &newImageLoadHistory->CallerImageFileName);\n\t}\n\n\t//\n\t// Copy the image file name if it is provided.\n\t//\n\tif (FullImageName)\n\t{\n\t\t//\n\t\t// Allocate the copy buffer. FullImageName will not be valid forever.\n\t\t//\n\t\tnewImageLoadHistory->ImageFileName.Buffer = RCAST<PWCH>(ExAllocatePoolWithTag(PagedPool, SCAST<SIZE_T>(FullImageName->Length) + 2, IMAGE_NAME_TAG));\n\t\tif (newImageLoadHistory->ImageFileName.Buffer == NULL)\n\t\t{\n\t\t\tDBGPRINT(\"ImageHistoryFilter!LoadImageNotifyRoutine: Failed to allocate space for the image file name.\");\n\t\t\tstatus = STATUS_NO_MEMORY;\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tnewImageLoadHistory->ImageFileName.Length = SCAST<SIZE_T>(FullImageName->Length) + 2;\n\t\tnewImageLoadHistory->ImageFileName.MaximumLength = SCAST<SIZE_T>(FullImageName->Length) + 2;\n\n\t\t//\n\t\t// Copy the image name.\n\t\t//\n\t\tstatus = RtlStringCbCopyUnicodeString(newImageLoadHistory->ImageFileName.Buffer, SCAST<SIZE_T>(FullImageName->Length) + 2, FullImageName);\n\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"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));\n\t\t\tgoto Exit;\n\t\t}\n\t}\n\n\t//\n\t// Grab the user-mode stack.\n\t//\n\tnewImageLoadHistory->CallerStackHistorySize = MAX_STACK_RETURN_HISTORY; // Will be updated in the resolve function.\n\twalker.WalkAndResolveStack(&newImageLoadHistory->CallerStackHistory, &newImageLoadHistory->CallerStackHistorySize, STACK_HISTORY_TAG);\n\tif (newImageLoadHistory->CallerStackHistory == NULL)\n\t{\n\t\tDBGPRINT(\"ImageHistoryFilter!LoadImageNotifyRoutine: Failed to allocate space for the stack history.\");\n\t\tstatus = STATUS_NO_MEMORY;\n\t\tgoto Exit;\n\t}\n\n\tFltAcquirePushLockExclusive(&currentProcessHistory->ImageLoadHistoryLock);\n\n\tInsertHeadList(RCAST<PLIST_ENTRY>(currentProcessHistory->ImageLoadHistory), RCAST<PLIST_ENTRY>(newImageLoadHistory));\n\tcurrentProcessHistory->ImageLoadHistorySize++;\n\n\tFltReleasePushLock(&currentProcessHistory->ImageLoadHistoryLock);\n\n\t//\n\t// Audit the stack.\n\t//\n\tImageHistoryFilter::detector->AuditUserStackWalk(ImageLoad,\n\t\t\t\t\t\t\t\t\t\t\t\t\t PsGetCurrentProcessId(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t currentProcessHistory->ProcessImageFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t &newImageLoadHistory->ImageFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newImageLoadHistory->CallerStackHistory,\n\t\t\t\t\t\t\t\t\t\t\t\t\t newImageLoadHistory->CallerStackHistorySize);\nExit:\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Clean up on failure.\n\t//\n\tif (newImageLoadHistory && NT_SUCCESS(status) == FALSE)\n\t{\n\t\tif (newImageLoadHistory->ImageFileName.Buffer)\n\t\t{\n\t\t\tExFreePoolWithTag(newImageLoadHistory->ImageFileName.Buffer, IMAGE_NAME_TAG);\n\t\t\tDBGPRINT(\"Free'd 'PmIn' at 0x%llx.\", newImageLoadHistory->ImageFileName.Buffer);\n\t\t}\n\t\tif (newImageLoadHistory->CallerStackHistory)\n\t\t{\n\t\t\tExFreePoolWithTag(newImageLoadHistory->CallerStackHistory, STACK_HISTORY_TAG);\n\t\t\tDBGPRINT(\"Free'd 'PmSh' at 0x%llx.\", newImageLoadHistory->CallerStackHistory);\n\t\t}\n\t\tExFreePoolWithTag(newImageLoadHistory, IMAGE_HISTORY_TAG);\n\t\tDBGPRINT(\"Free'd 'PmIh' at 0x%llx.\", newImageLoadHistory);\n\t}\n}\n\n/**\n\tGet the summary for MaxProcessSummaries processes starting from the top of list + SkipCount.\n\t@param SkipCount - How many processes to skip in the list.\n\t@param ProcessSummaries - Caller-supplied array of process summaries that this function fills.\n\t@param MaxProcessSumaries - Maximum number of process summaries that the array allows for.\n\t@return The actual number of summaries returned.\n*/\nULONG\nImageHistoryFilter::GetProcessHistorySummary (\n\t_In_ ULONG SkipCount,\n\t_Inout_ PPROCESS_SUMMARY_ENTRY ProcessSummaries,\n\t_In_ ULONG MaxProcessSummaries\n\t)\n{\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\tULONG currentProcessIndex;\n\tULONG actualFilledSummaries;\n\tNTSTATUS status;\n\n\tcurrentProcessIndex = 0;\n\tactualFilledSummaries = 0;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn 0;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\t//\n\t// Iterate histories for the MaxProcessSummaries processes after SkipCount processes.\n\t//\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Flink);\n\t\twhile (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead && actualFilledSummaries < MaxProcessSummaries)\n\t\t{\n\t\t\tif (currentProcessIndex >= SkipCount)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Fill out the summary.\n\t\t\t\t//\n\t\t\t\tProcessSummaries[actualFilledSummaries].EpochExecutionTime = currentProcessHistory->EpochExecutionTime;\n\t\t\t\tProcessSummaries[actualFilledSummaries].ProcessId = currentProcessHistory->ProcessId;\n\t\t\t\tProcessSummaries[actualFilledSummaries].ProcessTerminated = currentProcessHistory->ProcessTerminated;\n\t\t\t\t\n\t\t\t\tif (currentProcessHistory->ProcessImageFileName)\n\t\t\t\t{\n\t\t\t\t\t//\n\t\t\t\t\t// Copy the image name.\n\t\t\t\t\t//\n\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(&ProcessSummaries[actualFilledSummaries].ImageFileName), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ProcessImageFileName);\n\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t{\n\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!GetProcessHistorySummary: Failed to copy the image file name with status 0x%X.\", status);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tactualFilledSummaries++;\n\t\t\t}\n\t\t\tcurrentProcessIndex++;\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Flink);\n\t\t}\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\treturn actualFilledSummaries;\n}\n\n/**\n\tPopulate a request for detailed information on a process.\n\t@param ProcessDetailedRequest - The request to populate.\n*/\nVOID\nImageHistoryFilter::PopulateProcessDetailedRequest (\n\t_Inout_ PPROCESS_DETAILED_REQUEST ProcessDetailedRequest\n\t)\n{\n\tNTSTATUS status;\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\tPIMAGE_LOAD_HISTORY_ENTRY currentImageEntry;\n\tULONG i;\n\n\ti = 0;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);\n\t\twhile (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)\n\t\t{\n\t\t\tif (ProcessDetailedRequest->ProcessId == currentProcessHistory->ProcessId &&\n\t\t\t\tProcessDetailedRequest->EpochExecutionTime == currentProcessHistory->EpochExecutionTime)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Set basic fields.\n\t\t\t\t//\n\t\t\t\tProcessDetailedRequest->Populated = TRUE;\n\t\t\t\tProcessDetailedRequest->CallerProcessId = currentProcessHistory->CallerId;\n\t\t\t\tProcessDetailedRequest->ParentProcessId = currentProcessHistory->ParentId;\n\n\t\t\t\t//\n\t\t\t\t// Copy the stack history.\n\t\t\t\t//\n\t\t\t\tProcessDetailedRequest->StackHistorySize = (ProcessDetailedRequest->StackHistorySize > currentProcessHistory->CallerStackHistorySize) ? currentProcessHistory->CallerStackHistorySize : ProcessDetailedRequest->StackHistorySize;\n\t\t\t\tmemcpy(ProcessDetailedRequest->StackHistory, currentProcessHistory->CallerStackHistory, ProcessDetailedRequest->StackHistorySize * sizeof(STACK_RETURN_INFO));\n\n\t\t\t\t//\n\t\t\t\t// Copy the paths.\n\t\t\t\t//\n\t\t\t\tif (currentProcessHistory->ProcessImageFileName)\n\t\t\t\t{\n\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ProcessPath), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ProcessImageFileName);\n\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t{\n\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of the process with status 0x%X.\", status);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (currentProcessHistory->CallerImageFileName)\n\t\t\t\t{\n\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->CallerProcessPath), MAX_PATH * sizeof(WCHAR), currentProcessHistory->CallerImageFileName);\n\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t{\n\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of the caller with status 0x%X.\", status);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (currentProcessHistory->ParentImageFileName)\n\t\t\t\t{\n\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ParentProcessPath), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ParentImageFileName);\n\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t{\n\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of the parent with status 0x%X.\", status);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (currentProcessHistory->ProcessCommandLine)\n\t\t\t\t{\n\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ProcessCommandLine), MAX_PATH * sizeof(WCHAR), currentProcessHistory->ProcessCommandLine);\n\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t{\n\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the command line of the process with status 0x%X.\", status);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t//\n\t\t\t\t// Iterate the images for basic information.\n\t\t\t\t//\n\t\t\t\tFltAcquirePushLockShared(&currentProcessHistory->ImageLoadHistoryLock);\n\n\t\t\t\t//\n\t\t\t\t// The head isn't an element so skip it.\n\t\t\t\t//\n\t\t\t\tcurrentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentProcessHistory->ImageLoadHistory->ListEntry.Flink);\n\t\t\t\twhile (currentImageEntry != currentProcessHistory->ImageLoadHistory && i < ProcessDetailedRequest->ImageSummarySize)\n\t\t\t\t{\n\t\t\t\t\t__try\n\t\t\t\t\t{\n\t\t\t\t\t\tif (currentImageEntry->ImageFileName.Buffer)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ProcessDetailedRequest->ImageSummary[i].ImagePath), MAX_PATH * sizeof(WCHAR), &currentImageEntry->ImageFileName);\n\t\t\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateProcessDetailedRequest: Failed to copy the image file name of an image with status 0x%X and source size %i.\", status, currentImageEntry->ImageFileName.Length);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tProcessDetailedRequest->ImageSummary[i].StackSize = currentImageEntry->CallerStackHistorySize;\n\t\t\t\t\t}\n\t\t\t\t\t__except (1)\n\t\t\t\t\t{\n\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateProcessDetailedRequest: Exception while processing image summaries.\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ti++;\n\n\t\t\t\t\tcurrentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentImageEntry->ListEntry.Flink);\n\t\t\t\t}\n\n\t\t\t\tFltReleasePushLock(&currentProcessHistory->ImageLoadHistoryLock);\n\n\t\t\t\tProcessDetailedRequest->ImageSummarySize = i; // Actual number of images put into the array.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);\n\t\t}\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n}\n\n/**\n\tPopulate a process sizes request.\n\t@param ProcesSizesRequest - The request to populate.\n*/\nVOID\nImageHistoryFilter::PopulateProcessSizes (\n\t_Inout_ PPROCESS_SIZES_REQUEST ProcessSizesRequest\n\t)\n{\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);\n\t\twhile (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)\n\t\t{\n\t\t\tif (ProcessSizesRequest->ProcessId == currentProcessHistory->ProcessId &&\n\t\t\t\tProcessSizesRequest->EpochExecutionTime == currentProcessHistory->EpochExecutionTime)\n\t\t\t{\n\t\t\t\tProcessSizesRequest->StackSize = currentProcessHistory->CallerStackHistorySize;\n\t\t\t\tProcessSizesRequest->ImageSize = currentProcessHistory->ImageLoadHistorySize;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);\n\t\t}\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n}\n\n/**\n\tIncrement process thread count by one and retrieve the latest value.\n\t@param ProcessId - The process ID of the target process.\n\t@param ThreadCount - The resulting thread count.\n\t@return Whether or not the process was found.\n*/\nBOOLEAN\nImageHistoryFilter::AddProcessThreadCount (\n\t_In_ HANDLE ProcessId,\n\t_Inout_ ULONG* ThreadCount\n\t)\n{\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\tBOOLEAN foundProcess;\n\n\tfoundProcess = FALSE;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn foundProcess;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);\n\t\twhile (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)\n\t\t{\n\t\t\tif (ProcessId == currentProcessHistory->ProcessId &&\n\t\t\t\tcurrentProcessHistory->ProcessTerminated == FALSE)\n\t\t\t{\n\t\t\t\tcurrentProcessHistory->ProcessThreadCount++;\n\t\t\t\t*ThreadCount = currentProcessHistory->ProcessThreadCount;\n\t\t\t\tfoundProcess = TRUE;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);\n\t\t}\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n\n\treturn foundProcess;\n}\n\nVOID\nImageHistoryFilter::PopulateImageDetailedRequest(\n\t_Inout_ PIMAGE_DETAILED_REQUEST ImageDetailedRequest\n\t)\n{\n\tNTSTATUS status;\n\tPPROCESS_HISTORY_ENTRY currentProcessHistory;\n\tPIMAGE_LOAD_HISTORY_ENTRY currentImageEntry;\n\tULONG i;\n\n\ti = 0;\n\n\tif (ImageHistoryFilter::destroying)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate processes.\n\t//\n\tFltAcquirePushLockShared(&ImageHistoryFilter::ProcessHistoryLock);\n\n\tif (ImageHistoryFilter::ProcessHistoryHead)\n\t{\n\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(ImageHistoryFilter::ProcessHistoryHead->ListEntry.Blink);\n\t\twhile (currentProcessHistory && currentProcessHistory != ImageHistoryFilter::ProcessHistoryHead)\n\t\t{\n\t\t\tif (ImageDetailedRequest->ProcessId == currentProcessHistory->ProcessId &&\n\t\t\t\tImageDetailedRequest->EpochExecutionTime == currentProcessHistory->EpochExecutionTime)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Iterate the images for basic information.\n\t\t\t\t//\n\t\t\t\tFltAcquirePushLockShared(&currentProcessHistory->ImageLoadHistoryLock);\n\n\t\t\t\t//\n\t\t\t\t// The head isn't an element so skip it.\n\t\t\t\t//\n\t\t\t\tcurrentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentProcessHistory->ImageLoadHistory->ListEntry.Flink);\n\t\t\t\twhile (currentImageEntry != currentProcessHistory->ImageLoadHistory)\n\t\t\t\t{\n\t\t\t\t\tif (i == ImageDetailedRequest->ImageIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (currentImageEntry->ImageFileName.Buffer)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus = RtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(ImageDetailedRequest->ImagePath), MAX_PATH * sizeof(WCHAR), &currentImageEntry->ImageFileName);\n\t\t\t\t\t\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDBGPRINT(\"ImageHistoryFilter!PopulateImageDetailedRequest: Failed to copy the image file name of an image with status 0x%X and source size %i.\", status, currentImageEntry->ImageFileName.Length);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Copy the stack history.\n\t\t\t\t\t\t//\n\t\t\t\t\t\tImageDetailedRequest->StackHistorySize = (ImageDetailedRequest->StackHistorySize > currentImageEntry->CallerStackHistorySize) ? currentImageEntry->CallerStackHistorySize : ImageDetailedRequest->StackHistorySize;\n\t\t\t\t\t\tmemcpy(ImageDetailedRequest->StackHistory, currentImageEntry->CallerStackHistory, ImageDetailedRequest->StackHistorySize * sizeof(STACK_RETURN_INFO));\n\n\t\t\t\t\t\tImageDetailedRequest->Populated = TRUE;\n\t\t\t\t\t}\n\t\t\t\t\ti++;\n\t\t\t\t\tcurrentImageEntry = RCAST<PIMAGE_LOAD_HISTORY_ENTRY>(currentImageEntry->ListEntry.Flink);\n\t\t\t\t}\n\n\t\t\t\tFltReleasePushLock(&currentProcessHistory->ImageLoadHistoryLock);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentProcessHistory = RCAST<PPROCESS_HISTORY_ENTRY>(currentProcessHistory->ListEntry.Blink);\n\t\t}\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&ImageHistoryFilter::ProcessHistoryLock);\n}"
  },
  {
    "path": "PeaceMaker Kernel/ImageHistoryFilter.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"StackWalker.h\"\n#include \"shared.h\"\n#include \"DetectionLogic.h\"\n\n#define IMAGE_NAME_TAG 'nImP'\n#define IMAGE_COMMMAND_TAG 'cImP'\n#define PROCESS_HISTORY_TAG 'hPmP'\n#define STACK_HISTORY_TAG 'hSmP'\n#define IMAGE_HISTORY_TAG 'hImP'\n\ntypedef struct ImageLoadHistoryEntry\n{\n\tLIST_ENTRY ListEntry;\t\t\t\t\t// The list entry to iterate multiple images in a process.\n\tUNICODE_STRING ImageFileName;\t\t\t// The full image file name of loaded image.\n\tHANDLE CallerProcessId;\t\t\t\t\t// The real caller of the load image routine.\n\tBOOLEAN RemoteImage;\t\t\t\t\t// Whether or not the image was loaded remotely.\n\tPUNICODE_STRING CallerImageFileName;\t\t// The full image file name of the caller. Only specified if RemoteImage == TRUE.\n\tPSTACK_RETURN_INFO CallerStackHistory;\t// A variable-length array of the stack that loaded the image.\n\tULONG CallerStackHistorySize;\t\t\t// The size of the variable-length stack history array.\n} IMAGE_LOAD_HISTORY_ENTRY, *PIMAGE_LOAD_HISTORY_ENTRY;\n\ntypedef struct ProcessHistoryEntry\n{\n\tLIST_ENTRY ListEntry;\t\t\t\t\t\t// The list entry to iterate multiple process histories.\n\n\tHANDLE CallerId;\t\t\t\t\t\t\t// The process id of the caller process.\n\tPUNICODE_STRING CallerImageFileName;\t\t// OPTIONAL: The image file name of the caller process.\n\n\tHANDLE ParentId;\t\t\t\t\t\t\t// The process id of the alleged parent process.\n\tPUNICODE_STRING ParentImageFileName;\t\t// OPTIONAL: The image file name of the alleged parent process.\n\n\tHANDLE ProcessId;\t\t\t\t\t\t\t// The process id of the executed process.\n\tPUNICODE_STRING ProcessImageFileName;\t\t// The image file name of the executed process.\n\n\tPUNICODE_STRING ProcessCommandLine;\t\t\t// The command-line string for the executed process.\n\n\tULONG ProcessThreadCount;\t\t\t\t\t// The number of threads the process has.\n\t\n\tULONGLONG EpochExecutionTime;\t\t\t\t// Process execution time in seconds since 1970.\n\tBOOLEAN ProcessTerminated;\t\t\t\t\t// Whether or not the process has terminated.\n\n\tPSTACK_RETURN_INFO CallerStackHistory;\t\t// A variable-length array of the stack that started the process.\n\tULONG CallerStackHistorySize;\t\t\t\t// The size of the variable-length stack history array.\n\n\tPIMAGE_LOAD_HISTORY_ENTRY ImageLoadHistory;\t// A linked-list of loaded images and their respective stack histories.\n\tEX_PUSH_LOCK ImageLoadHistoryLock;\t\t\t// The lock protecting the linked-list of loaded images.\n\tULONG ImageLoadHistorySize;\t\t\t\t\t// The size of the image load history linked-list.\n} PROCESS_HISTORY_ENTRY, *PPROCESS_HISTORY_ENTRY;\n\ntypedef class ImageHistoryFilter\n{\n\n\tstatic VOID CreateProcessNotifyRoutine (\n\t\t_In_ PEPROCESS Process,\n\t\t_In_ HANDLE ProcessId,\n\t\t_In_ PPS_CREATE_NOTIFY_INFO CreateInfo\n\t\t);\n\n\tstatic VOID LoadImageNotifyRoutine (\n\t\t_In_ PUNICODE_STRING FullImageName,\n\t\t_In_ HANDLE ProcessId,\n\t\t_In_ PIMAGE_INFO ImageInfo\n\t\t);\n\n\tstatic StackWalker walker;\t\t\t\t\t\t\t// Stack walking utility.\n\tstatic PPROCESS_HISTORY_ENTRY ProcessHistoryHead;\t// Linked-list of process history objects.\n\tstatic EX_PUSH_LOCK ProcessHistoryLock;\t\t\t\t// Lock protecting the ProcessHistory linked-list.\n\tstatic BOOLEAN destroying;\t\t\t\t\t\t\t// This boolean indicates to functions that a lock should not be held as we are in the process of destruction.\n\tstatic PDETECTION_LOGIC detector;\n\n\tstatic VOID AddProcessToHistory(\n\t\t_In_ HANDLE ProcessId,\n\t\t_In_ PPS_CREATE_NOTIFY_INFO CreateInfo\n\t\t);\n\n\tstatic VOID TerminateProcessInHistory(\n\t\t_In_ HANDLE ProcessId\n\t\t);\n\npublic:\n\tImageHistoryFilter(\n\t\t_In_ PDETECTION_LOGIC Detector,\n\t\t_Out_ NTSTATUS* InitializeStatus\n\t\t);\n\t~ImageHistoryFilter(VOID);\n\n\tstatic BOOLEAN GetProcessImageFileName(\n\t\t_In_ HANDLE ProcessId,\n\t\t_Inout_ PUNICODE_STRING* ImageFileName\n\t\t);\n\n\tULONG GetProcessHistorySummary(\n\t\t_In_ ULONG SkipCount,\n\t\t_Inout_ PPROCESS_SUMMARY_ENTRY ProcessSummaries,\n\t\t_In_ ULONG MaxProcessSummaries\n\t\t);\n\n\tVOID PopulateProcessDetailedRequest(\n\t\t_Inout_ PPROCESS_DETAILED_REQUEST ProcessDetailedRequest\n\t\t);\n\n\tVOID PopulateProcessSizes(\n\t\t_Inout_ PPROCESS_SIZES_REQUEST ProcessSizesRequest\n\t\t);\n\n\tVOID PopulateImageDetailedRequest(\n\t\t_Inout_ PIMAGE_DETAILED_REQUEST ImageDetailedRequest\n\t\t);\n\n\tstatic BOOLEAN AddProcessThreadCount(\n\t\t_In_ HANDLE ProcessId,\n\t\t_Inout_ ULONG* ThreadCount\n\t\t);\n\tstatic ULONG64 ProcessHistorySize;\t\t\t\t\t// Number of entries in the ProcessHistory linked-list.\n} IMAGE_HISTORY_FILTER, *PIMAGE_HISTORY_FILTER;"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.inf",
    "content": ";;;\n;;; FilterTesting\n;;;\n\n[Version]\nSignature   = \"$Windows NT$\"\n; TODO - Change the Class and ClassGuid to match the Load Order Group value, see https://msdn.microsoft.com/en-us/windows/hardware/gg462963\n; Class       = \"ActivityMonitor\"                         ;This is determined by the work this filter driver does\n; ClassGuid   = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}    ;This value is determined by the Load Order Group value\nClass = \"ActivityMonitor\"\nClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}\nProvider    = %ManufacturerName%\nDriverVer   = 12/17/2019,1.0.0.0\nCatalogFile = PeaceMakerKernel.cat\n\n[DestinationDirs]\nDefaultDestDir          = 12\nMiniFilter.DriverFiles  = 12            ;%windir%\\system32\\drivers\n\n;;\n;; Default install sections\n;;\n\n[DefaultInstall]\nOptionDesc          = %ServiceDescription%\nCopyFiles           = MiniFilter.DriverFiles\n\n[DefaultInstall.Services]\nAddService          = %ServiceName%,,MiniFilter.Service\n\n;;\n;; Default uninstall sections\n;;\n\n[DefaultUninstall]\nDelFiles   = MiniFilter.DriverFiles\n\n[DefaultUninstall.Services]\nDelService = %ServiceName%,0x200      ;Ensure service is stopped before deleting\n\n;\n; Services Section\n;\n\n[MiniFilter.Service]\nDisplayName      = %ServiceName%\nDescription      = %ServiceDescription%\nServiceBinary    = %12%\\%DriverName%.sys        ;%windir%\\system32\\drivers\\\nDependencies     = \"FltMgr\"\nServiceType      = 2                            ;SERVICE_FILE_SYSTEM_DRIVER\nStartType        = 2                            ;SERVICE_AUTO_START\nErrorControl     = 1                            ;SERVICE_ERROR_NORMAL\n; TODO - Change the Load Order Group value\n; LoadOrderGroup = \"FSFilter Activity Monitor\"\nLoadOrderGroup = \"FSFilter Activity Monitor\"\nAddReg           = MiniFilter.AddRegistry\n\n;\n; Registry Modifications\n;\n\n[MiniFilter.AddRegistry]\nHKR,,\"DebugFlags\",0x00010001 ,0x0\nHKR,,\"SupportedFeatures\",0x00010001,0x3\nHKR,\"Instances\",\"DefaultInstance\",0x00000000,%DefaultInstance%\nHKR,\"Instances\\\"%Instance1.Name%,\"Altitude\",0x00000000,%Instance1.Altitude%\nHKR,\"Instances\\\"%Instance1.Name%,\"Flags\",0x00010001,%Instance1.Flags%\n\n;\n; Copy Files\n;\n\n[MiniFilter.DriverFiles]\n%DriverName%.sys\n\n[SourceDisksFiles]\nPeaceMakerKernel.sys = 1,,\n\n[SourceDisksNames]\n1 = %DiskId1%,,,\n\n;;\n;; String Section\n;;\n\n[Strings]\n; TODO - Add your manufacturer\nManufacturerName        = \"Bill Demirkapi\"\nServiceDescription      = \"Peacemaker Kernel Mini-Filter Driver\"\nServiceName             = \"Peacemaker Kernel\"\nDriverName              = \"PeaceMakerKernel\"\nDiskId1                 = \"Peacemaker Kernel Device Installation Disk\"\n\n;Instances specific information.\nDefaultInstance         = \"FilterTesting Instance\"\nInstance1.Name          = \"FilterTesting Instance\"\n; TODO - Change the altitude value, see https://msdn.microsoft.com/en-us/windows/hardware/drivers/ifs/load-order-groups-and-altitudes-for-minifilter-drivers\nInstance1.Altitude       = \"321410\"\nInstance1.Flags         = 0x0              ; Allow all attachments\n"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.rc",
    "content": "#include <windows.h>\n\n#include <ntverp.h>\n\n#define VER_FILETYPE    VFT_DRV\n#define VER_FILESUBTYPE VFT2_DRV_SYSTEM\n#define VER_COMPANYNAME_STR \t\t\"Demirkapi Security Group\"\n#define VER_FILEVERSION_STR\t\t\t\"1.0.0.0\"\n#define VER_LEGALCOPYRIGHT_STR\t\t\"Demirkapi Security Group 2019-2020\"\n#define VER_PRODUCTNAME_STR\t\t\t\"PeaceMaker Threat Detection\"\n#define VER_FILEDESCRIPTION_STR     \"The PeaceMaker TD Kernel Component.\"\n#define VER_INTERNALNAME_STR\t\t\"peacemaker.sys\"\n\n#include \"common.ver\""
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"TamperGuard.cpp\" />\n    <ClCompile Include=\"ThreadFilter.cpp\" />\n    <ResourceCompile Include=\"PeaceMaker Kernel.rc\" />\n    <ClCompile Include=\"AlertQueue.cpp\" />\n    <ClCompile Include=\"common.cpp\" />\n    <ClCompile Include=\"DetectionLogic.cpp\" />\n    <ClCompile Include=\"FSFilter.cpp\" />\n    <ClCompile Include=\"ImageHistoryFilter.cpp\" />\n    <ClCompile Include=\"IOCTLCommunication.cpp\" />\n    <ClCompile Include=\"RegistryFilter.cpp\" />\n    <ClCompile Include=\"StackWalker.cpp\" />\n    <ClCompile Include=\"StringFilters.cpp\" />\n    <ClCompile Include=\"FilterTesting.cpp\" />\n    <Inf Include=\"PeaceMaker Kernel.inf\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}</ProjectGuid>\n    <TemplateGuid>{f2f62967-0815-4fd7-9b86-6eedcac766eb}</TemplateGuid>\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\n    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>\n    <Configuration>Debug</Configuration>\n    <Platform Condition=\"'$(Platform)' == ''\">Win32</Platform>\n    <RootNamespace>PeaceMaker Kernel</RootNamespace>\n    <ProjectName>PeaceMaker Kernel</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows7</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n    <PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalOptions>/INTEGRITYCHECK %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n    <PostBuildEvent>\n      <Command>\"$(OutDir)signbinary.bat\" \"$(TargetPath)\"</Command>\n    </PostBuildEvent>\n    <ClCompile />\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <FilesToPackage Include=\"$(TargetPath)\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AlertQueue.h\" />\n    <ClInclude Include=\"common.h\" />\n    <ClInclude Include=\"DetectionLogic.h\" />\n    <ClInclude Include=\"FSFilter.h\" />\n    <ClInclude Include=\"IOCTLCommunication.h\" />\n    <ClInclude Include=\"ntdef.h\" />\n    <ClInclude Include=\"ImageHistoryFilter.h\" />\n    <ClInclude Include=\"RegistryFilter.h\" />\n    <ClInclude Include=\"shared.h\" />\n    <ClInclude Include=\"StackWalker.h\" />\n    <ClInclude Include=\"StringFilters.h\" />\n    <ClInclude Include=\"TamperGuard.h\" />\n    <ClInclude Include=\"ThreadFilter.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "PeaceMaker Kernel/PeaceMaker Kernel.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Driver Files\">\n      <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>\n      <Extensions>inf;inv;inx;mof;mc;</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\\Filters\">\n      <UniqueIdentifier>{e51791fd-6d37-4d03-af6a-4cf1d58ff83a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\Filters\">\n      <UniqueIdentifier>{07baa70a-638f-458b-a11e-cc54d633a0f5}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Header Files\\Utilities\">\n      <UniqueIdentifier>{d2416d0a-1b1f-400a-a990-1af1d2a15b4b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\Utilities\">\n      <UniqueIdentifier>{b653583e-a15b-446e-85e9-7f8cceecae8c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Header Files\\Core\">\n      <UniqueIdentifier>{67667525-d9bd-4041-8ca5-f90fe95a4741}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\Core\">\n      <UniqueIdentifier>{bbb90d1c-ab67-44c2-a036-5847843b131f}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Inf Include=\"PeaceMaker Kernel.inf\">\n      <Filter>Driver Files</Filter>\n    </Inf>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"PeaceMaker Kernel.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"FilterTesting.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"common.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FSFilter.cpp\">\n      <Filter>Source Files\\Filters</Filter>\n    </ClCompile>\n    <ClCompile Include=\"RegistryFilter.cpp\">\n      <Filter>Source Files\\Filters</Filter>\n    </ClCompile>\n    <ClCompile Include=\"StackWalker.cpp\">\n      <Filter>Source Files\\Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ImageHistoryFilter.cpp\">\n      <Filter>Source Files\\Filters</Filter>\n    </ClCompile>\n    <ClCompile Include=\"StringFilters.cpp\">\n      <Filter>Source Files\\Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DetectionLogic.cpp\">\n      <Filter>Source Files\\Core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"IOCTLCommunication.cpp\">\n      <Filter>Source Files\\Core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AlertQueue.cpp\">\n      <Filter>Source Files\\Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ThreadFilter.cpp\">\n      <Filter>Source Files\\Filters</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TamperGuard.cpp\">\n      <Filter>Source Files\\Filters</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"common.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FSFilter.h\">\n      <Filter>Header Files\\Filters</Filter>\n    </ClInclude>\n    <ClInclude Include=\"RegistryFilter.h\">\n      <Filter>Header Files\\Filters</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StackWalker.h\">\n      <Filter>Header Files\\Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ntdef.h\">\n      <Filter>Header Files\\Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ImageHistoryFilter.h\">\n      <Filter>Header Files\\Filters</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StringFilters.h\">\n      <Filter>Header Files\\Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AlertQueue.h\">\n      <Filter>Header Files\\Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"shared.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DetectionLogic.h\">\n      <Filter>Header Files\\Core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"IOCTLCommunication.h\">\n      <Filter>Header Files\\Core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ThreadFilter.h\">\n      <Filter>Header Files\\Filters</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TamperGuard.h\">\n      <Filter>Header Files\\Filters</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "PeaceMaker Kernel/RegistryFilter.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"RegistryFilter.h\"\n\nLARGE_INTEGER RegistryBlockingFilter::RegistryFilterCookie;\nPDETECTION_LOGIC RegistryBlockingFilter::detector;\nSTACK_WALKER RegistryBlockingFilter::walker;\nPSTRING_FILTERS RegistryBlockingFilter::RegistryStringFilters;\n\n/**\n\tInitializes the necessary components of the registry filter.\n\t@param DriverObject - The object of the driver necessary for mini-filter initialization.\n\t@param RegistryPath - The registry path of the driver.\n\t@param Detector - Detection instance used to analyze untrusted operations.\n\t@param InitializeStatus - Status of initialization.\n*/\nRegistryBlockingFilter::RegistryBlockingFilter(\n\t_In_ PDRIVER_OBJECT DriverObject,\n\t_In_ PUNICODE_STRING RegistryPath,\n\t_In_ PDETECTION_LOGIC Detector,\n\t_Out_ NTSTATUS* InitializeStatus\n\t)\n{\n\tUNICODE_STRING filterAltitude;\n\n\tRegistryBlockingFilter::RegistryStringFilters = new (NonPagedPool, STRING_REGISTRY_FILTERS_TAG) StringFilters(RegistryFilter, RegistryPath, L\"RegistryFilterStore\");\n\tif (RegistryBlockingFilter::RegistryStringFilters == NULL)\n\t{\n\t\tDBGPRINT(\"RegistryBlockingFilter!RegistryBlockingFilter: Failed to allocate memory for string filters.\");\n\t\t*InitializeStatus = STATUS_NO_MEMORY;\n\t\treturn;\n\t}\n\t//\n\t// Restore existing filters.\n\t//\n\tRegistryBlockingFilter::RegistryStringFilters->RestoreFilters();\n\n\t//\n\t// Put our altitude into a UNICODE_STRING.\n\t//\n\tRtlInitUnicodeString(&filterAltitude, FILTER_ALTITUDE);\n\n\t//\n\t// Register our registry callback.\n\t//\n\t*InitializeStatus = CmRegisterCallbackEx(RCAST<PEX_CALLBACK_FUNCTION>(RegistryBlockingFilter::RegistryCallback), &filterAltitude, DriverObject, NULL, &RegistryFilterCookie, NULL);\n\n\t//\n\t// Set the detector.\n\t//\n\tRegistryBlockingFilter::detector = Detector;\n}\n\n/**\n\tFree data members that were dynamically allocated.\n*/\nRegistryBlockingFilter::~RegistryBlockingFilter()\n{\n\t//\n\t// Remove the registry callback.\n\t//\n\tCmUnRegisterCallback(this->RegistryFilterCookie);\n\n\t//\n\t// Make sure to deconstruct the class.\n\t//\n\tRegistryBlockingFilter::RegistryStringFilters->~StringFilters();\n\tExFreePoolWithTag(RegistryBlockingFilter::RegistryStringFilters, STRING_REGISTRY_FILTERS_TAG);\n}\n\n/**\n\tReturn the string filters used in the registry filter.\n\t@return String filters for registry operations.\n*/\nPSTRING_FILTERS RegistryBlockingFilter::GetStringFilters()\n{\n\treturn RegistryBlockingFilter::RegistryStringFilters;\n}\n\n/**\n\tFunction that decides whether or not to block a registry operation.\n\t@param KeyObject - The registry key of the operation.\n\t@param ValueName - The name of the registry value specified by the operation.\n\t@param OperationFlag - The flags of the operation (i.e WRITE/DELETE).\n\t@return Whether or not to block the operation.\n*/\nBOOLEAN\nRegistryBlockingFilter::BlockRegistryOperation (\n\t_In_ PVOID KeyObject,\n\t_In_ PUNICODE_STRING ValueName,\n\t_In_ ULONG OperationFlag\n\t)\n{\n\tBOOLEAN blockOperation;\n\tNTSTATUS internalStatus;\n\tHANDLE keyHandle;\n\tPKEY_NAME_INFORMATION pKeyNameInformation;\n\tULONG returnLength;\n\tULONG fullKeyValueLength;\n\tPWCHAR tempValueName;\n\tPWCHAR fullKeyValueName;\n\n\tUNICODE_STRING registryOperationPath;\n\tPUNICODE_STRING callerProcessPath;\n\tPSTACK_RETURN_INFO registryOperationStack;\n\tULONG registryOperationStackSize;\n\n\tblockOperation = FALSE;\n\tregistryOperationStackSize = MAX_STACK_RETURN_HISTORY;\n\tkeyHandle = NULL;\n\treturnLength = NULL;\n\tpKeyNameInformation = NULL;\n\ttempValueName = NULL;\n\tfullKeyValueName = NULL;\n\n\tif (ValueName == NULL || ValueName->Length == 0 || ValueName->Buffer == NULL || ValueName->Length > (NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR)))\n\t{\n\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: ValueName is NULL.\");\n\t\tgoto Exit;\n\t}\n\n\ttempValueName = RCAST<PWCHAR>(ExAllocatePoolWithTag(NonPagedPoolNx, ValueName->Length, REGISTRY_KEY_NAME_TAG));\n\tif (tempValueName == NULL)\n\t{\n\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to allocate memory for value name with size 0x%X.\", ValueName->Length);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// There can be some wonky exceptions with weird input,\n\t// just in case we don't handle something is a simple\n\t// catch all.\n\t//\n\t__try {\n\t\t//\n\t\t// Open the registry key.\n\t\t//\n\t\tinternalStatus = ObOpenObjectByPointer(KeyObject, OBJ_KERNEL_HANDLE, NULL, GENERIC_ALL, *CmKeyObjectType, KernelMode, &keyHandle);\n\t\tif (NT_SUCCESS(internalStatus) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to open a handle to a key object with status 0x%X.\", internalStatus);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tZwQueryKey(keyHandle, KeyNameInformation, NULL, 0, &returnLength);\n\t\tif (returnLength == 0)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to determine size of key name.\");\n\t\t\tgoto Exit;\n\t\t}\n\n\t\treturnLength += 1; // For null terminator.\n\t\tpKeyNameInformation = RCAST<PKEY_NAME_INFORMATION>(ExAllocatePoolWithTag(PagedPool, returnLength, REGISTRY_KEY_NAME_TAG));\n\t\tif (pKeyNameInformation == NULL)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to allocate memory for key name with size 0x%X.\", returnLength);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Query the name information of the key to retrieve its name.\n\t\t//\n\t\tinternalStatus = ZwQueryKey(keyHandle, KeyNameInformation, pKeyNameInformation, returnLength, &returnLength);\n\t\tif (NT_SUCCESS(internalStatus) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to query name of key object with status 0x%X.\", internalStatus);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Allocate space for key name, a backslash, the value name, and the null-terminator.\n\t\t//\n\t\tfullKeyValueLength = pKeyNameInformation->NameLength + 2 + ValueName->Length + 1000;\n\t\tfullKeyValueName = RCAST<PWCHAR>(ExAllocatePoolWithTag(NonPagedPoolNx, fullKeyValueLength, REGISTRY_KEY_NAME_TAG));\n\t\tif (fullKeyValueName == NULL)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to allocate memory for full key/value name with size 0x%X.\", fullKeyValueLength);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Copy the key name.\n\t\t//\n\t\tinternalStatus = RtlStringCbCopyNW(fullKeyValueName, fullKeyValueLength, RCAST<PCWSTR>(&pKeyNameInformation->Name), pKeyNameInformation->NameLength);\n\t\tif (NT_SUCCESS(internalStatus) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to copy key name with status 0x%X.\", internalStatus);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Concatenate the backslash.\n\t\t//\n\t\tinternalStatus = RtlStringCbCatW(fullKeyValueName, fullKeyValueLength, L\"\\\\\");\n\t\tif (NT_SUCCESS(internalStatus) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to concatenate backslash with status 0x%X.\", internalStatus);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\t//\n\t\t// Concatenate the value name.\n\t\t//\n\t\tinternalStatus = RtlStringCbCatNW(fullKeyValueName, fullKeyValueLength, ValueName->Buffer, ValueName->Length);\n\t\tif (NT_SUCCESS(internalStatus) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Failed to concatenate value name with status 0x%X.\", internalStatus);\n\t\t\tgoto Exit;\n\t\t}\n\n\t\tblockOperation = RegistryBlockingFilter::RegistryStringFilters->MatchesFilter(fullKeyValueName, OperationFlag);\n\n\t\t//DBGPRINT(\"RegistryBlockingFilter!BlockRegistryOperation: Full name: %S.\", fullKeyValueName);\n\t}\n\t__except (EXCEPTION_EXECUTE_HANDLER)\n\t{}\n\n\tif (blockOperation)\n\t{\n\t\t//\n\t\t// Grab the caller's path.\n\t\t//\n\t\tImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &callerProcessPath);\n\n\t\t//\n\t\t// Walk the stack.\n\t\t//\n\t\tRegistryBlockingFilter::walker.WalkAndResolveStack(&registryOperationStack, &registryOperationStackSize, STACK_HISTORY_TAG);\n\n\t\tNT_ASSERT(registryOperationStack);\n\n\t\t//\n\t\t// Only if we successfully walked the stack, report the violation.\n\t\t//\n\t\tif (registryOperationStack != NULL && registryOperationStackSize != 0)\n\t\t{\n\t\t\t//\n\t\t\t// Convert the registry path to a unicode string.\n\t\t\t//\n\t\t\tRtlInitUnicodeString(&registryOperationPath, fullKeyValueName);\n\n\t\t\t//\n\t\t\t// Report the violation.\n\t\t\t//\n\t\t\tRegistryBlockingFilter::detector->ReportFilterViolation(RegistryFilterMatch, PsGetCurrentProcessId(), callerProcessPath, &registryOperationPath, registryOperationStack, registryOperationStackSize);\n\n\t\t\t//\n\t\t\t// Clean up.\n\t\t\t//\n\t\t\tExFreePoolWithTag(registryOperationStack, STACK_HISTORY_TAG);\n\t\t}\n\n\t\tExFreePoolWithTag(callerProcessPath, IMAGE_NAME_TAG);\n\t}\nExit:\n\tif (tempValueName)\n\t{\n\t\tExFreePoolWithTag(tempValueName, REGISTRY_KEY_NAME_TAG);\n\t}\n\tif (fullKeyValueName)\n\t{\n\t\tExFreePoolWithTag(fullKeyValueName, REGISTRY_KEY_NAME_TAG);\n\t}\n\tif (pKeyNameInformation)\n\t{\n\t\tExFreePoolWithTag(pKeyNameInformation, REGISTRY_KEY_NAME_TAG);\n\t}\n\tif (keyHandle)\n\t{\n\t\tZwClose(keyHandle);\n\t}\n\treturn blockOperation;\n}\n\n/**\n\tThe callback for registry operations. If necessary, blocks certain operations on protected keys/values.\n\t@param CallbackContext - Unreferenced parameter.\n\t@param OperationClass - The type of registry operation.\n\t@param Argument2 - A pointer to the structure associated with the operation.\n\t@return The status of the registry operation.\n*/\nNTSTATUS RegistryBlockingFilter::RegistryCallback (\n\t_In_ PVOID CallbackContext,\n\t_In_ REG_NOTIFY_CLASS OperationClass, \n\t_In_ PVOID Argument2\n\t)\n{\n\tUNREFERENCED_PARAMETER(CallbackContext);\n\tNTSTATUS returnStatus;\n\tPREG_SET_VALUE_KEY_INFORMATION setValueInformation;\n\tPREG_DELETE_VALUE_KEY_INFORMATION deleteValueInformation;\n\n\treturnStatus = STATUS_SUCCESS;\n\n\t//\n\t// PeaceMaker is not designed to block kernel operations.\n\t//\n\tif (ExGetPreviousMode() != KernelMode)\n\t{\n\t\tswitch (OperationClass)\n\t\t{\n\t\tcase RegNtPreSetValueKey:\n\t\t\tsetValueInformation = RCAST<PREG_SET_VALUE_KEY_INFORMATION>(Argument2);\n\t\t\tif (BlockRegistryOperation(setValueInformation->Object, setValueInformation->ValueName, FILTER_FLAG_WRITE))\n\t\t\t{\n\t\t\t\tDBGPRINT(\"RegistryBlockingFilter!RegistryCallback: Detected RegNtPreSetValueKey of %wZ. Prevented set!\", setValueInformation->ValueName);\n\t\t\t\treturnStatus = STATUS_ACCESS_DENIED;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase RegNtPreDeleteValueKey:\n\t\t\tdeleteValueInformation = RCAST<PREG_DELETE_VALUE_KEY_INFORMATION>(Argument2);\n\t\t\tif (BlockRegistryOperation(deleteValueInformation->Object, deleteValueInformation->ValueName, FILTER_FLAG_DELETE))\n\t\t\t{\n\t\t\t\tDBGPRINT(\"RegistryBlockingFilter!RegistryCallback: Detected RegNtPreDeleteValueKey of %wZ. Prevented rewrite!\", deleteValueInformation->ValueName);\n\t\t\t\treturnStatus = STATUS_ACCESS_DENIED;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn returnStatus;\n}"
  },
  {
    "path": "PeaceMaker Kernel/RegistryFilter.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"StringFilters.h\"\n#include \"StackWalker.h\"\n#include \"DetectionLogic.h\"\n#include \"ImageHistoryFilter.h\"\n\ntypedef class RegistryBlockingFilter\n{\n\tstatic BOOLEAN BlockRegistryOperation(_In_ PVOID KeyObject,\n\t\t\t\t\t\t\t\t\t\t  _In_ PUNICODE_STRING ValueName,\n\t\t\t\t\t\t\t\t\t\t  _In_ ULONG OperationFlag\n\t\t\t\t\t\t\t\t\t\t  );\n\n\tstatic NTSTATUS RegistryCallback(_In_ PVOID CallbackContext,\n\t\t\t\t\t\t\t\t\t _In_ REG_NOTIFY_CLASS OperationClass,\n\t\t\t\t\t\t\t\t\t _In_ PVOID Argument2\n\t\t\t\t\t\t\t\t\t);\n\n\t//\n\t// Contains strings to block various registry operations.\n\t//\n\tstatic PSTRING_FILTERS RegistryStringFilters;\n\n\t//\n\t// Cookie used to remove registry callback.\n\t//\n\tstatic LARGE_INTEGER RegistryFilterCookie;\n\n\tstatic STACK_WALKER walker;\n\tstatic PDETECTION_LOGIC detector;\npublic:\n\tRegistryBlockingFilter (\n\t\t_In_ PDRIVER_OBJECT DriverObject,\n\t\t_In_ PUNICODE_STRING RegistryPath,\n\t\t_In_ PDETECTION_LOGIC Detector,\n\t\t_Out_ NTSTATUS* Initialized\n\t\t);\n\t~RegistryBlockingFilter();\n\n\tstatic PSTRING_FILTERS GetStringFilters();\n} REGISTRY_BLOCKING_FILTER, *PREGISTRY_BLOCKING_FILTER;\n\n#define STRING_REGISTRY_FILTERS_TAG 'rFmP'\n#define REGISTRY_KEY_NAME_TAG 'nKmP'"
  },
  {
    "path": "PeaceMaker Kernel/StackWalker.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"StackWalker.h\"\n\n/**\n\tSearch the current process to see if any modules contain the address.\n\t@param Address - The address to search for.\n\t@param StackReturnInfo - The structure to be populated.\n*/\nVOID\nStackWalker::ResolveAddressModule (\n\t_In_ PVOID Address,\n\t_Inout_ PSTACK_RETURN_INFO StackReturnInfo\n\t)\n{\n\tNTSTATUS status;\n\tMEMORY_BASIC_INFORMATION meminfo;\n\tSIZE_T returnLength;\n\tSIZE_T mappedFilenameLength;\n\tPUNICODE_STRING mappedFilename;\n\n\tmappedFilenameLength = sizeof(UNICODE_STRING) + MAX_PATH * 2;\n\n\t//\n\t// Query the virtual memory to see if it's part of an image.\n\t//\n\tstatus = ZwQueryVirtualMemory(NtCurrentProcess(), Address, MemoryBasicInformation, &meminfo, sizeof(meminfo), &returnLength);\n\tif (NT_SUCCESS(status) && meminfo.Type == MEM_IMAGE)\n\t{\n\t\tStackReturnInfo->MemoryInModule = TRUE;\n\t\tStackReturnInfo->BinaryOffset = RCAST<ULONG64>(Address) - RCAST<ULONG64>(meminfo.AllocationBase);\n\n\t\t//\n\t\t// Allocate the filename.\n\t\t//\n\t\tmappedFilename = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, mappedFilenameLength, STACK_WALK_MAPPED_NAME));\n\t\tif (mappedFilename == NULL)\n\t\t{\n\t\t\tDBGPRINT(\"StackWalker!ResolveAddressModule: Failed to allocate module name.\");\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// Query the filename.\n\t\t//\n\t\tstatus = ZwQueryVirtualMemory(NtCurrentProcess(), Address, SCAST<MEMORY_INFORMATION_CLASS>(MemoryMappedFilenameInformation), mappedFilename, mappedFilenameLength, &mappedFilenameLength);\n\t\tif (status == STATUS_BUFFER_OVERFLOW)\n\t\t{\n\t\t\t//\n\t\t\t// If we don't have a large enough buffer, allocate one!\n\t\t\t//\n\t\t\tExFreePoolWithTag(mappedFilename, STACK_WALK_MAPPED_NAME);\n\t\t\tmappedFilename = RCAST<PUNICODE_STRING>(ExAllocatePoolWithTag(PagedPool, mappedFilenameLength, STACK_WALK_MAPPED_NAME));\n\t\t\tif (mappedFilename == NULL)\n\t\t\t{\n\t\t\t\tDBGPRINT(\"StackWalker!ResolveAddressModule: Failed to allocate module name.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstatus = ZwQueryVirtualMemory(NtCurrentProcess(), Address, SCAST<MEMORY_INFORMATION_CLASS>(MemoryMappedFilenameInformation), mappedFilename, mappedFilenameLength, &mappedFilenameLength);\n\t\t}\n\n\t\tif (NT_SUCCESS(status) == FALSE)\n\t\t{\n\t\t\tDBGPRINT(\"StackWalker!ResolveAddressModule: Failed to query memory module name with status 0x%X.\", status);\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// Copy the mapped name.\n\t\t//\n\t\tRtlStringCbCopyUnicodeString(RCAST<NTSTRSAFE_PWSTR>(&StackReturnInfo->BinaryPath), sizeof(StackReturnInfo->BinaryPath), mappedFilename);\n\n\t\tExFreePoolWithTag(mappedFilename, STACK_WALK_MAPPED_NAME);\n\t}\n}\n\n/**\n\tCheck if the memory pointed by address is executable.\n\t@param Address - The address to check.\n\t@return Whether or not the memory is executable.\n*/\nBOOLEAN\nStackWalker::IsAddressExecutable (\n\t_In_ PVOID Address\n\t)\n{\n\tNTSTATUS status;\n\tMEMORY_BASIC_INFORMATION memoryBasicInformation;\n\tBOOLEAN executable;\n\n\texecutable = FALSE;\n\tmemset(&memoryBasicInformation, 0, sizeof(memoryBasicInformation));\n\n\t//\n\t// Query the basic information about the memory.\n\t//\n\tstatus = ZwQueryVirtualMemory(NtCurrentProcess(), Address, MemoryBasicInformation, &memoryBasicInformation, sizeof(memoryBasicInformation), NULL);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"StackWalker!IsAddressExecutable: Failed to query virtual memory for address 0x%llx with status 0x%X.\", RCAST<ULONG64>(Address), status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Check if the protection flags specifies executable.\n\t//\n\texecutable = FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE) ||\n\t\t\t\t FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE_READ) ||\n\t\t\t\t FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE_READWRITE) ||\n\t\t\t\t FlagOn(memoryBasicInformation.AllocationProtect, PAGE_EXECUTE_WRITECOPY);\nExit:\n\treturn NT_SUCCESS(status) && executable;\n}\n\n/**\n\tWalk the stack of the current thread and resolve the module associated with the return addresses.\n\t@param ResolvedStack - Caller-supplied array of return address information that this function populates.\n\t@param ResolvedStackSize - The number of return addresses to resolve.\n\t@param ResolvedStackTag - The tag to allocate ResolvedStack with.\n*/\nVOID\nStackWalker::WalkAndResolveStack (\n\t_Inout_ PSTACK_RETURN_INFO* ResolvedStack,\n\t_Inout_ ULONG* ResolvedStackSize,\n\t_In_ ULONG ResolvedStackTag\n\t)\n{\n\tPVOID* stackReturnPtrs;\n\tULONG capturedReturnPtrs;\n\tULONG i;\n\t\n\tcapturedReturnPtrs = 0;\n\t*ResolvedStack = NULL;\n\n\t//\n\t// Allocate space for the return addresses.\n\t//\n\tstackReturnPtrs = RCAST<PVOID*>(ExAllocatePoolWithTag(PagedPool, sizeof(PVOID) * *ResolvedStackSize, STACK_WALK_ARRAY_TAG));\n\tif (stackReturnPtrs == NULL)\n\t{\n\t\tDBGPRINT(\"StackWalker!WalkAndResolveStack: Failed to allocate space for temporary stack array.\");\n\t\tgoto Exit;\n\t}\n\n\tmemset(stackReturnPtrs, 0, sizeof(PVOID) * *ResolvedStackSize);\n\n\t//\n\t// Get the return addresses leading up to this call.\n\t//\n\tcapturedReturnPtrs = RtlWalkFrameChain(stackReturnPtrs, *ResolvedStackSize, 1);\n\tif (capturedReturnPtrs == 0)\n\t{\n\t\tDBGPRINT(\"StackWalker!WalkAndResolveStack: Failed to walk the stack.\");\n\t\tgoto Exit;\n\t}\n\n\tNT_ASSERT(capturedReturnPtrs < ResolvedStackSize);\n\n\t*ResolvedStackSize = capturedReturnPtrs;\n\n\t//\n\t// Allocate space for the stack return info array.\n\t//\n\t*ResolvedStack = RCAST<PSTACK_RETURN_INFO>(ExAllocatePoolWithTag(PagedPool, sizeof(STACK_RETURN_INFO) * *ResolvedStackSize, ResolvedStackTag));\n\tif (*ResolvedStack == NULL)\n\t{\n\t\tDBGPRINT(\"StackWalker!WalkAndResolveStack: Failed to allocate space for stack info array.\");\n\t\tgoto Exit;\n\t}\n\tmemset(*ResolvedStack, 0, sizeof(STACK_RETURN_INFO) * *ResolvedStackSize);\n\n\n\t//\n\t// Iterate each return address and fill out the struct.\n\t//\n\tfor (i = 0; i < capturedReturnPtrs; i++)\n\t{\n\t\t(*ResolvedStack)[i].RawAddress = stackReturnPtrs[i];\n\n\t\t//\n\t\t// If the memory isn't executable or is in kernel, it's not worth our time.\n\t\t//\n\t\tif (RCAST<ULONG64>(stackReturnPtrs[i]) < MmUserProbeAddress && this->IsAddressExecutable(stackReturnPtrs[i]))\n\t\t{\n\t\t\t(*ResolvedStack)[i].ExecutableMemory = TRUE;\n\t\t\tthis->ResolveAddressModule(stackReturnPtrs[i], &(*ResolvedStack)[i]);\n\t\t}\n\t}\nExit:\n\tif (stackReturnPtrs)\n\t{\n\t\tExFreePoolWithTag(stackReturnPtrs, STACK_WALK_ARRAY_TAG);\n\t}\n}"
  },
  {
    "path": "PeaceMaker Kernel/StackWalker.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"shared.h\"\n\ntypedef class StackWalker\n{\n\tBOOLEAN IsAddressExecutable (\n\t\t_In_ PVOID Address\n\t\t);\n\npublic:\n\tStackWalker() {};\n\t\n\tVOID WalkAndResolveStack (\n\t\t_Inout_ PSTACK_RETURN_INFO* ResolvedStack,\n\t\t_Inout_ ULONG* ResolvedStackSize,\n\t\t_In_ ULONG ResolvedStackTag\n\t\t);\n\n\tVOID ResolveAddressModule (\n\t\t_In_ PVOID Address,\n\t\t_Inout_ PSTACK_RETURN_INFO StackReturnInfo\n\t\t);\n} STACK_WALKER, *PSTACK_WALKER;\n\n#define STACK_WALK_ARRAY_TAG 'aSmP'\n#define STACK_WALK_MAPPED_NAME 'nMmP'"
  },
  {
    "path": "PeaceMaker Kernel/StringFilters.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"StringFilters.h\"\n\n/**\n\tInitialize the CUSTOM_FILTERS class by initializing the linked list's lock.\n\t@param Type - The type of filter to add (filesystem or registry).\n\t@param RegistryPath - The registry path of the driver.\n\t@param FilterStoreName - Name of the filter store.\n*/\nStringFilters::StringFilters (\n\t_In_ STRING_FILTER_TYPE FilterType,\n\t_In_ PUNICODE_STRING RegistryPath,\n\t_In_ CONST WCHAR* FilterStoreName\n\t)\n{\n\t//\n\t// Initialize the lock for the filters.\n\t//\n\tFltInitializePushLock(&this->filtersLock);\n\n\tthis->filtersHead = RCAST<PFILTER_INFO_LINKED>(ExAllocatePoolWithTag(NonPagedPool, sizeof(FILTER_INFO_LINKED), FILTER_INFO_TAG));\n\tInitializeListHead(RCAST<PLIST_ENTRY>(this->filtersHead));\n\tthis->destroying = FALSE;\n\n\tthis->filtersCount = 0;\n\tthis->filterType = FilterType;\n\n\t//\n\t// Initialize space for the driver registry key.\n\t//\n\tthis->driverRegistryPath.Buffer = RCAST<PWCH>(ExAllocatePoolWithTag(NonPagedPool, RegistryPath->MaximumLength, FILTER_INFO_TAG));\n\tthis->driverRegistryPath.MaximumLength = RegistryPath->MaximumLength;\n\tRtlCopyUnicodeString(&this->driverRegistryPath, RegistryPath);\n\n\tRtlInitUnicodeString(&this->filterStoreValueName, FilterStoreName);\n}\n\n/**\n\tDestroy the CustomFilters class by clearing the filters linked list and deleting the associated lock.\n*/\nStringFilters::~StringFilters()\n{\n\tPLIST_ENTRY currentFilter;\n\n\t//\n\t// Set destroying to TRUE so that no other threads can get a lock.\n\t//\n\tthis->destroying = TRUE;\n\n\t//\n\t// Acquire an exclusive lock to push out other threads.\n\t//\n\tFltAcquirePushLockExclusive(&this->filtersLock);\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&this->filtersLock);\n\n\t//\n\t// Delete the lock for the filters.\n\t//\n\tFltDeletePushLock(&this->filtersLock);\n\n\t//\n\t// Go through each filter and free it.\n\t//\n\tif (this->filtersHead)\n\t{\n\t\twhile (IsListEmpty(RCAST<PLIST_ENTRY>(this->filtersHead)) == FALSE)\n\t\t{\n\t\t\tcurrentFilter = RemoveHeadList(RCAST<PLIST_ENTRY>(this->filtersHead));\n\t\t\t//\n\t\t\t// Free the filter.\n\t\t\t//\n\t\t\tExFreePoolWithTag(SCAST<PVOID>(currentFilter), FILTER_INFO_TAG);\n\t\t}\n\n\t\t//\n\t\t// Finally, free the list head.\n\t\t//\n\t\tExFreePoolWithTag(SCAST<PVOID>(this->filtersHead), FILTER_INFO_TAG);\n\t}\n\n\t//\n\t// Free the driver registy path.\n\t//\n\tExFreePoolWithTag(this->driverRegistryPath.Buffer, FILTER_INFO_TAG);\n}\n\n/**\n\tAdd a filter to the linked list of filters.\n\t@param MatchString - The string to filter with.\n\t@param OperationFlag - Specifies what operations this filter should be used for.\n\t@param SaveFilters - Whether or not to save filters.\n\t@return A random identifier required for future operations with the new filter.\n*/\nULONG\nStringFilters::AddFilter (\n\t_In_ WCHAR* MatchString,\n\t_In_ ULONG OperationFlag,\n\t_In_ BOOLEAN SaveFilters\n\t)\n{\n\tPFILTER_INFO_LINKED newFilter;\n\tLARGE_INTEGER currentTime;\n\tULONG epochSeconds;\n\n\tif (this == NULL || this->destroying)\n\t{\n\t\treturn NULL;\n\t}\n\n\t//\n\t// Get an exclusive lock because we're modifying the filters linked list.\n\t//\n\tFltAcquirePushLockExclusive(&this->filtersLock);\n\n\t//\n\t// Allocate space for the new filter.\n\t//\n\tnewFilter = RCAST<PFILTER_INFO_LINKED>(ExAllocatePoolWithTag(NonPagedPool, sizeof(FILTER_INFO_LINKED), FILTER_INFO_TAG));\n\tif (newFilter == NULL)\n\t{\n\t\tDBGPRINT(\"Failed to allocate space for filter info.\");\n\t\tgoto Exit;\n\t}\n\n\tmemset(RCAST<PVOID>(newFilter), 0, sizeof(FILTER_INFO_LINKED));\n\n\tInsertTailList(RCAST<PLIST_ENTRY>(this->filtersHead), RCAST<PLIST_ENTRY>(newFilter));\n\n\tthis->filtersCount++;\n\n\t//\n\t// Generate a pseudo-random ID for the filter using the system time.\n\t//\n\tKeQuerySystemTime(&currentTime);\n\tRtlTimeToSecondsSince1970(&currentTime, &epochSeconds);\n\tnewFilter->Filter.Id = RtlRandomEx(&epochSeconds);\n\tnewFilter->Filter.Type = this->filterType;\n\n\t//\n\t// Copy the filter string to the new filter.\n\t//\n\twcsncpy_s(newFilter->Filter.MatchString, MatchString, MAX_PATH);\n\n\t//\n\t// Set the operation flags for this filter.\n\t//\n\tnewFilter->Filter.Flags = OperationFlag;\nExit:\n\t//\n\t// New filter has been initialized, release the lock.\n\t//\n\tFltReleasePushLock(&this->filtersLock);\n\tif (SaveFilters)\n\t{\n\t\tthis->SaveFilters();\n\t}\n\n\tif (newFilter)\n\t{\n\t\treturn newFilter->Filter.Id;\n\t}\n\n\t//\n\t// The ID cannot be 0 because we add 1.\n\t//\n\treturn NULL;\n}\n\n/**\n\tRemove a filter from the linked list of filters.\n\t@param FilterId - The unique filter ID of the filter to delete.\n\t@return Whether or not deletion was successful.\n*/\nBOOLEAN\nStringFilters::RemoveFilter (\n\t_In_ ULONG FilterId\n\t)\n{\n\tBOOLEAN filterDeleted;\n\tPFILTER_INFO_LINKED currentFilter;\n\n\tcurrentFilter = NULL;\n\tfilterDeleted = FALSE;\n\n\tif (this == NULL || this->destroying)\n\t{\n\t\treturn FALSE;\n\t}\n\n\t//\n\t// Get an exclusive lock because we're modifying the filters linked list.\n\t//\n\tFltAcquirePushLockExclusive(&this->filtersLock);\n\n\t//\n\t// Check if we have a single filter already.\n\t//\n\tif (this->filtersHead)\n\t{\n\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);\n\n\t\twhile (currentFilter && currentFilter != this->filtersHead)\n\t\t{\n\t\t\tif (currentFilter->Filter.Id == FilterId)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);\n\t\t}\n\t\t\n\t\t//\n\t\t// Remove the entry from the list.\n\t\t//\n\t\tif (currentFilter && currentFilter != this->filtersHead)\n\t\t{\n\t\t\tRemoveEntryList(RCAST<PLIST_ENTRY>(currentFilter));\n\t\t\tfilterDeleted = TRUE;\n\t\t\tthis->filtersCount--;\n\t\t\t//\n\t\t\t// Free the filter.\n\t\t\t//\n\t\t\tExFreePoolWithTag(SCAST<PVOID>(currentFilter), FILTER_INFO_TAG);\n\t\t}\n\t}\n\n\t//\n\t// Release the lock.\n\t//\n\tFltReleasePushLock(&this->filtersLock);\n\n\tif (filterDeleted)\n\t{\n\t\tthis->SaveFilters();\n\t}\n\n\treturn filterDeleted;\n}\n\n/**\n\tCheck if a string contains any filtered phrases.\n\t@param StrToCmp - The string to search.\n\t@param OperationFlag - Specify FILTER_FLAG_X's to match certain filters for a variety of operations.\n\t@return Whether or not there was a filter that matched.\n*/\nBOOLEAN\nStringFilters::MatchesFilter (\n\t_In_ WCHAR* StrToCmp,\n\t_In_ ULONG OperationFlag\n\t)\n{\n\tBOOLEAN filterMatched;\n\tPFILTER_INFO_LINKED currentFilter;\n\tWCHAR tempStrToCmp[MAX_PATH];\n\tINT i;\n\n\tif (this == NULL || this->destroying)\n\t{\n\t\treturn FALSE;\n\t}\n\n\tfilterMatched = FALSE;\n\n\t//\n\t// Copy the string to compare so we don't modify the original string.\n\t//\n\twcsncpy_s(tempStrToCmp, StrToCmp, MAX_PATH);\n\n\t//\n\t// Make the input string lowercase.\n\t//\n\ti = 0;\n\twhile (tempStrToCmp[i])\n\t{\n\t\ttempStrToCmp[i] = towlower(tempStrToCmp[i]);\n\t\ti++;\n\t}\n\n\t//\n\t// Acquire a shared lock to iterate filters.\n\t//\n\tFltAcquirePushLockShared(&this->filtersLock);\n\n\t//\n\t// Iterate filters for a match.\n\t//\n\tif (this->filtersHead)\n\t{\n\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);\n\t\twhile (currentFilter && currentFilter != this->filtersHead)\n\t\t{\n\t\t\t//\n\t\t\t// Check if the string to compare contains the filter.\n\t\t\t//\n\t\t\tif ((currentFilter->Filter.Flags & OperationFlag) &&\n\t\t\t\t(wcsstr(RCAST<CONST WCHAR*>(&tempStrToCmp), RCAST<CONST WCHAR*>(&currentFilter->Filter.MatchString)) != NULL))\n\t\t\t{\n\t\t\t\tfilterMatched = TRUE;\n\t\t\t\tgoto Exit;\n\t\t\t}\n\t\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);\n\t\t}\n\t}\nExit:\n\tFltReleasePushLock(&this->filtersLock);\n\treturn filterMatched;\n}\n\n/**\n\tGet the filters present in the linked-list.\n\t@param SkipFilters - The number of filters to skip.\n\t@param Filters - The output array.\n\t@param FilterSize - Maximum number of filters.\n\t@return The number of filters copied.\n*/\nULONG\nStringFilters::GetFilters (\n\t_In_ ULONG SkipFilters,\n\t_Inout_ PFILTER_INFO Filters,\n\t_In_ ULONG FiltersSize\n\t)\n{\n\tPFILTER_INFO_LINKED currentFilter;\n\tULONG skipCount;\n\tULONG copyCount;\n\n\tskipCount = 0;\n\tcopyCount = 0;\n\n\t//\n\t// Acquire a shared lock to iterate filters.\n\t//\n\tFltAcquirePushLockShared(&this->filtersLock);\n\n\t//\n\t// Iterate filters for a match.\n\t//\n\tif (this->filtersHead)\n\t{\n\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);\n\t\twhile (currentFilter && currentFilter != this->filtersHead && copyCount < FiltersSize)\n\t\t{\n\t\t\tif (skipCount >= SkipFilters)\n\t\t\t{\n\t\t\t\tmemcpy_s(&Filters[copyCount], sizeof(FILTER_INFO), &currentFilter->Filter, sizeof(FILTER_INFO));\n\t\t\t\tDBGPRINT(\"StringFilters!GetFilters: Copying filter ID 0x%X.\", currentFilter->Filter.Id);\n\t\t\t\tcopyCount++;\n\t\t\t}\n\t\t\tskipCount++;\n\t\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);\n\t\t}\n\t}\n\n\tFltReleasePushLock(&this->filtersLock);\n\n\treturn copyCount;\n}\n\n/**\n\tSave the current filters to the registry for persistence.\n\t@return Whether or not the save was successful.\n*/\nBOOLEAN\nStringFilters::SaveFilters (\n\tVOID\n\t)\n{\n\tPFILTER_STORE filterStore;\n\tPFILTER_INFO_LINKED currentFilter;\n\tULONG i;\n\tOBJECT_ATTRIBUTES driverRegistryAttributes;\n\tNTSTATUS status;\n\tHANDLE driverRegistryKey;\n\tBOOLEAN result;\n\n\tresult = FALSE;\n\tdriverRegistryKey = NULL;\n\ti = 0;\n\n\t//\n\t// Allocate space for the filter store.\n\t//\n\tfilterStore = RCAST<PFILTER_STORE>(ExAllocatePoolWithTag(NonPagedPool, FILTER_STORE_SIZE(this->filtersCount), FILTER_INFO_TAG));\n\tif (filterStore == NULL)\n\t{\n\t\tDBGPRINT(\"StringFilters!SaveFilters: Failed to allocate space for the filter store with size %i.\", this->filtersCount);\n\t\tgoto Exit;\n\t}\n\tmemset(filterStore, 0, sizeof(filterStore));\n\n\t//\n\t// Initialize basic members.\n\t//\n\tfilterStore->FilterCount = this->filtersCount;\n\n\t//\n\t// Acquire a shared lock to iterate filters.\n\t//\n\tFltAcquirePushLockShared(&this->filtersLock);\n\n\t//\n\t// Iterate filters for a match.\n\t//\n\tif (this->filtersHead)\n\t{\n\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(this->filtersHead->ListEntry.Flink);\n\t\twhile (currentFilter && currentFilter != this->filtersHead)\n\t\t{\n\t\t\tmemcpy_s(&filterStore->Filters[i], sizeof(FILTER_INFO), &currentFilter->Filter, sizeof(FILTER_INFO));\n\t\t\ti++;\n\t\t\tcurrentFilter = RCAST<PFILTER_INFO_LINKED>(currentFilter->ListEntry.Flink);\n\t\t}\n\t}\n\n\tFltReleasePushLock(&this->filtersLock);\n\n\t//\n\t// Open the driver's registry key.\n\t//\n\tInitializeObjectAttributes(&driverRegistryAttributes, &this->driverRegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tstatus = ZwOpenKey(&driverRegistryKey, KEY_ALL_ACCESS, &driverRegistryAttributes);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"StringFilters!SaveFilters: Failed to open driver registry key with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Write the current filters.\n\t//\n\tstatus = ZwSetValueKey(driverRegistryKey, &this->filterStoreValueName, 0, REG_BINARY, filterStore, FILTER_STORE_SIZE(this->filtersCount));\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"StringFilters!SaveFilters: Failed to write filter store to driver registry key with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\tresult = TRUE;\nExit:\n\tif (filterStore)\n\t{\n\t\tExFreePoolWithTag(filterStore, FILTER_INFO_TAG);\n\t}\n\tif (driverRegistryKey)\n\t{\n\t\tZwClose(driverRegistryKey);\n\t}\n\treturn result;\n}\n\n/**\n\tRestore filters from the registry.\n\t@return Whether or not the restoration was successful.\n*/\nBOOLEAN\nStringFilters::RestoreFilters (\n\tVOID\n\t)\n{\n\tOBJECT_ATTRIBUTES driverRegistryAttributes;\n\tNTSTATUS status;\n\tHANDLE driverRegistryKey;\n\tULONG filterStorePartialSize;\n\tPFILTER_STORE filterStore;\n\tPKEY_VALUE_PARTIAL_INFORMATION filterStorePartial;\n\tULONG i;\n\tBOOLEAN result;\n\n\tresult = FALSE;\n\ti = 0;\n\tfilterStorePartial = NULL;\n\tfilterStore = NULL;\n\n\t//\n\t// Open the driver's registry key.\n\t//\n\tInitializeObjectAttributes(&driverRegistryAttributes, &this->driverRegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tstatus = ZwOpenKey(&driverRegistryKey, KEY_ALL_ACCESS, &driverRegistryAttributes);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"StringFilters!RestoreFilters: Failed to open driver registry key with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\t\n\t//\n\t// Read the size of the FilterStore.\n\t//\n\tstatus = ZwQueryValueKey(driverRegistryKey, &this->filterStoreValueName, KeyValuePartialInformation, NULL, 0, &filterStorePartialSize);\n\tif (status != STATUS_BUFFER_TOO_SMALL)\n\t{\n\t\tDBGPRINT(\"StringFilters!RestoreFilters: Failed to query filter store size with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\t\n\t//\n\t// Allocate space for the FilterStore partial struct and query the actual value.\n\t//\n\tfilterStorePartial = RCAST<PKEY_VALUE_PARTIAL_INFORMATION>(ExAllocatePoolWithTag(NonPagedPool, filterStorePartialSize, FILTER_INFO_TAG));\n\tstatus = ZwQueryValueKey(driverRegistryKey, &this->filterStoreValueName, KeyValuePartialInformation, filterStorePartial, filterStorePartialSize, &filterStorePartialSize);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"StringFilters!RestoreFilters: Failed to query filter store with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\t\n\t//\n\t// Grab the filter store from the data member of the partial struct.\n\t//\n\tfilterStore = RCAST<PFILTER_STORE>(filterStorePartial->Data);\n\n\t//\n\t// Add the filters.\n\t//\n\tfor (i = 0; i < filterStore->FilterCount; i++)\n\t{\n\t\tthis->AddFilter(filterStore->Filters[i].MatchString, filterStore->Filters[i].Flags, FALSE);\n\t}\n\tresult = TRUE;\nExit:\n\tif (driverRegistryKey)\n\t{\n\t\tZwClose(driverRegistryKey);\n\t}\n\tif (filterStorePartial)\n\t{\n\t\tExFreePoolWithTag(filterStorePartial, FILTER_INFO_TAG);\n\t}\n\treturn result;\n}"
  },
  {
    "path": "PeaceMaker Kernel/StringFilters.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"shared.h\"\n\ntypedef struct FilterInfoLinked\n{\n\tLIST_ENTRY ListEntry;\t// The list entry used to iterate multiple filters.\n\tFILTER_INFO Filter;\t\t// The filter itself.\n} FILTER_INFO_LINKED, *PFILTER_INFO_LINKED;\n\ntypedef struct FilterStore\n{\n\tULONG FilterCount;\t\t// Number of filters in the following array.\n\tFILTER_INFO Filters[1];\t// Dynamically-sized array based on FilterCount member.\n} FILTER_STORE, *PFILTER_STORE;\n\n#define FILTER_STORE_SIZE(filterCount) sizeof(FILTER_STORE) + (sizeof(FILTER_INFO) * (filterCount - 1))\n\ntypedef class StringFilters\n{\n\tPFILTER_INFO_LINKED filtersHead; // The linked list of filters.\n\tEX_PUSH_LOCK filtersLock; // The lock protecting the linked list of filters.\n\tBOOLEAN destroying; // This boolean indicates to functions that a lock should not be held as we are in the process of destruction.\n\tUNICODE_STRING driverRegistryPath; // Used for filter persistence across reboots.\n\tUNICODE_STRING filterStoreValueName; // Used for filter persistence across reboots.\n\tSTRING_FILTER_TYPE filterType; // What type of filter this class stores.\npublic:\n\tStringFilters(\n\t\t_In_ STRING_FILTER_TYPE FilterType,\n\t\t_In_ PUNICODE_STRING RegistryPath,\n\t\t_In_ CONST WCHAR* FilterStoreName\n\t\t);\n\t~StringFilters();\n\n\tULONG AddFilter(\n\t\t_In_ WCHAR* MatchString,\n\t\t_In_ ULONG OperationFlag,\n\t\t_In_ BOOLEAN SaveFilters = TRUE\n\t\t);\n\tBOOLEAN RemoveFilter(\n\t\t_In_ ULONG FilterId\n\t\t);\n\tULONG GetFilters(\n\t\t_In_ ULONG SkipFilters,\n\t\t_Inout_ PFILTER_INFO Filters,\n\t\t_In_ ULONG FiltersSize\n\t\t);\n\n\tBOOLEAN MatchesFilter(\n\t\t_In_ WCHAR* StrToCmp,\n\t\t_In_ ULONG OperationFlag\n\t\t);\n\n\tBOOLEAN SaveFilters(\n\t\tVOID\n\t\t);\n\n\tBOOLEAN RestoreFilters(\n\t\tVOID\n\t\t);\n\n\tULONG filtersCount;\t// Count of filters in the linked-list.\n} STRING_FILTERS, *PSTRING_FILTERS;\n\n#define FILTER_INFO_TAG 'iFmP'"
  },
  {
    "path": "PeaceMaker Kernel/TamperGuard.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"TamperGuard.h\"\n\nHANDLE TamperGuard::ProtectedProcessId;\n\n/**\n\tInitialize tamper protection. This constructor will create appropriate callbacks.\n\t@param InitializeStatus - Status of initialization.\n*/\nTamperGuard::TamperGuard (\n\t_Out_ NTSTATUS* InitializeStatus\n\t)\n{\n\tUNICODE_STRING CallbackAltitude;\n\n\tRtlInitUnicodeString(&CallbackAltitude, FILTER_ALTITUDE);\n\n\tObRegistrationInformation.Version = OB_FLT_REGISTRATION_VERSION;\n\tObRegistrationInformation.OperationRegistrationCount = 2;\n\tObRegistrationInformation.Altitude = CallbackAltitude;\n\tObRegistrationInformation.RegistrationContext = NULL;\n\tObRegistrationInformation.OperationRegistration = ObOperationRegistration;\n\n\t//\n\t// We want to protect both the process and the threads of the protected process.\n\t//\n\tObOperationRegistration[0].ObjectType = PsProcessType;\n\tObOperationRegistration[0].Operations |= OB_OPERATION_HANDLE_CREATE;\n\tObOperationRegistration[0].Operations |= OB_OPERATION_HANDLE_DUPLICATE;\n\tObOperationRegistration[0].PreOperation = PreOperationCallback;\n\n\tObOperationRegistration[1].ObjectType = PsThreadType;\n\tObOperationRegistration[1].Operations |= OB_OPERATION_HANDLE_CREATE;\n\tObOperationRegistration[1].Operations |= OB_OPERATION_HANDLE_DUPLICATE;\n\tObOperationRegistration[1].PreOperation = PreOperationCallback;\n\n\t//\n\t// Actually register the callbacks.\n\t//\n\t*InitializeStatus = ObRegisterCallbacks(&ObRegistrationInformation, &RegistrationHandle);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"TamperGuard!TamperGuard: Failed to register object callbacks with status 0x%X.\", *InitializeStatus);\n\t}\n}\n\n/**\n\tDestruct tamper guard members.\n*/\nTamperGuard::~TamperGuard (\n\tVOID\n\t)\n{\n\tObUnRegisterCallbacks(RegistrationHandle);\n}\n\n/**\n\tUpdate the process to protect.\n\t@param NewProcessId - The new process to protect from tampering.\n*/\nVOID\nTamperGuard::UpdateProtectedProcess (\n\t_In_ HANDLE NewProcessId\n\t)\n{\n\tTamperGuard::ProtectedProcessId = NewProcessId;\n}\n\n/**\n\tFilter for certain operations on a protected process.\n\t@param RegistrationContext - Always NULL.\n\t@param OperationInformation - Information about the current operation.\n*/\nOB_PREOP_CALLBACK_STATUS\nTamperGuard::PreOperationCallback (\n\t_In_ PVOID RegistrationContext,\n\t_In_ POB_PRE_OPERATION_INFORMATION OperationInformation\n\t)\n{\n\tHANDLE callerProcessId;\n\tHANDLE targetProcessId;\n\tACCESS_MASK targetAccessMask;\n\n\tUNREFERENCED_PARAMETER(RegistrationContext);\n\n\tcallerProcessId = NULL;\n\ttargetProcessId = NULL;\n\ttargetAccessMask = NULL;\n\tcallerProcessId = PsGetCurrentProcessId();\n\n\t//\n\t// Grab the appropriate process IDs based on the operation object type.\n\t//\n\tif (OperationInformation->ObjectType == *PsProcessType)\n\t{\n\t\ttargetProcessId = PsGetProcessId(RCAST<PEPROCESS>(OperationInformation->Object));\n\t\ttargetAccessMask = PROCESS_TERMINATE;\n\t}\n\telse if (OperationInformation->ObjectType == *PsThreadType)\n\t{\n\t\ttargetProcessId = PsGetThreadProcessId(RCAST<PETHREAD>(OperationInformation->Object));\n\t\ttargetAccessMask = THREAD_TERMINATE;\n\t}\n\n\t//\n\t// If this is an operation on your own process, ignore it.\n\t//\n\tif (callerProcessId == targetProcessId)\n\t{\n\t\treturn OB_PREOP_SUCCESS;\n\t}\n\n\t//\n\t// If the target process isn't the process we're protecting, no issue.\n\t//\n\tif (targetProcessId != TamperGuard::ProtectedProcessId)\n\t{\n\t\treturn OB_PREOP_SUCCESS;\n\t}\n\n\t//\n\t// Strip the proper desired access ACCESS_MASK.\n\t//\n\tswitch (OperationInformation->Operation)\n\t{\n\tcase OB_OPERATION_HANDLE_CREATE:\n\t\tOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~targetAccessMask;\n\t\tbreak;\n\tcase OB_OPERATION_HANDLE_DUPLICATE:\n\t\tOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~targetAccessMask;\n\t\tbreak;\n\t}\n\n\tDBGPRINT(\"TamperGuard!PreOperationCallback: Stripped process 0x%X terminate handle on protected process.\", callerProcessId);\n\n\treturn OB_PREOP_SUCCESS;\n}"
  },
  {
    "path": "PeaceMaker Kernel/TamperGuard.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"shared.h\"\n\ntypedef class TamperGuard\n{\n\tstatic OB_PREOP_CALLBACK_STATUS PreOperationCallback(_In_ PVOID RegistrationContext,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t _In_ POB_PRE_OPERATION_INFORMATION OperationInformation\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t );\n\tOB_CALLBACK_REGISTRATION ObRegistrationInformation;\n\tOB_OPERATION_REGISTRATION ObOperationRegistration[2];\n\tPVOID RegistrationHandle;\n\n\tstatic HANDLE ProtectedProcessId;\npublic:\n\tTamperGuard(_Out_ NTSTATUS* InitializeStatus\n\t\t\t\t);\n\t~TamperGuard(VOID);\n\n\tVOID UpdateProtectedProcess(_In_ HANDLE NewProcessId\n\t\t\t\t\t\t\t\t);\n} TAMPER_GUARD, *PTAMPER_GUARD;\n\n#define PROCESS_TERMINATE                  (0x0001)  \n#define THREAD_TERMINATE                 (0x0001)  "
  },
  {
    "path": "PeaceMaker Kernel/ThreadFilter.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"ThreadFilter.h\"\n\nPDETECTION_LOGIC ThreadFilter::Detector;\t// Detection utility.\nSTACK_WALKER ThreadFilter::Walker;\t\t\t// Stack walking utility.\n\n/**\n\tInitialize thread notify filters to detect manually mapped threads.\n\t@param DetectionLogic - Detection instance used to analyze untrusted operations.\n\t@param InitializeStatus - Status of initialization.\n*/\nThreadFilter::ThreadFilter (\n\t_In_ PDETECTION_LOGIC DetectionLogic,\n\t_Inout_ NTSTATUS* InitializeStatus\n\t)\n{\n\tThreadFilter::Detector = DetectionLogic;\n\n\t//\n\t// Create a thread notify routine.\n\t//\n\t*InitializeStatus = PsSetCreateThreadNotifyRoutine(ThreadFilter::ThreadNotifyRoutine);\n\tif (NT_SUCCESS(*InitializeStatus) == FALSE)\n\t{\n\t\tDBGPRINT(\"ThreadFilter!ThreadFilter: Failed to create thread notify routine with status 0x%X.\", *InitializeStatus);\n\t}\n}\n\n/**\n\tTeardown dynamic components of the thread filter.\n*/\nThreadFilter::~ThreadFilter (\n\tVOID\n\t)\n{\n\tPsRemoveCreateThreadNotifyRoutine(ThreadFilter::ThreadNotifyRoutine);\n}\n\n/**\n\tQuery a thread's start address for validation.\n\t@param ThreadId - The target thread's ID.\n\t@return The start address of the target thread.\n*/\nPVOID\nThreadFilter::GetThreadStartAddress (\n\t_In_ HANDLE ThreadId\n\t)\n{\n\tNTSTATUS status;\n\tPVOID startAddress;\n\tPETHREAD threadObject;\n\tHANDLE threadHandle;\n\tULONG returnLength;\n\n\tstartAddress = NULL;\n\tthreadHandle = NULL;\n\n\t//\n\t// First look up the PETHREAD of the thread.\n\t//\n\tstatus = PsLookupThreadByThreadId(ThreadId, &threadObject);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"ThreadFilter!GetThreadStartAddress: Failed to lookup thread 0x%X by its ID.\", ThreadId);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Open a handle to the thread.\n\t//\n\tstatus = ObOpenObjectByPointer(threadObject, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, *PsThreadType, KernelMode, &threadHandle);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"ThreadFilter!GetThreadStartAddress: Failed to open handle to process with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\n\n\t//\n\t// Query the thread's start address.\n\t//\n\tstatus = NtQueryInformationThread(threadHandle, ThreadQuerySetWin32StartAddress, &startAddress, sizeof(startAddress), &returnLength);\n\tif (NT_SUCCESS(status) == FALSE)\n\t{\n\t\tDBGPRINT(\"ThreadFilter!GetThreadStartAddress: Failed to query thread start address with status 0x%X.\", status);\n\t\tgoto Exit;\n\t}\nExit:\n\tif (threadHandle != NULL)\n\t{\n\t\tZwClose(threadHandle);\n\t}\n\treturn startAddress;\n}\n\n/**\n\tCalled when a new thread is created. Ensure the thread is legit.\n\t@param ProcessId - The process ID of the process receiving the new thread.\n\t@param ThreadId - The thread ID of the new thread.\n\t@param Create - Whether or not this is termination of a thread or creation.\n*/\nVOID\nThreadFilter::ThreadNotifyRoutine (\n\t_In_ HANDLE ProcessId,\n\t_In_ HANDLE ThreadId,\n\t_In_ BOOLEAN Create\n\t)\n{\n\tULONG processThreadCount;\n\tPVOID threadStartAddress;\n\tPSTACK_RETURN_INFO threadCreateStack;\n\tULONG threadCreateStackSize;\n\tPUNICODE_STRING threadCallerName;\n\tPUNICODE_STRING threadTargetName;\n\n\tthreadCreateStack = NULL;\n\tthreadCreateStackSize = 20;\n\tthreadCallerName = NULL;\n\tthreadTargetName = NULL;\n\n\t//\n\t// We don't really care about thread termination or if the thread is kernel-mode.\n\t//\n\tif (Create == FALSE || ExGetPreviousMode() == KernelMode)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// If we can't find the process or it's the first thread of the process, skip it.\n\t//\n\tif (ImageHistoryFilter::AddProcessThreadCount(ProcessId, &processThreadCount) == FALSE ||\n\t\tprocessThreadCount <= 1)\n\t{\n\t\treturn;\n\t}\n\n\t//\n\t// Walk the stack.\n\t//\n\tThreadFilter::Walker.WalkAndResolveStack(&threadCreateStack, &threadCreateStackSize, STACK_HISTORY_TAG);\n\n\t//\n\t// Grab the name of the caller.\n\t//\n\tif (ImageHistoryFilter::GetProcessImageFileName(PsGetCurrentProcessId(), &threadCallerName) == FALSE)\n\t{\n\t\tgoto Exit;\n\t}\n\n\tthreadTargetName = threadCallerName;\n\n\t//\n\t// We only need to resolve again if the target process is a different than the caller.\n\t//\n\tif (PsGetCurrentProcessId() != ProcessId)\n\t{\n\t\t//\n\t\t// Grab the name of the target.\n\t\t//\n\t\tif (ImageHistoryFilter::GetProcessImageFileName(ProcessId, &threadTargetName) == FALSE)\n\t\t{\n\t\t\tgoto Exit;\n\t\t}\n\t}\n\t\n\t//\n\t// Grab the start address of the thread.\n\t//\n\tthreadStartAddress = ThreadFilter::GetThreadStartAddress(ThreadId);\n\n\t//\n\t// Audit the target's start address.\n\t//\n\tThreadFilter::Detector->AuditUserPointer(ThreadCreate, threadStartAddress, PsGetCurrentProcessId(), threadCallerName, threadTargetName, threadCreateStack, threadCreateStackSize);\n\n\t//\n\t// Audit the caller's stack.\n\t//\n\tThreadFilter::Detector->AuditUserStackWalk(ThreadCreate, PsGetCurrentProcessId(), threadCallerName, threadTargetName, threadCreateStack, threadCreateStackSize);\n\n\t//\n\t// Check if this is a remote operation.\n\t//\n\tThreadFilter::Detector->AuditCallerProcessId(ThreadCreate, PsGetCurrentProcessId(), ProcessId, threadCallerName, threadTargetName, threadCreateStack, threadCreateStackSize);\nExit:\n\tif (threadCreateStack != NULL)\n\t{\n\t\tExFreePoolWithTag(threadCreateStack, STACK_HISTORY_TAG);\n\t}\n\tif (threadCallerName != NULL)\n\t{\n\t\tExFreePoolWithTag(threadCallerName, IMAGE_NAME_TAG);\n\t}\n\tif (threadCallerName != threadTargetName && threadTargetName != NULL)\n\t{\n\t\tExFreePoolWithTag(threadTargetName, IMAGE_NAME_TAG);\n\t}\n}"
  },
  {
    "path": "PeaceMaker Kernel/ThreadFilter.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"common.h\"\n#include \"DetectionLogic.h\"\n#include \"ImageHistoryFilter.h\"\n#include \"StackWalker.h\"\n\ntypedef class ThreadFilter\n{\n\tstatic PDETECTION_LOGIC Detector;\t// Detection utility.\n\tstatic STACK_WALKER Walker;\t\t\t// Stack walking utility.\n\n\tstatic PVOID GetThreadStartAddress(\n\t\t_In_ HANDLE ThreadId\n\t\t);\n\n\tstatic VOID ThreadNotifyRoutine(\n\t\tHANDLE ProcessId,\n\t\tHANDLE ThreadId,\n\t\tBOOLEAN Create\n\t\t);\npublic:\n\tThreadFilter(\n\t\t_In_ PDETECTION_LOGIC DetectionLogic,\n\t\t_Inout_ NTSTATUS* InitializeStatus\n\t\t);\n\t~ThreadFilter(VOID);\n\n\n} THREAD_FILTER, *PTHREAD_FILTER;"
  },
  {
    "path": "PeaceMaker Kernel/common.cpp",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#include \"common.h\"\n#include \"shared.h\"\n\nvoid* __cdecl operator new(size_t size, POOL_TYPE pool, ULONG tag) {\n\tPVOID newAddress = ExAllocatePoolWithTag(pool, size, tag);\n\t//\n\t// Remove remenants from previous use.\n\t//\n\tif (newAddress)\n\t{\n\t\tmemset(newAddress, 0, size);\n\t}\n\treturn newAddress;\n}\n\nvoid __cdecl operator delete(void* p, unsigned __int64) {\n\tExFreePool(p);\n}\n\nPPEB PsGetProcessPeb(IN PEPROCESS Process)\n{\n\tUNICODE_STRING funcName;\n\ttypedef PPEB(NTAPI* PsGetProcessPeb_t)(PEPROCESS Process);\n\tstatic PsGetProcessPeb_t fPsGetProcessPeb = NULL;\n\n\tif (fPsGetProcessPeb == NULL)\n\t{\n\t\tRtlInitUnicodeString(&funcName, L\"PsGetProcessPeb\");\n\t\tfPsGetProcessPeb = RCAST<PsGetProcessPeb_t>(MmGetSystemRoutineAddress(&funcName));\n\t}\n\n\treturn fPsGetProcessPeb(Process);\n}\n\nNTSTATUS NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength)\n{\n\tUNICODE_STRING funcName;\n\ttypedef NTSTATUS(NTAPI* NtQueryInformationProcess_t)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);\n\tstatic NtQueryInformationProcess_t fNtQueryInformationProcess = NULL;\n\n\tif (fNtQueryInformationProcess == NULL)\n\t{\n\t\tRtlInitUnicodeString(&funcName, L\"ZwQueryInformationProcess\");\n\t\tfNtQueryInformationProcess = RCAST<NtQueryInformationProcess_t>(MmGetSystemRoutineAddress(&funcName));\n\t}\n\n\treturn fNtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength);\n}\n\nNTSTATUS NtQueryInformationThread(_In_ HANDLE ThreadHandle, _In_ THREADINFOCLASS ThreadInformationClass, _Out_ PVOID ThreadInformation, _In_ ULONG ThreadInformationLength, _Out_ PULONG ReturnLength)\n{\n\tUNICODE_STRING funcName;\n\ttypedef NTSTATUS(NTAPI * NtQueryInformationThread_t)(_In_ HANDLE ThreadHandle, _In_ THREADINFOCLASS ThreadInformationClass, _Out_ PVOID ThreadInformation, _In_ ULONG ThreadInformationLength, _Out_ PULONG ReturnLength);\n\tstatic NtQueryInformationThread_t fNtQueryInformationThread = NULL;\n\n\tif (fNtQueryInformationThread == NULL)\n\t{\n\t\tRtlInitUnicodeString(&funcName, L\"ZwQueryInformationThread\");\n\t\tfNtQueryInformationThread = RCAST<NtQueryInformationThread_t>(MmGetSystemRoutineAddress(&funcName));\n\t}\n\n\treturn fNtQueryInformationThread(ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength);\n}\n"
  },
  {
    "path": "PeaceMaker Kernel/common.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include \"ntdef.h\"\n\n#define MAX_PATH 260\n\n#define DBGPRINT(msg, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, msg\"\\n\", __VA_ARGS__)\n\nvoid* __cdecl operator new(size_t size, POOL_TYPE pool, ULONG tag = 0);\nvoid __cdecl operator delete(void* p, unsigned __int64);\n\n#define FILTER_ALTITUDE L\"321410\"\n\n#define TICKSPERSEC        10000000\n#define SECSPERDAY         86400\n#define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)\n\nPPEB NTAPI PsGetProcessPeb(IN PEPROCESS Process);\nNTSTATUS NTAPI NtQueryInformationProcess(_In_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass, _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, _In_ ULONG ProcessInformationLength, _Out_opt_ PULONG ReturnLength);\nNTSTATUS NTAPI NtQueryInformationThread(_In_ HANDLE ThreadHandle, _In_ THREADINFOCLASS ThreadInformationClass, _Out_ PVOID ThreadInformation, _In_ ULONG ThreadInformationLength, _Out_ PULONG ReturnLength);"
  },
  {
    "path": "PeaceMaker Kernel/ntdef.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#include <fltKernel.h>\n#include <dontuse.h>\n#include <ntstrsafe.h>\n\ntypedef struct _LDR_MODULE {\n    LIST_ENTRY InLoadOrderModuleList;\n    LIST_ENTRY InMemoryOrderModuleList;\n    LIST_ENTRY InInitializationOrderModuleList;\n    PVOID BaseAddress;\n    PVOID EntryPoint;\n    ULONG SizeOfImage;\n    UNICODE_STRING FullDllName;\n    UNICODE_STRING BaseDllName;\n    ULONG Flags;\n    SHORT LoadCount;\n    SHORT TlsIndex;\n    LIST_ENTRY HashTableEntry;\n    ULONG TimeDateStamp;\n} LDR_MODULE, * PLDR_MODULE;\n\ntypedef struct _PEB_LDR_DATA\n{\n    ULONG Length;\n    UCHAR Initialized;\n    PVOID SsHandle;\n    LIST_ENTRY InLoadOrderModuleList;\n    LIST_ENTRY InMemoryOrderModuleList;\n    LIST_ENTRY InInitializationOrderModuleList;\n    PVOID EntryInProgress;\n} PEB_LDR_DATA, * PPEB_LDR_DATA;\n\ntypedef struct _PEB\n{\n    UCHAR InheritedAddressSpace;\n    UCHAR ReadImageFileExecOptions;\n    UCHAR BeingDebugged;\n    UCHAR BitField;\n    ULONG ImageUsesLargePages : 1;\n    ULONG IsProtectedProcess : 1;\n    ULONG IsLegacyProcess : 1;\n    ULONG IsImageDynamicallyRelocated : 1;\n    ULONG SpareBits : 4;\n    PVOID Mutant;\n    PVOID ImageBaseAddress;\n    PPEB_LDR_DATA Ldr;\n    PVOID ProcessParameters;\n    PVOID SubSystemData;\n    PVOID ProcessHeap;\n    PVOID FastPebLock;\n    PVOID AtlThunkSListPtr;\n    PVOID IFEOKey;\n    ULONG CrossProcessFlags;\n    ULONG ProcessInJob : 1;\n    ULONG ProcessInitializing : 1;\n    ULONG ReservedBits0 : 30;\n    union\n    {\n        PVOID KernelCallbackTable;\n        PVOID UserSharedInfoPtr;\n    };\n    ULONG SystemReserved[1];\n    ULONG SpareUlong;\n    PVOID FreeList;\n    ULONG TlsExpansionCounter;\n    PVOID TlsBitmap;\n    ULONG TlsBitmapBits[2];\n    PVOID ReadOnlySharedMemoryBase;\n    PVOID HotpatchInformation;\n    VOID** ReadOnlyStaticServerData;\n    PVOID AnsiCodePageData;\n    PVOID OemCodePageData;\n    PVOID UnicodeCaseTableData;\n    ULONG NumberOfProcessors;\n    ULONG NtGlobalFlag;\n    LARGE_INTEGER CriticalSectionTimeout;\n    ULONG HeapSegmentReserve;\n    ULONG HeapSegmentCommit;\n    ULONG HeapDeCommitTotalFreeThreshold;\n    ULONG HeapDeCommitFreeBlockThreshold;\n    ULONG NumberOfHeaps;\n    ULONG MaximumNumberOfHeaps;\n    VOID** ProcessHeaps;\n    PVOID GdiSharedHandleTable;\n    PVOID ProcessStarterHelper;\n    ULONG GdiDCAttributeList;\n    PVOID LoaderLock;\n    ULONG OSMajorVersion;\n    ULONG OSMinorVersion;\n    SHORT OSBuildNumber;\n    SHORT OSCSDVersion;\n    ULONG OSPlatformId;\n    ULONG ImageSubsystem;\n    ULONG ImageSubsystemMajorVersion;\n    ULONG ImageSubsystemMinorVersion;\n    ULONG ImageProcessAffinityMask;\n    ULONG GdiHandleBuffer[34];\n    PVOID PostProcessInitRoutine;\n    PVOID TlsExpansionBitmap;\n    ULONG TlsExpansionBitmapBits[32];\n    ULONG SessionId;\n    ULARGE_INTEGER AppCompatFlags;\n    ULARGE_INTEGER AppCompatFlagsUser;\n    PVOID pShimData;\n    PVOID AppCompatInfo;\n    UNICODE_STRING CSDVersion;\n    PVOID ActivationContextData;\n    PVOID ProcessAssemblyStorageMap;\n    PVOID SystemDefaultActivationContextData;\n    PVOID SystemAssemblyStorageMap;\n    ULONG MinimumStackCommit;\n    PVOID FlsCallback;\n    LIST_ENTRY FlsListHead;\n    PVOID FlsBitmap;\n    ULONG FlsBitmapBits[4];\n    ULONG FlsHighIndex;\n    PVOID WerRegistrationData;\n    PVOID WerShipAssertPtr;\n} PEB, * PPEB;\n\n#pragma warning(disable : 4201)\ntypedef struct _KNONVOLATILE_CONTEXT_POINTERS {\n    union {\n        PM128A FloatingContext[16];\n        struct {\n            PM128A Xmm0;\n            PM128A Xmm1;\n            PM128A Xmm2;\n            PM128A Xmm3;\n            PM128A Xmm4;\n            PM128A Xmm5;\n            PM128A Xmm6;\n            PM128A Xmm7;\n            PM128A Xmm8;\n            PM128A Xmm9;\n            PM128A Xmm10;\n            PM128A Xmm11;\n            PM128A Xmm12;\n            PM128A Xmm13;\n            PM128A Xmm14;\n            PM128A Xmm15;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME;\n\n    union {\n        PDWORD64 IntegerContext[16];\n        struct {\n            PDWORD64 Rax;\n            PDWORD64 Rcx;\n            PDWORD64 Rdx;\n            PDWORD64 Rbx;\n            PDWORD64 Rsp;\n            PDWORD64 Rbp;\n            PDWORD64 Rsi;\n            PDWORD64 Rdi;\n            PDWORD64 R8;\n            PDWORD64 R9;\n            PDWORD64 R10;\n            PDWORD64 R11;\n            PDWORD64 R12;\n            PDWORD64 R13;\n            PDWORD64 R14;\n            PDWORD64 R15;\n        } DUMMYSTRUCTNAME;\n    } DUMMYUNIONNAME2;\n\n} KNONVOLATILE_CONTEXT_POINTERS, * PKNONVOLATILE_CONTEXT_POINTERS;\n\n#pragma warning(default : 4201)\n\n\ntypedef struct _SCOPE_TABLE_AMD64 {\n    DWORD Count;\n    struct {\n        DWORD BeginAddress;\n        DWORD EndAddress;\n        DWORD HandlerAddress;\n        DWORD JumpTarget;\n    } ScopeRecord[1];\n} SCOPE_TABLE_AMD64, * PSCOPE_TABLE_AMD64;\n\ntypedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY RUNTIME_FUNCTION, * PRUNTIME_FUNCTION;\ntypedef SCOPE_TABLE_AMD64 SCOPE_TABLE, * PSCOPE_TABLE;\n\n#define UNWIND_HISTORY_TABLE_SIZE 12\n\ntypedef struct _UNWIND_HISTORY_TABLE_ENTRY {\n    DWORD64 ImageBase;\n    PRUNTIME_FUNCTION FunctionEntry;\n} UNWIND_HISTORY_TABLE_ENTRY, * PUNWIND_HISTORY_TABLE_ENTRY;\n\ntypedef struct _UNWIND_HISTORY_TABLE {\n    DWORD Count;\n    UCHAR  LocalHint;\n    UCHAR  GlobalHint;\n    UCHAR  Search;\n    UCHAR  Once;\n    DWORD64 LowAddress;\n    DWORD64 HighAddress;\n    UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE];\n} UNWIND_HISTORY_TABLE, * PUNWIND_HISTORY_TABLE;\n\n#define UNW_FLAG_NHANDLER       0x0\n#define UNW_FLAG_EHANDLER       0x1\n#define UNW_FLAG_UHANDLER       0x2\n#define UNW_FLAG_CHAININFO      0x4\n\n#define MEM_IMAGE 0x1000000\n\n#define MemoryWorkingSetInformation 0x1\n#define MemoryMappedFilenameInformation 0x2\n#define MemoryRegionInformation 0x3\n#define MemoryWorkingSetExInformation 0x4\n#define MemorySharedCommitInformation 0x5\n#define MemoryImageInformation 0x6\n#define MemoryRegionInformationEx 0x7\n#define MemoryPrivilegedBasicInformation 0x8\n#define MemoryEnclaveImageInformation 0x9\n#define MemoryBasicInformationCapped 0xA"
  },
  {
    "path": "PeaceMaker Kernel/shared.h",
    "content": "/*\n * This file is subject to the terms and conditions defined in\n * file 'LICENSE', which is part of this source code package.\n * \n * COPYRIGHT Bill Demirkapi 2020\n */\n#pragma once\n#if _KERNEL_MODE == 1\n#include <fltKernel.h>\n#else\n#include <Windows.h>\n#endif\n\n#define GLOBAL_NAME\t\t\tL\"\\\\\\\\.\\\\PeaceMaker\"\n#define NT_DEVICE_NAME      L\"\\\\Device\\\\PeaceMaker\"\n#define DOS_DEVICE_NAME     L\"\\\\DosDevices\\\\PeaceMaker\"\n\n#define IOCTL_ALERTS_QUEUED\t\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x1, METHOD_BUFFERED, FILE_WRITE_DATA)\n#define IOCTL_POP_ALERT\t\t\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x2, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_GET_PROCESSES\t\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x3, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_GET_PROCESS_DETAILED\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x4, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_ADD_FILTER\t\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x5, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_LIST_FILTERS\t\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x6, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_GET_IMAGE_DETAILED\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x7, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_GET_PROCESS_SIZES\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x8, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n#define IOCTL_GET_GLOBAL_SIZES\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x9, METHOD_BUFFERED, FILE_WRITE_DATA)\n#define IOCTL_DELETE_FILTER\t\t\tCTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x10, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\n\n#define RCAST reinterpret_cast\n#define SCAST static_cast\n#define CCAST const_cast\n\n#define CONFIG_FILE_NAME \"peacemaker.cfg\"\n\n//\n// Maximum amount of STACK_RETURN_INFO to have in the process execution stack return history.\n//\n#define MAX_STACK_RETURN_HISTORY 30\n\ntypedef struct ProcessSummaryEntry\n{\n\tHANDLE ProcessId;\t\t\t\t// The process id of the executed process.\n\tWCHAR ImageFileName[MAX_PATH];\t// The image file name of the executed process.\n\tULONGLONG EpochExecutionTime;\t// Process execution time in seconds since 1970.\n\tBOOLEAN ProcessTerminated;\t\t// Whether or not the process has terminated.\n} PROCESS_SUMMARY_ENTRY, * PPROCESS_SUMMARY_ENTRY;\n\ntypedef struct StackReturnInfo\n{\n\tPVOID RawAddress;\t\t\t// The raw return address.\n\tBOOLEAN MemoryInModule;\t\t// Whether or not the address is in a loaded module.\n\tBOOLEAN ExecutableMemory;\t// Whether or not the address is in executable memory.\n\tWCHAR BinaryPath[MAX_PATH];\t// The path of the binary this return address specifies.\n\tULONG64 BinaryOffset;\t\t// The offset in the binary that the return address refers to.\n} STACK_RETURN_INFO, * PSTACK_RETURN_INFO;\n\ntypedef struct ProcessSummaryRequest\n{\n\tULONG SkipCount;\t\t\t\t\t\t\t// How many processes to skip.\n\tULONG ProcessHistorySize;\t\t\t\t\t// Size of the variable-length ProcessHistory array.\n\tPROCESS_SUMMARY_ENTRY ProcessHistory[1];\t// Variable-length array of process history summaries.\n} PROCESS_SUMMARY_REQUEST, *PPROCESS_SUMMARY_REQUEST;\n\n#define MAX_PROCESS_SUMMARY_REQUEST_SIZE_RAW(size) sizeof(PROCESS_SUMMARY_REQUEST) + (size - 1) * sizeof(PROCESS_SUMMARY_ENTRY)\n#define MAX_PROCESS_SUMMARY_REQUEST_SIZE(summaryRequest) MAX_PROCESS_SUMMARY_REQUEST_SIZE_RAW(summaryRequest->ProcessHistorySize)\n\ntypedef struct ImageSummary\n{\n\tWCHAR ImagePath[MAX_PATH];\t// The path to the image. Populated by the driver.\n\tULONG StackSize;\t\t\t// The size of the stack history.\n} IMAGE_SUMMARY, *PIMAGE_SUMMARY;\n\ntypedef struct ProcessDetailedRequest\n{\n\tHANDLE ProcessId;\t\t\t\t\t// The process id of the executed process.\n\tULONGLONG EpochExecutionTime;\t\t// Process execution time in seconds since 1970.\n\tBOOLEAN Populated;\t\t\t\t\t// Whether not this structure was populated (the process was found).\n\n\tWCHAR ProcessPath[MAX_PATH];\t\t// The image file name of the executed process.\n\n\tHANDLE CallerProcessId;\t\t\t\t// The process id of the caller process.\n\tWCHAR CallerProcessPath[MAX_PATH];\t// OPTIONAL: The image file name of the caller process.\n\n\tHANDLE ParentProcessId;\t\t\t\t// The process id of the alleged parent process.\n\tWCHAR ParentProcessPath[MAX_PATH];\t// OPTIONAL: The image file name of the alleged parent process.\n\n\tWCHAR ProcessCommandLine[MAX_PATH]; // The process command line.\n\n\tULONG ImageSummarySize;\t\t\t\t// The length of the ImageSummary array.\n\tPIMAGE_SUMMARY ImageSummary;\t\t// Variable-length array of image summaries.\n\n\tULONG StackHistorySize;\t\t\t\t// The length of the StackHistory array.\n\tPSTACK_RETURN_INFO StackHistory;\t// Variable-length array of stack history.\n} PROCESS_DETAILED_REQUEST, *PPROCESS_DETAILED_REQUEST;\n\ntypedef struct ImageDetailedRequest\n{\n\tHANDLE ProcessId;\t\t\t\t\t// The process id of the executed process.\n\tULONGLONG EpochExecutionTime;\t\t// Process execution time in seconds since 1970.\n\tBOOLEAN Populated;\t\t\t\t\t// Whether not this structure was populated (the image was found).\n\n\tULONG ImageIndex;\t\t\t\t\t// The index of the target image. Must not be larger than the process images list size.\n\tWCHAR ImagePath[MAX_PATH];\t\t\t// The path to the image. Populated by the driver.\n\tULONG StackHistorySize;\t\t\t\t// The length of the StackHistory array.\n\tSTACK_RETURN_INFO StackHistory[1];\t// Variable-length array of stack history. Populated by the driver.\n} IMAGE_DETAILED_REQUEST, *PIMAGE_DETAILED_REQUEST;\n\n#define MAX_IMAGE_DETAILED_REQUEST_SIZE_RAW(size) sizeof(IMAGE_DETAILED_REQUEST) + ((size - 1) * sizeof(STACK_RETURN_INFO))\n#define MAX_IMAGE_DETAILED_REQUEST_SIZE(detailedRequest) MAX_IMAGE_DETAILED_REQUEST_SIZE_RAW(detailedRequest->StackHistorySize)\n\ntypedef struct ProcessSizesRequest\n{\n\tHANDLE ProcessId;\t\t\t\t\t// The process id of the executed process.\n\tULONGLONG EpochExecutionTime;\t\t// Process execution time in seconds since 1970.\n\tULONG ProcessSize;\t\t\t\t\t// The number of loaded processes.\n\tULONG ImageSize;\t\t\t\t\t// The number of loaded images in the process.\n\tULONG StackSize;\t\t\t\t\t// The number of stack return entries in the stack history for the process.\n} PROCESS_SIZES_REQUEST, *PPROCESS_SIZES_REQUEST;\n\ntypedef enum FilterType\n{\n\tFilesystemFilter,\n\tRegistryFilter\n} STRING_FILTER_TYPE, *PSTRING_FILTER_TYPE;\n\n//\n// Bitwise flags used for filtering for specific filters.\n//\n#define FILTER_FLAG_DELETE 0x1\n#define FILTER_FLAG_WRITE 0x2\n#define FILTER_FLAG_EXECUTE 0x4\n\n#define FlagOn(_F,_SF) ((_F) & (_SF))\n\n#define FILTER_FLAG_ALL (FILTER_FLAG_DELETE | FILTER_FLAG_WRITE | FILTER_FLAG_EXECUTE)\n\ntypedef struct FilterInfo\n{\n\tULONG Id;\t\t\t\t\t\t// Unique ID of the filter used to remove entries.\n\tSTRING_FILTER_TYPE Type;\t\t// The general target of the filter (Filesystem/Registry).\n\tWCHAR MatchString[MAX_PATH];\t// The string to match against. Always lowercase.\n\tULONG MatchStringSize;\t\t\t// The length of the match string.\n\tULONG Flags;\t\t\t\t\t// Used by MatchesFilter to determine if should use filter. Caller specifies the filters they want via flag.\n} FILTER_INFO, *PFILTER_INFO;\n\ntypedef struct StringFilterRequest\n{\n\tSTRING_FILTER_TYPE FilterType;\t// The general target of the filter (Filesystem/Registry).\n\tFILTER_INFO Filter;\n} STRING_FILTER_REQUEST, * PSTRING_FILTER_REQUEST;\n\ntypedef struct ListFiltersRequest\n{\n\tSTRING_FILTER_TYPE FilterType;\t// The general target of the filter (Filesystem/Registry).\n\tULONG TotalFilters;\t\t\t\t// Populated by the IOCTL request. The number of total filters there really are.\n\tULONG SkipFilters;\t\t\t\t// Number of filters to skip.\n\tULONG CopiedFilters;\t\t\t// Populated by the IOCTL request. Number of filters actually copied.\n\tFILTER_INFO Filters[10];\t\t// You can request more than 10 filters via multiple requests.\n} LIST_FILTERS_REQUEST, *PLIST_FILTERS_REQUEST;\n\ntypedef enum AlertType\n{\n\tStackViolation,\n\tFilterViolation,\n\tParentProcessIdSpoofing,\n\tRemoteThreadCreation\n} ALERT_TYPE;\n\ntypedef enum DetectionSource\n{\n\tProcessCreate,\n\tImageLoad,\n\tRegistryFilterMatch,\n\tFileFilterMatch,\n\tThreadCreate\n} DETECTION_SOURCE;\n\ntypedef struct BaseAlertInfo\n{\n\tLIST_ENTRY Entry;\t\t\t\t// The LIST_ENTRY details.\n\tULONG AlertSize;\t\t\t\t// The size (in bytes) of the structure.\n\tDETECTION_SOURCE AlertSource;\t// The source of the alert.\n\tALERT_TYPE AlertType;\t\t\t// The type of alert.\n\tHANDLE SourceId;\t\t\t\t// The process id of the source of the alert.\n\tWCHAR SourcePath[MAX_PATH];\t\t// The path to the source.\n\tWCHAR TargetPath[MAX_PATH];\t\t// The path to the target.\n} BASE_ALERT_INFO, * PBASE_ALERT_INFO;\n\ntypedef struct StackViolationAlert\n{\n\tBASE_ALERT_INFO AlertInformation;\t// Basic alert information.\n\tPVOID ViolatingAddress;\t\t\t\t// The specific address that was detected out-of-bounds.\n\tULONG StackHistorySize;\t\t\t\t// The length of the StackHistory array.\n\tSTACK_RETURN_INFO StackHistory[1];\t// Variable-length array of stack history.\n} STACK_VIOLATION_ALERT, * PSTACK_VIOLATION_ALERT;\n\n//\n// How many bytes the user-mode caller must supply as its output buffer.\n//\n#define MAX_STACK_VIOLATION_ALERT_SIZE sizeof(STACK_VIOLATION_ALERT) + (MAX_STACK_RETURN_HISTORY-1) * sizeof(STACK_RETURN_INFO)\n\ntypedef struct FilterViolationAlert\n{\n\tBASE_ALERT_INFO AlertInformation;\t// Basic alert information.\n\tULONG StackHistorySize;\t\t\t\t// The length of the StackHistory array.\n\tSTACK_RETURN_INFO StackHistory[1];\t// Variable-length array of stack history.\n} FILTER_VIOLATION_ALERT, * PFILTER_VIOLATION_ALERT;\n\n//\n// How many bytes the user-mode caller must supply as its output buffer.\n//\n#define MAX_FILTER_VIOLATION_ALERT_SIZE sizeof(FILTER_VIOLATION_ALERT) + (MAX_STACK_RETURN_HISTORY-1) * sizeof(STACK_RETURN_INFO)\n\ntypedef struct RemoteOperationAlert\n{\n\tBASE_ALERT_INFO AlertInformation;\t// Basic alert information.\n\tHANDLE RemoteTargetId;\t\t\t\t// Process ID of the target process.\n\tULONG StackHistorySize;\t\t\t\t// The length of the StackHistory array.\n\tSTACK_RETURN_INFO StackHistory[1];\t// Variable-length array of stack history.\n} REMOTE_OPERATION_ALERT, *PREMOTE_OPERATION_ALERT;\n\n//\n// How many bytes the user-mode caller must supply as its output buffer.\n//\n#define MAX_REMOTE_OPERATION_ALERT_SIZE sizeof(REMOTE_OPERATION_ALERT) + (MAX_STACK_RETURN_HISTORY-1) * sizeof(STACK_RETURN_INFO)\n\ntypedef struct GlobalSizes\n{\n\tULONG64 ProcessHistorySize;\n\tULONG64 FilesystemFilterSize;\n\tULONG64 RegistryFilterSize;\n} GLOBAL_SIZES, *PGLOBAL_SIZES;\n\ntypedef struct DeleteFilterRequest\n{\n\tULONG FilterId;\t\t\t\t\t// Unique ID of the filter used to remove entries.\n\tSTRING_FILTER_TYPE FilterType;\t// The general target of the filter (Filesystem/Registry).\n\tBOOLEAN Deleted;\t\t\t\t// Whether or not the filter was deleted.\n} DELETE_FILTER_REQUEST, *PDELETE_FILTER_REQUEST;"
  },
  {
    "path": "PeaceMaker Kernel.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"PeaceMaker Kernel.rc\" />\n    <ClCompile Include=\"common.cpp\" />\n    <ClCompile Include=\"FSFilter.cpp\" />\n    <ClCompile Include=\"ImageHistoryFilter.cpp\" />\n    <ClCompile Include=\"RegistryFilter.cpp\" />\n    <ClCompile Include=\"StackWalker.cpp\" />\n    <ClCompile Include=\"StringFilters.cpp\" />\n    <ClCompile Include=\"FilterTesting.cpp\" />\n    <Inf Include=\"PeaceMaker Kernel.inf\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}</ProjectGuid>\n    <TemplateGuid>{f2f62967-0815-4fd7-9b86-6eedcac766eb}</TemplateGuid>\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\n    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>\n    <Configuration>Debug</Configuration>\n    <Platform Condition=\"'$(Platform)' == ''\">Win32</Platform>\n    <RootNamespace>PeaceMaker Kernel</RootNamespace>\n    <ProjectName>PeaceMaker Kernel</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\n    <ConfigurationType>Driver</ConfigurationType>\n    <DriverType>WDM</DriverType>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n    <PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <PostBuildEvent>\n      <Command>\"$(OutDir)signbinary.bat\" \"$(TargetPath)\"</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\n    <Link>\n      <AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <FilesToPackage Include=\"$(TargetPath)\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"common.h\" />\n    <ClInclude Include=\"FSFilter.h\" />\n    <ClInclude Include=\"ntdef.h\" />\n    <ClInclude Include=\"ImageHistoryFilter.h\" />\n    <ClInclude Include=\"RegistryFilter.h\" />\n    <ClInclude Include=\"StackWalker.h\" />\n    <ClInclude Include=\"StringFilters.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "PeaceMaker.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.29215.179\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"PeaceMaker Kernel\", \"PeaceMaker Kernel\\PeaceMaker Kernel.vcxproj\", \"{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"PeaceMaker CLI\", \"PeaceMaker CLI\\PeaceMaker CLI.vcxproj\", \"{A287D40E-AB7B-4FE9-AA84-44114766C79D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|ARM = Debug|ARM\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|ARM = Release|ARM\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|ARM.Deploy.0 = Debug|ARM\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|x64.Build.0 = Debug|x64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|x86.Build.0 = Debug|Win32\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Debug|x86.Deploy.0 = Debug|Win32\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|ARM.Build.0 = Release|ARM\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|ARM.Deploy.0 = Release|ARM\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|x64.ActiveCfg = Release|x64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|x64.Build.0 = Release|x64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|x64.Deploy.0 = Release|x64\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|x86.ActiveCfg = Release|Win32\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|x86.Build.0 = Release|Win32\n\t\t{5A9C319B-EDBD-4E53-BFEE-2FBD7BAE767F}.Release|x86.Deploy.0 = Release|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Debug|ARM.ActiveCfg = Debug|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Debug|ARM64.ActiveCfg = Debug|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Debug|x64.Build.0 = Debug|x64\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Debug|x86.Build.0 = Debug|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Release|ARM.ActiveCfg = Release|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Release|ARM64.ActiveCfg = Release|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Release|x64.ActiveCfg = Release|x64\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Release|x64.Build.0 = Release|x64\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Release|x86.ActiveCfg = Release|Win32\n\t\t{A287D40E-AB7B-4FE9-AA84-44114766C79D}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {479F6A46-1341-4A08-A813-8E0B2C36CFC9}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "PeaceMakerGUI/AssetResources.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>assets/PeaceMakerLogo.png</file>\n        <file>assets/AlertsTabActive.png</file>\n        <file>assets/AlertsTabInactive.png</file>\n        <file>assets/ConfigTabActive.png</file>\n        <file>assets/ConfigTabInactive.png</file>\n        <file>assets/FiltersTabActive.png</file>\n        <file>assets/FiltersTabInactive.png</file>\n        <file>assets/ProcessesTabActive.png</file>\n        <file>assets/ProcessesTabInactive.png</file>\n        <file>assets/Copyright.png</file>\n        <file>assets/PeaceMakerIcon.ico</file>\n        <file>assets/BasicProcessInformation.png</file>\n        <file>assets/CreatorStackHistory.png</file>\n        <file>assets/Images.png</file>\n        <file>assets/ImageStackHistory.png</file>\n        <file>assets/Search.png</file>\n        <file>assets/AlertDetails.png</file>\n        <file>assets/AlertStackHistory.png</file>\n        <file>assets/FilterContent.png</file>\n        <file>assets/FilterFlags.png</file>\n        <file>assets/FilterType.png</file>\n        <file>assets/PendingAlertsTab.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "PeaceMakerGUI/ClickableTab.cpp",
    "content": "#include \"ClickableTab.h\"\n#include \"mainwindow.h\"\n\nClickableTab::ClickableTab(QWidget* parent, Qt::WindowFlags f)\n    : QLabel(parent) {\n    std::string parentName;\n    QWidget* currentParent;\n\n    //\n    // Find the MainWindow.\n    //\n    currentParent = parent;\n    do\n    {\n        currentParent = currentParent->parentWidget();\n        parentName = currentParent->objectName().toStdString();\n    } while(parentName != \"MainWindow\");\n\n    this->mainWindow = currentParent;\n\n    this->tabActive = false;\n}\n\nClickableTab::~ClickableTab() {}\n\n/**\n * @brief ClickableTab::SwapActiveState - Swap the \"state\" of the tab. If was clicked, remove underline, otherwise add underline.\n */\nvoid ClickableTab::SwapActiveState()\n{\n    int statusPosition;\n    std::string currentTabContent;\n    //\n    // These values are what we look for in the tab HTML to replace.\n    //\n    const std::string activeName = \"Active\";\n    const std::string inactiveName = \"Inactive\";\n\n    //\n    // Get the current tab content.\n    //\n    currentTabContent = this->text().toStdString();\n    if(customText)\n    {\n        currentTabContent = oldText.toStdString();\n        customText = false;\n    }\n    //\n    // Replace the active state depending on whether it was already active.\n    //\n    if(this->tabActive)\n    {\n        statusPosition = currentTabContent.find(activeName);\n        currentTabContent.replace(statusPosition, activeName.length(), inactiveName);\n        this->tabActive = false;\n        for(QWidget* widget : this->associatedElements)\n        {\n            widget->setVisible(false);\n        }\n    }\n    else\n    {\n        statusPosition = currentTabContent.find(inactiveName);\n        currentTabContent.replace(statusPosition, inactiveName.length(), activeName);\n        this->tabActive = true;\n        for(QWidget* widget : this->associatedElements)\n        {\n            widget->setVisible(true);\n        }\n    }\n\n    //\n    // Set this new text.\n    //\n    this->setText(QString::fromStdString(currentTabContent));\n}\n\n/**\n * @brief ClickableTab::AddAssociatedElement - Track associated widgets to hide/show on state changes.\n * @param widget - The widget associated with this tab.\n */\nvoid ClickableTab::AddAssociatedElement(QWidget *widget)\n{\n    this->associatedElements.push_back(widget);\n\n    //\n    // By default, widgets should be hidden.\n    //\n    widget->setVisible(false);\n}\n\n/**\n * @brief ClickableTab::SetCustomText - Set custom text for the tab, but store the previous text.\n * @param newText - The new custom text to set.\n */\nvoid ClickableTab::SetCustomText(QString newText)\n{\n    if(customText == false)\n    {\n        oldText = this->text();\n        this->setText(newText);\n        customText = true;\n    }\n}\n\n/**\n * @brief ClickableTab::mousePressEvent notifies the main window of a tab being clicked.\n * @param event - Details about the click event.\n */\nvoid ClickableTab::mousePressEvent(QMouseEvent* event) {\n    ((MainWindow*)this->mainWindow)->NotifyTabClick(this);\n}\n"
  },
  {
    "path": "PeaceMakerGUI/ClickableTab.h",
    "content": "#ifndef CLICKABLETAB_H\n#define CLICKABLETAB_H\n\n#include <QLabel>\n#include <QWidget>\n#include <Qt>\n#include <vector>\n\n//\n// These tab types allow the MainWindow to know what was clicked.\n//\nenum TabType\n{\n    AlertsTab,\n    ProcessesTab,\n    FiltersTab,\n    ConfigTab\n};\n\nclass ClickableTab : public QLabel {\n    Q_OBJECT\n    QWidget* mainWindow;\n    bool tabActive;\n    std::vector<QWidget*> associatedElements;\n    QString oldText;\n    bool customText = false;\n\npublic:\n    explicit ClickableTab(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());\n    ~ClickableTab();\n\n    void SwapActiveState();\n    void AddAssociatedElement(QWidget* widget);\n    void SetCustomText(QString newText);\nsignals:\n    void clicked();\n\nprotected:\n    void mousePressEvent(QMouseEvent* event);\n\n};\n\n#endif // CLICKABLETAB_H\n"
  },
  {
    "path": "PeaceMakerGUI/InvestigateProcessWindow.cpp",
    "content": "#include \"InvestigateProcessWindow.h\"\n#include \"ui_InvestigateProcessWindow.h\"\n\n/**\n * @brief InvestigateProcessWindow::InitializeCommonTable - Common initialization across all tables.\n * @param table\n */\nvoid InvestigateProcessWindow::InitializeCommonTable(QTableWidget *table)\n{\n    //\n    // Set properties that are common across tables.\n    //\n    table->horizontalHeader()->setStretchLastSection(true);\n    table->horizontalHeader()->setHighlightSections(false);\n    table->verticalHeader()->setVisible(false);\n    table->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    table->setSelectionBehavior(QAbstractItemView::SelectRows);\n    table->setSelectionMode(QAbstractItemView::SingleSelection);\n    table->verticalScrollBar()->setStyleSheet(\"color: white;\");\n    table->setSortingEnabled(false);\n    table->setStyleSheet(\"background: white;\");\n    table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);\n    table->verticalHeader()->setDefaultSectionSize(10);\n}\n\n/**\n * @brief InvestigateProcessWindow::InitializeProcessInfoTable - Initialize properties for the process info table.\n */\nvoid InvestigateProcessWindow::InitializeProcessInfoTable()\n{\n    this->ui->ProcessInformationTable->setColumnCount(2);\n    this->ProcessInfoTableSize = 0;\n\n    AddProcessInfoItem(\"Process Id\");\n    AddProcessInfoItem(\"Path\");\n    AddProcessInfoItem(\"Command Line\");\n    AddProcessInfoItem(\"Execution Time\");\n    AddProcessInfoItem(\"Caller Process Id\");\n    //AddProcessInfoItem(\"Caller Path\");\n    AddProcessInfoItem(\"Parent Process Id\");\n    AddProcessInfoItem(\"Parent Path\");\n\n    this->ui->ProcessInformationTable->horizontalHeader()->hide();\n    this->ui->ProcessInformationTable->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);\n    InitializeCommonTable(this->ui->ProcessInformationTable);\n}\n\n/**\n * @brief InvestigateProcessWindow::InitializeStackHistoryTable - Initialize properties for the stack history table.\n * @param historyTable - The stack history table to modify.\n */\nvoid InvestigateProcessWindow::InitializeStackHistoryTable(QTableWidget* historyTable)\n{\n    QStringList headers;\n\n    historyTable->setColumnCount(1);\n    InitializeCommonTable(historyTable);\n\n    headers << \"Stack Return Address\";\n    historyTable->setHorizontalHeaderLabels(headers);\n    historyTable->setColumnWidth(0, 300);\n    historyTable->setWordWrap(true);\n}\n\n/**\n * @brief InvestigateProcessWindow::InitializeProcessImagesTable - Initialize properties for the process images table.\n */\nvoid InvestigateProcessWindow::InitializeProcessImagesTable()\n{\n    InitializeCommonTable(this->ui->ImagesTable);\n\n    this->ui->ImagesTable->setColumnCount(1);\n    this->ui->ImagesTable->setColumnWidth(0, 400);\n\n    this->ui->ImagesTable->horizontalHeader()->hide();\n    this->ui->ImagesTable->setWordWrap(true);\n}\n\n/**\n * @brief InvestigateProcessWindow::AddProcessInfoItem - Add a header item to the process info table.\n * @param HeaderName - Header name.\n */\nvoid InvestigateProcessWindow::AddProcessInfoItem(std::string HeaderName)\n{\n    this->ui->ProcessInformationTable->setRowCount(this->ProcessInfoTableSize + 1);\n    this->ui->ProcessInformationTable->setItem(this->ProcessInfoTableSize, 0, new QTableWidgetItem(QString::fromStdString(HeaderName)));\n    this->ProcessInfoTableSize++;\n}\n\n/**\n * @brief InvestigateProcessWindow::UpdateWidget - Refresh stylesheet (Qt bug).\n * @param widget - Widget to update.\n */\nvoid InvestigateProcessWindow::UpdateWidget(QWidget *widget)\n{\n    widget->style()->unpolish(widget);\n    widget->style()->polish(widget);\n    QEvent event(QEvent::StyleChange);\n    QApplication::sendEvent(widget, &event);\n    widget->update();\n    widget->updateGeometry();\n}\n\nInvestigateProcessWindow::InvestigateProcessWindow(QWidget *parent) :\n    QWidget(parent),\n    ui(new Ui::InvestigateProcessWindow)\n{\n    ui->setupUi(this);\n\n    this->setFixedSize(QSize(930, 400));\n\n    InitializeProcessInfoTable();\n    InitializeStackHistoryTable(this->ui->ProcessStackHistoryTable);\n    InitializeProcessImagesTable();\n    InitializeStackHistoryTable(this->ui->ImageStackHistoryTable);\n}\n\nInvestigateProcessWindow::~InvestigateProcessWindow()\n{\n    delete ui;\n}\n\n/**\n * @brief InvestigateProcessWindow::UpdateNewProcess - Set the investigator to display another process.\n * @param detailedProcessInformation - The new process to display.\n */\nvoid InvestigateProcessWindow::UpdateNewProcess(PROCESS_DETAILED_REQUEST detailedProcessInformation)\n{\n    std::time_t processExecutionDate;\n    std::string dateString;\n    ULONG i;\n    CHAR tempBuffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];\n    PSYMBOL_INFO currentSymbolInformation;\n    ULONG64 offset;\n    QString stackHistoryString;\n    QString tooltip;\n    QTableWidgetItem* newWidget;\n    bool stackHistoryViolation;\n\n    memset(tempBuffer, 0, sizeof(tempBuffer));\n    currentSymbolInformation = RCAST<PSYMBOL_INFO>(tempBuffer);\n    currentSymbolInformation->SizeOfStruct = sizeof(SYMBOL_INFO);\n    currentSymbolInformation->MaxNameLen = MAX_SYM_NAME;\n\n    //\n    // First, we need to convert the epoch time to a date.\n    //\n    processExecutionDate = detailedProcessInformation.EpochExecutionTime;\n    dateString = std::ctime(&processExecutionDate);\n    dateString[dateString.length()-1] = '\\0'; // Remove the newline.\n\n    this->ProcessId = detailedProcessInformation.ProcessId;\n    this->EpochExecutionTime = detailedProcessInformation.EpochExecutionTime;\n\n    //\n    // Copy basic process information.\n    //\n    this->ui->ProcessInformationTable->setItem(0, 1, new QTableWidgetItem(QString::number(RCAST<ULONG64>(detailedProcessInformation.ProcessId))));\n\n    newWidget = new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.ProcessPath));\n    newWidget->setToolTip(QString::fromWCharArray(detailedProcessInformation.ProcessPath));\n    this->ui->ProcessInformationTable->setItem(1, 1, newWidget);\n\n    newWidget = new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.ProcessCommandLine));\n    newWidget->setToolTip(QString::fromWCharArray(detailedProcessInformation.ProcessCommandLine));\n    this->ui->ProcessInformationTable->setItem(2, 1, newWidget);\n\n    this->ui->ProcessInformationTable->setItem(3, 1, new QTableWidgetItem(QString::fromStdString(dateString)));\n    this->ui->ProcessInformationTable->resizeRowsToContents();\n\n    this->ui->ProcessInformationTable->setItem(4, 1, new QTableWidgetItem(QString::number(RCAST<ULONG64>(detailedProcessInformation.CallerProcessId))));\n\n    //newWidget = new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.CallerProcessPath));\n    //newWidget->setToolTip(QString::fromWCharArray(detailedProcessInformation.CallerProcessPath));\n    //this->ui->ProcessInformationTable->setItem(5, 1, new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.CallerProcessPath)));\n\n    this->ui->ProcessInformationTable->setItem(5, 1, new QTableWidgetItem(QString::number(RCAST<ULONG64>(detailedProcessInformation.ParentProcessId))));\n\n    newWidget = new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.ParentProcessPath));\n    newWidget->setToolTip(QString::fromWCharArray(detailedProcessInformation.ParentProcessPath));\n    this->ui->ProcessInformationTable->setItem(6, 1, new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.ParentProcessPath)));\n\n    this->ui->ProcessInformationTable->resizeRowsToContents();\n\n    //\n    // Fix sizing.\n    //\n    this->ui->ProcessInformationTable->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);\n    this->ui->ProcessInformationTable->verticalHeader()->setDefaultSectionSize(10);\n\n    //\n    // Copy the stack history.\n    //\n    this->ui->ProcessStackHistoryTable->setRowCount(detailedProcessInformation.StackHistorySize);\n    for(i = 0; i < detailedProcessInformation.StackHistorySize; i++)\n    {\n        stackHistoryString = \"\";\n        stackHistoryViolation = false;\n        //\n        // First, try a symbol lookup.\n        //\n        if(SymFromAddr(GetCurrentProcess(), RCAST<DWORD64>(detailedProcessInformation.StackHistory[i].RawAddress), &offset, currentSymbolInformation))\n        {\n            stackHistoryString = stackHistoryString.sprintf(\"%s+0x%llx\", currentSymbolInformation->Name, offset);\n            tooltip = tooltip.sprintf(\"%ls+0x%llx\", detailedProcessInformation.StackHistory[i].BinaryPath, detailedProcessInformation.StackHistory[i].BinaryOffset);\n        }\n        else\n        {\n            printf(\"Failed SymFromAddr %i.\\n\", GetLastError());\n\n            if(wcslen(detailedProcessInformation.StackHistory[i].BinaryPath) == 0)\n            {\n                stackHistoryString = stackHistoryString.sprintf(\"0x%llx\", detailedProcessInformation.StackHistory[i].RawAddress);\n                stackHistoryViolation = true;\n            }\n            else\n            {\n                stackHistoryString = stackHistoryString.sprintf(\"%ls+0x%llx\", detailedProcessInformation.StackHistory[i].BinaryPath, detailedProcessInformation.StackHistory[i].BinaryOffset);\n            }\n            tooltip = stackHistoryString;\n        }\n\n        this->ui->ProcessStackHistoryTable->setRowCount(i + 1);\n        newWidget = new QTableWidgetItem(stackHistoryString);\n        newWidget->setToolTip(tooltip);\n        if(stackHistoryViolation)\n        {\n            newWidget->setBackground(Qt::red);\n        }\n        this->ui->ProcessStackHistoryTable->setItem(i, 0, newWidget);\n        this->ui->ProcessStackHistoryTable->resizeRowsToContents();\n    }\n\n    //\n    // Copy the images.\n    //\n    this->images.clear();\n    for(i = 0; i < detailedProcessInformation.ImageSummarySize; i++)\n    {\n        this->images.push_back(detailedProcessInformation.ImageSummary[i]);\n        this->ui->ImagesTable->setRowCount(i + 1);\n        newWidget = new QTableWidgetItem(QString::fromWCharArray(detailedProcessInformation.ImageSummary[i].ImagePath));\n        newWidget->setToolTip(QString::fromWCharArray(detailedProcessInformation.ImageSummary[i].ImagePath));\n        this->ui->ImagesTable->setItem(i, 0, newWidget);\n        this->ui->ImagesTable->resizeRowsToContents();\n    }\n\n    this->ui->ImagesTable->selectRow(0);\n\n    //\n    // By default, first image is picked.\n    //\n    this->on_ImagesTable_cellClicked(0, 0);\n}\n\n/**\n * @brief InvestigateProcessWindow::RefreshWidgets - Update the standard tables.\n */\nvoid InvestigateProcessWindow::RefreshWidgets()\n{\n    UpdateWidget(this->ui->ProcessInformationTable);\n    UpdateWidget(this->ui->ProcessStackHistoryTable);\n    UpdateWidget(this->ui->ImagesTable);\n    UpdateWidget(this->ui->ImageStackHistoryTable);\n    UpdateWidget(this);\n    this->setStyleSheet(\"background-color: #404040;\");\n}\n\n/**\n * @brief InvestigateProcessWindow::on_ImagesTable_cellClicked - Grab the stack for the new image.\n * @param row - Row of the image selected.\n * @param column - Column of the image selected.\n */\nvoid InvestigateProcessWindow::on_ImagesTable_cellClicked(int row, int column)\n{\n    IMAGE_SUMMARY image;\n    PIMAGE_DETAILED_REQUEST imageDetailed;\n    ULONG i;\n    QString stackHistoryString;\n    QString tooltip;\n    CHAR tempBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME];\n    PIMAGEHLP_SYMBOL64 currentSymbolInformation;\n    ULONG64 offset;\n    QTableWidgetItem* newWidget;\n    bool stackHistoryViolation;\n\n    memset(tempBuffer, 0, sizeof(tempBuffer));\n    currentSymbolInformation = RCAST<PIMAGEHLP_SYMBOL64>(tempBuffer);\n    currentSymbolInformation->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);\n    currentSymbolInformation->MaxNameLength = MAX_SYM_NAME;\n\n    image = images[row];\n    imageDetailed = communicator->RequestDetailedImage(this->ProcessId, this->EpochExecutionTime, row, image.StackSize);\n    if (imageDetailed == NULL || imageDetailed->Populated == FALSE)\n    {\n        return;\n    }\n\n    //\n    // Copy the stack history.\n    //\n    this->ui->ImageStackHistoryTable->setRowCount(imageDetailed->StackHistorySize);\n    for(i = 0; i < imageDetailed->StackHistorySize; i++)\n    {\n        stackHistoryViolation = false;\n        //\n        // First, try a symbol lookup.\n        //\n        if(SymGetSymFromAddr64(GetCurrentProcess(), RCAST<DWORD64>(imageDetailed->StackHistory[i].RawAddress), &offset, currentSymbolInformation))\n        {\n            stackHistoryString = stackHistoryString.sprintf(\"%s+0x%llx\", currentSymbolInformation->Name, offset);\n            tooltip = tooltip.sprintf(\"%ls+0x%llx\", imageDetailed->StackHistory[i].BinaryPath, imageDetailed->StackHistory[i].BinaryOffset);\n        }\n        else\n        {\n            if(wcslen(imageDetailed->StackHistory[i].BinaryPath) == 0)\n            {\n                stackHistoryString = stackHistoryString.sprintf(\"0x%llx\", imageDetailed->StackHistory[i].RawAddress);\n                stackHistoryViolation = true;\n            }\n            else\n            {\n                stackHistoryString = stackHistoryString.sprintf(\"%ls+0x%llx\", imageDetailed->StackHistory[i].BinaryPath, imageDetailed->StackHistory[i].BinaryOffset);\n            }\n\n            tooltip = stackHistoryString;\n        }\n\n        this->ui->ImageStackHistoryTable->setRowCount(i + 1);\n        newWidget = new QTableWidgetItem(stackHistoryString);\n\n        //\n        // Always set the tooltip to the expanded version.\n        //\n        newWidget->setToolTip(tooltip);\n        if(stackHistoryViolation)\n        {\n            newWidget->setBackground(Qt::red);\n        }\n        this->ui->ImageStackHistoryTable->setItem(i, 0, newWidget);\n        this->ui->ImageStackHistoryTable->resizeRowsToContents();\n    }\n\n    free(imageDetailed);\n}\n"
  },
  {
    "path": "PeaceMakerGUI/InvestigateProcessWindow.h",
    "content": "#ifndef INVESTIGATEPROCESSWINDOW_H\n#define INVESTIGATEPROCESSWINDOW_H\n\n#include <QWidget>\n#include <QTableWidget>\n#include <QScrollBar>\n\n#include <Windows.h>\n#include <DbgHelp.h>\n#include <string>\n#include <sstream>\n#include <vector>\n#include \"shared.h\"\n#include \"IOCTLCommunicationUser.h\"\n\nnamespace Ui {\nclass InvestigateProcessWindow;\n}\n\nclass InvestigateProcessWindow : public QWidget\n{\n    Q_OBJECT\n\n    void InitializeCommonTable(QTableWidget* table);\n\n    void InitializeProcessInfoTable();\n    void InitializeStackHistoryTable(QTableWidget* historyTable);\n    void InitializeProcessImagesTable();\n\n    void AddProcessInfoItem(std::string HeaderName);\n\n    HANDLE ProcessId;\n    ULONG64 EpochExecutionTime;\n\n    int ProcessInfoTableSize;\n\n    std::vector<IMAGE_SUMMARY> images;\n\n    void UpdateWidget(QWidget* widget);\n\npublic:\n    explicit InvestigateProcessWindow(QWidget *parent = nullptr);\n    ~InvestigateProcessWindow();\n\n    void UpdateNewProcess(PROCESS_DETAILED_REQUEST detailedProcessInformation);\n\n    void RefreshWidgets();\n\n    IOCTLCommunication* communicator;\nprivate slots:\n    void on_ImagesTable_cellClicked(int row, int column);\n\nprivate:\n    Ui::InvestigateProcessWindow *ui;\n};\n\n#endif // INVESTIGATEPROCESSWINDOW_H\n"
  },
  {
    "path": "PeaceMakerGUI/InvestigateProcessWindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>InvestigateProcessWindow</class>\n <widget class=\"QWidget\" name=\"InvestigateProcessWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>930</width>\n    <height>400</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Process Investigator</string>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"AssetResources.qrc\">\n    <normaloff>:/assets/PeaceMakerIcon.ico</normaloff>:/assets/PeaceMakerIcon.ico</iconset>\n  </property>\n  <property name=\"styleSheet\">\n   <string notr=\"true\">background-color: #404040;</string>\n  </property>\n  <widget class=\"QTableWidget\" name=\"ProcessInformationTable\">\n   <property name=\"geometry\">\n    <rect>\n     <x>20</x>\n     <y>30</y>\n     <width>440</width>\n     <height>160</height>\n    </rect>\n   </property>\n   <property name=\"sizePolicy\">\n    <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Expanding\">\n     <horstretch>0</horstretch>\n     <verstretch>20</verstretch>\n    </sizepolicy>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QTableWidget\" name=\"ProcessStackHistoryTable\">\n   <property name=\"geometry\">\n    <rect>\n     <x>20</x>\n     <y>220</y>\n     <width>440</width>\n     <height>160</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"BasicProcessInformationLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>150</x>\n     <y>10</y>\n     <width>179</width>\n     <height>17</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>12</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color:white;</string>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/BasicProcessInformation.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"CreatorStackHistoryLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>160</x>\n     <y>200</y>\n     <width>148</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>12</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color:white;</string>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/CreatorStackHistory.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"ImagesLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>660</x>\n     <y>10</y>\n     <width>50</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>12</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color:white;</string>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/Images.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"ImageStackHistoryLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>620</x>\n     <y>200</y>\n     <width>138</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>12</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color:white;</string>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/ImageStackHistory.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QTableWidget\" name=\"ImagesTable\">\n   <property name=\"geometry\">\n    <rect>\n     <x>470</x>\n     <y>30</y>\n     <width>440</width>\n     <height>160</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QTableWidget\" name=\"ImageStackHistoryTable\">\n   <property name=\"geometry\">\n    <rect>\n     <x>470</x>\n     <y>220</y>\n     <width>440</width>\n     <height>160</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background: white;</string>\n   </property>\n  </widget>\n </widget>\n <resources>\n  <include location=\"AssetResources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "PeaceMakerGUI/PeaceMakerGUI.pro",
    "content": "QT       += core gui\n\ngreaterThan(QT_MAJOR_VERSION, 4): QT += widgets\n\nCONFIG += c++11\n\n# The following define makes your compiler emit warnings if you use\n# any Qt feature that has been marked deprecated (the exact warnings\n# depend on your compiler). Please consult the documentation of the\n# deprecated API in order to know how to port your code away from it.\nDEFINES += QT_DEPRECATED_WARNINGS\n\n# You can also make your code fail to compile if it uses deprecated APIs.\n# In order to do so, uncomment the following line.\n# You can also select to disable deprecated APIs only up to a certain version of Qt.\n#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0\n\nSOURCES += \\\n    ClickableTab.cpp \\\n    InvestigateProcessWindow.cpp \\\n    addfilterwindow.cpp \\\n    configparser.cpp \\\n    detailedalertwindow.cpp \\\n    main.cpp \\\n    mainwindow.cpp\n\nHEADERS += \\\n    ClickableTab.h \\\n    InvestigateProcessWindow.h \\\n    addfilterwindow.h \\\n    configparser.h \\\n    detailedalertwindow.h \\\n    mainwindow.h\n\nFORMS += \\\n    InvestigateProcessWindow.ui \\\n    addfilterwindow.ui \\\n    detailedalertwindow.ui \\\n    mainwindow.ui\n\n# Default rules for deployment.\nqnx: target.path = /tmp/$${TARGET}/bin\nelse: unix:!android: target.path = /opt/$${TARGET}/bin\n!isEmpty(target.path): INSTALLS += target\n\nRESOURCES += \\\n    AssetResources.qrc\n\nINCLUDEPATH += \"../PeaceMaker Kernel\" \\\n                \"../PeaceMaker CLI\"\n\nSOURCES += \"../PeaceMaker CLI/IOCTLCommunicationUser.cpp\"\n\nLIBS += -limagehlp\n"
  },
  {
    "path": "PeaceMakerGUI/addfilterwindow.cpp",
    "content": "#include \"addfilterwindow.h\"\n#include \"ui_addfilterwindow.h\"\n\nAddFilterWindow::AddFilterWindow(QWidget *parent) :\n    QWidget(parent),\n    ui(new Ui::AddFilterWindow)\n{\n    ui->setupUi(this);\n    this->setFixedSize(QSize(300, 240));\n\n    //\n    // Add the different types of filter.\n    //\n    this->ui->FilterTypeBox->addItem(\"Filesystem Filter\");\n    this->ui->FilterTypeBox->addItem(\"Registry Filter\");\n}\n\nAddFilterWindow::~AddFilterWindow()\n{\n    delete ui;\n}\n\n/**\n * @brief AddFilterWindow::ClearStates - Clear previously entered input.\n */\nvoid AddFilterWindow::ClearStates()\n{\n    this->ui->FilterTypeBox->setCurrentIndex(0);\n    this->ui->FilterContent->setText(\"\");\n    this->ui->DeleteFlag->setChecked(false);\n    this->ui->WriteFlag->setChecked(false);\n    this->ui->ExecuteFlag->setChecked(false);\n}\n\n/**\n * @brief AddFilterWindow::on_pushButton_clicked - Handle the \"Add Filter\" button and actually add the filter.\n */\nvoid AddFilterWindow::on_pushButton_clicked()\n{\n    STRING_FILTER_TYPE filterType;\n    std::wstring filterContent;\n    ULONG filterFlags;\n\n    filterFlags = 0;\n\n    switch(this->ui->FilterTypeBox->currentIndex())\n    {\n    case 0:\n        filterType = FilesystemFilter;\n        break;\n    case 1:\n        filterType = RegistryFilter;\n        break;\n    }\n\n    filterContent = this->ui->FilterContent->text().toStdWString();\n\n    if(this->ui->DeleteFlag->isChecked())\n    {\n        filterFlags |= FILTER_FLAG_DELETE;\n    }\n    if(this->ui->WriteFlag->isChecked())\n    {\n        filterFlags |= FILTER_FLAG_WRITE;\n    }\n    if(this->ui->ExecuteFlag->isChecked())\n    {\n        filterFlags |= FILTER_FLAG_EXECUTE;\n    }\n\n    communicator->AddFilter(filterType, filterFlags, CCAST<PWCHAR>(filterContent.c_str()), filterContent.length() + 1);\n    this->hide();\n}\n"
  },
  {
    "path": "PeaceMakerGUI/addfilterwindow.h",
    "content": "#ifndef ADDFILTERWINDOW_H\n#define ADDFILTERWINDOW_H\n\n#include <QWidget>\n\n#include <string>\n#include \"shared.h\"\n#include \"IOCTLCommunicationUser.h\"\n\nnamespace Ui {\nclass AddFilterWindow;\n}\n\nclass AddFilterWindow : public QWidget\n{\n    Q_OBJECT\n\npublic:\n    explicit AddFilterWindow(QWidget *parent = nullptr);\n    ~AddFilterWindow();\n\n    void ClearStates();\n\n    IOCTLCommunication* communicator;\nprivate slots:\n    void on_pushButton_clicked();\n\nprivate:\n    Ui::AddFilterWindow *ui;\n};\n\n#endif // ADDFILTERWINDOW_H\n"
  },
  {
    "path": "PeaceMakerGUI/addfilterwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>AddFilterWindow</class>\n <widget class=\"QWidget\" name=\"AddFilterWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>300</width>\n    <height>240</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Add Filter</string>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"AssetResources.qrc\">\n    <normaloff>:/assets/PeaceMakerIcon.ico</normaloff>:/assets/PeaceMakerIcon.ico</iconset>\n  </property>\n  <property name=\"styleSheet\">\n   <string notr=\"true\">background-color: #404040;</string>\n  </property>\n  <widget class=\"QLineEdit\" name=\"FilterContent\">\n   <property name=\"geometry\">\n    <rect>\n     <x>30</x>\n     <y>100</y>\n     <width>241</width>\n     <height>20</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background-color: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QComboBox\" name=\"FilterTypeBox\">\n   <property name=\"geometry\">\n    <rect>\n     <x>30</x>\n     <y>40</y>\n     <width>241</width>\n     <height>22</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background-color: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QCheckBox\" name=\"DeleteFlag\">\n   <property name=\"geometry\">\n    <rect>\n     <x>50</x>\n     <y>160</y>\n     <width>65</width>\n     <height>18</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>10</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color: white;</string>\n   </property>\n   <property name=\"text\">\n    <string>Delete</string>\n   </property>\n  </widget>\n  <widget class=\"QCheckBox\" name=\"WriteFlag\">\n   <property name=\"geometry\">\n    <rect>\n     <x>120</x>\n     <y>160</y>\n     <width>61</width>\n     <height>18</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>10</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color: white;</string>\n   </property>\n   <property name=\"text\">\n    <string>Write</string>\n   </property>\n  </widget>\n  <widget class=\"QCheckBox\" name=\"ExecuteFlag\">\n   <property name=\"geometry\">\n    <rect>\n     <x>180</x>\n     <y>160</y>\n     <width>70</width>\n     <height>18</height>\n    </rect>\n   </property>\n   <property name=\"font\">\n    <font>\n     <pointsize>10</pointsize>\n     <weight>75</weight>\n     <bold>true</bold>\n    </font>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">color: white;</string>\n   </property>\n   <property name=\"text\">\n    <string>Execute</string>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"pushButton\">\n   <property name=\"geometry\">\n    <rect>\n     <x>30</x>\n     <y>200</y>\n     <width>241</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background-color: white;</string>\n   </property>\n   <property name=\"text\">\n    <string>Add Filter</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"FilterTypeLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>115</x>\n     <y>15</y>\n     <width>71</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/FilterType.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"FilterContentLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>105</x>\n     <y>80</y>\n     <width>94</width>\n     <height>17</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/FilterContent.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"FilterFlagsLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>110</x>\n     <y>140</y>\n     <width>78</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/FilterFlags.png&quot;/&gt;</string>\n   </property>\n  </widget>\n </widget>\n <resources>\n  <include location=\"AssetResources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "PeaceMakerGUI/configparser.cpp",
    "content": "#include \"configparser.h\"\n\n/**\n * @brief ConfigParser::ConfigParser - Read the config file.\n * @param ConfigFile - The config file to parse.\n */\nConfigParser::ConfigParser(std::string ConfigFile)\n{\n    std::ifstream configFile(ConfigFile);\n    std::string currentLine;\n\n    size_t findIndex;\n    std::string currentPropertyName;\n    std::string currentPropertyValue;\n\n    if(configFile.is_open() == FALSE)\n    {\n        printf(\"Failed to open config file.\");\n        return;\n    }\n\n    while(std::getline(configFile, currentLine))\n    {\n        //\n        // Check if the current line is a comment.\n        //\n        if(currentLine[0] == '#')\n        {\n            continue;\n        }\n        //\n        // Check if there is anything on the current line.\n        //\n        if(currentLine.length() == 0)\n        {\n            continue;\n        }\n\n        findIndex = currentLine.find(\"=\");\n        currentPropertyName = currentLine.substr(0, findIndex);\n        currentPropertyValue = currentLine.substr(findIndex + 1);\n        configMap[currentPropertyName] = currentPropertyValue;\n    }\n}\n\n/**\n * @brief ConfigParser::GetConfigFalsePositives - Parse false positive strings from the config.\n * @return False positives.\n */\nFALSE_POSITIVES ConfigParser::GetConfigFalsePositives()\n{\n    FALSE_POSITIVES falsePositives;\n    std::string currentCommaItem;\n    std::stringstream falsePositiveStream;\n    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;\n\n    //\n    // Check if there is anything for us to parse.\n    //\n    if(configMap.count(\"false_positive_sourcepath\") == 0)\n    {\n        printf(\"ConfigParser!GetConfigFalsePositives: No source path false positives to parse.\\n\");\n    }\n    if(configMap.count(\"false_positive_targetpath\") == 0)\n    {\n        printf(\"ConfigParser!GetConfigFalsePositives: No target path false positives to parse.\\n\");\n    }\n    if(configMap.count(\"false_positive_stackhistory\") == 0)\n    {\n        printf(\"ConfigParser!GetConfigFalsePositives: No stack history false positives to parse.\\n\");\n    }\n\n    if(configMap.count(\"false_positive_sourcepath\") != 0)\n    {\n        falsePositiveStream = std::stringstream(configMap[\"false_positive_sourcepath\"]);\n        //\n        // Enumerate source path false positives.\n        //\n        while(falsePositiveStream.good())\n        {\n            std::getline(falsePositiveStream, currentCommaItem, ',');\n            if(configMap.count(currentCommaItem) == 0)\n            {\n                printf(\"ConfigParser!GetConfigFalsePositives: false_positive_sourcepath had invalid false positive named %s.\\n\", currentCommaItem.c_str());\n                continue;\n            }\n            falsePositives.SourcePathFilter.push_back(converter.from_bytes(configMap[currentCommaItem]));\n        }\n    }\n\n    if(configMap.count(\"false_positive_targetpath\") != 0)\n    {\n        falsePositiveStream = std::stringstream(configMap[\"false_positive_targetpath\"]);\n        //\n        // Enumerate target path false positives.\n        //\n        while(falsePositiveStream.good())\n        {\n            std::getline(falsePositiveStream, currentCommaItem, ',');\n            if(configMap.count(currentCommaItem) == 0)\n            {\n                printf(\"ConfigParser!GetConfigFalsePositives: false_positive_targetpath had invalid false positive named %s.\\n\", currentCommaItem.c_str());\n                continue;\n            }\n            falsePositives.TargetPathFilter.push_back(converter.from_bytes(configMap[currentCommaItem]));\n        }\n    }\n\n    if(configMap.count(\"false_positive_stackhistory\") != 0)\n    {\n        falsePositiveStream = std::stringstream(configMap[\"false_positive_stackhistory\"]);\n        //\n        // Enumerate source path false positives.\n        //\n        while(falsePositiveStream.good())\n        {\n            std::getline(falsePositiveStream, currentCommaItem, ',');\n            if(configMap.count(currentCommaItem) == 0)\n            {\n                printf(\"ConfigParser!GetConfigFalsePositives: false_positive_stackhistory had invalid false positive named %s.\\n\", currentCommaItem.c_str());\n                continue;\n            }\n            falsePositives.StackHistoryFilter.push_back(converter.from_bytes(configMap[currentCommaItem]));\n        }\n    }\n\n    return falsePositives;\n}\n\n/**\n * @brief ConfigParser::GetConfigFilters - Parse filters from the config.\n * @return Parsed filter info.\n */\nstd::vector<FILTER_INFO> ConfigParser::GetConfigFilters()\n{\n    std::vector<std::string> filterNames;\n    std::vector<FILTER_INFO> filters;\n    FILTER_INFO currentFilter;\n    std::string currentFilterName;\n    std::string currentFilterType;\n    std::wstring currentFilterContent;\n    ULONG currentFilterFlags;\n    std::stringstream filterStream;\n    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;\n\n    //\n    // Check if there is anything for us to parse.\n    //\n    if(configMap.count(\"filters\") == 0)\n    {\n        printf(\"ConfigParser!GetConfigFilters: No filters to parse.\\n\");\n        return filters;\n    }\n\n    filterStream = std::stringstream(configMap[\"filters\"]);\n    //\n    // Enumerate the filters.\n    //\n    while(filterStream.good())\n    {\n        std::getline(filterStream, currentFilterName, ',');\n        filterNames.push_back(currentFilterName);\n    }\n\n    for(std::string filterName : filterNames)\n    {\n        //\n        // Check for the content of the filter.\n        //\n        if(configMap.count(filterName + \".content\") == 0)\n        {\n            printf(\"ConfigParser!GetConfigFilters: Failed to find content of filter %s.\\n\", filterName.c_str());\n            continue;\n        }\n        //\n        // Check for the type of the filter.\n        //\n        if(configMap.count(filterName + \".type\") == 0)\n        {\n            printf(\"ConfigParser!GetConfigFilters: Failed to find type of filter %s.\\n\", filterName.c_str());\n            continue;\n        }\n        //\n        // Check for the flags of the filter.\n        //\n        if(configMap.count(filterName + \".flags\") == 0)\n        {\n            printf(\"ConfigParser!GetConfigFilters: Failed to find flags of filter %s.\\n\", filterName.c_str());\n            continue;\n        }\n\n        currentFilterContent = converter.from_bytes(configMap[filterName + \".content\"]);\n        currentFilterType = configMap[filterName + \".type\"]; // f or r\n        currentFilterFlags = 0;\n\n        //\n        // Parse the flags config.\n        //\n        if(configMap[filterName + \".flags\"].find(\"e\") != std::string::npos)\n        {\n            currentFilterFlags |= FILTER_FLAG_EXECUTE;\n        }\n        if(configMap[filterName + \".flags\"].find(\"d\") != std::string::npos)\n        {\n            currentFilterFlags |= FILTER_FLAG_DELETE;\n        }\n        if(configMap[filterName + \".flags\"].find(\"w\") != std::string::npos)\n        {\n            currentFilterFlags |= FILTER_FLAG_WRITE;\n        }\n\n        //\n        // Parse the filter type.\n        //\n        if(currentFilterType[0] == 'f')\n        {\n            currentFilter.Type = FilesystemFilter;\n        } else if(currentFilterType[0] == 'r')\n        {\n            currentFilter.Type = RegistryFilter;\n        }\n        currentFilter.Flags = currentFilterFlags;\n        wcscpy_s(currentFilter.MatchString, currentFilterContent.c_str());\n        currentFilter.MatchStringSize = currentFilterContent.size() + 2;\n        filters.push_back(currentFilter);\n    }\n}\n\n"
  },
  {
    "path": "PeaceMakerGUI/configparser.h",
    "content": "#ifndef CONFIGPARSER_H\n#define CONFIGPARSER_H\n#include \"shared.h\"\n#include <fstream>\n#include <vector>\n#include <map>\n#include <string>\n#include <sstream>\n#include <codecvt>\n#include <locale>\n\ntypedef struct FalsePositives\n{\n    std::vector<std::wstring> SourcePathFilter;\n    std::vector<std::wstring> TargetPathFilter;\n    std::vector<std::wstring> StackHistoryFilter;\n} FALSE_POSITIVES;\n\nclass ConfigParser\n{\n    std::map<std::string, std::string> configMap;\n\npublic:\n    ConfigParser(std::string ConfigFile);\n\n    FALSE_POSITIVES GetConfigFalsePositives();\n    std::vector<FILTER_INFO> GetConfigFilters();\n};\n\n#endif // CONFIGPARSER_H\n"
  },
  {
    "path": "PeaceMakerGUI/detailedalertwindow.cpp",
    "content": "#include \"detailedalertwindow.h\"\n#include \"ui_detailedalertwindow.h\"\n\n/**\n * @brief DetailedAlertWindow::InitializeCommonTable - Common initialization across all tables.\n * @param table\n */\nvoid DetailedAlertWindow::InitializeCommonTable(QTableWidget *table)\n{\n    //\n    // Set properties that are common across tables.\n    //\n    table->horizontalHeader()->setStretchLastSection(true);\n    table->horizontalHeader()->setHighlightSections(false);\n    table->verticalHeader()->setVisible(false);\n    table->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    table->setSelectionBehavior(QAbstractItemView::SelectRows);\n    table->setSelectionMode(QAbstractItemView::SingleSelection);\n    table->verticalScrollBar()->setStyleSheet(\"color: white;\");\n    table->setSortingEnabled(false);\n    table->setStyleSheet(\"background: white;\");\n    table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);\n    table->verticalHeader()->setDefaultSectionSize(10);\n    table->horizontalHeader()->setVisible(false);\n}\n\nDetailedAlertWindow::DetailedAlertWindow(QWidget *parent) :\n    QWidget(parent),\n    ui(new Ui::DetailedAlertWindow)\n{\n    ui->setupUi(this);\n    this->setFixedSize(QSize(770, 550));\n}\n\nDetailedAlertWindow::~DetailedAlertWindow()\n{\n    delete ui;\n}\n\n/**\n * @brief DetailedAlertWindow::UpdateDisplayAlert - Update the window to display alert details based on AlertInfo.\n * @param AlertInfo - The new alert to display.\n */\nvoid DetailedAlertWindow::UpdateDisplayAlert(PBASE_ALERT_INFO AlertInfo)\n{\n    QString alertName;\n    QString alertSource;\n    PSTACK_VIOLATION_ALERT stackViolationAlert;\n    PFILTER_VIOLATION_ALERT filterViolationAlert;\n    PREMOTE_OPERATION_ALERT remoteOperationAlert;\n    ULONG i;\n    QString violatingAddress;\n\n    STACK_RETURN_INFO* stackHistory;\n    ULONG stackHistorySize;\n    CHAR tempBuffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];\n    PSYMBOL_INFO currentSymbolInformation;\n    ULONG64 offset;\n    QString stackHistoryString;\n    QString tooltip;\n    QTableWidgetItem* newWidget;\n    bool stackHistoryViolation;\n\n    memset(tempBuffer, 0, sizeof(tempBuffer));\n    currentSymbolInformation = RCAST<PSYMBOL_INFO>(tempBuffer);\n    currentSymbolInformation->SizeOfStruct = sizeof(SYMBOL_INFO);\n    currentSymbolInformation->MaxNameLen = MAX_SYM_NAME;\n\n    this->ui->AlertDetailsTable->setColumnCount(2);\n    this->ui->AlertDetailsTable->setRowCount(6);\n    InitializeCommonTable(this->ui->AlertDetailsTable);\n\n    //\n    // Fill out basic fields.\n    //\n    this->ui->AlertDetailsTable->setItem(0, 0, new QTableWidgetItem(\"Name\"));\n\n    this->ui->AlertDetailsTable->setItem(1, 0, new QTableWidgetItem(\"Source\"));\n\n    this->ui->AlertDetailsTable->setItem(2, 0, new QTableWidgetItem(\"Source Id\"));\n    this->ui->AlertDetailsTable->setItem(2, 1, new QTableWidgetItem(QString::number(RCAST<ULONG64>(AlertInfo->SourceId))));\n\n    this->ui->AlertDetailsTable->setItem(3, 0, new QTableWidgetItem(\"Source Path\"));\n    newWidget = new QTableWidgetItem(QString::fromWCharArray(AlertInfo->SourcePath));\n    newWidget->setToolTip(QString::fromWCharArray(AlertInfo->SourcePath));\n    this->ui->AlertDetailsTable->setItem(3, 1, newWidget);\n\n    this->ui->AlertDetailsTable->setItem(4, 0, new QTableWidgetItem(\"Target Path\"));\n    newWidget = new QTableWidgetItem(QString::fromWCharArray(AlertInfo->TargetPath));\n    newWidget->setToolTip(QString::fromWCharArray(AlertInfo->TargetPath));\n    this->ui->AlertDetailsTable->setItem(4, 1, newWidget);\n\n    //\n    // Get the name of the source.\n    //\n    switch(AlertInfo->AlertSource)\n    {\n    case ProcessCreate:\n        alertSource = \"Process Creation\";\n        break;\n    case ImageLoad:\n        alertSource = \"Image Load\";\n        break;\n    case RegistryFilterMatch:\n        alertSource = \"Registry Filter Match\";\n        break;\n    case FileFilterMatch:\n        alertSource = \"File Filter Match\";\n        break;\n    case ThreadCreate:\n        alertSource = \"Thread Create\";\n        break;\n    }\n\n    //\n    // Grab alert-type specific stuff.\n    //\n    switch(AlertInfo->AlertType)\n    {\n    case StackViolation:\n        stackViolationAlert = RCAST<PSTACK_VIOLATION_ALERT>(AlertInfo);\n        this->ui->AlertDetailsTable->setRowCount(6);\n        this->ui->AlertDetailsTable->setItem(5, 0, new QTableWidgetItem(\"Violating Address\"));\n        violatingAddress = violatingAddress.sprintf(\"0x%llx\", stackViolationAlert->ViolatingAddress);\n        this->ui->AlertDetailsTable->setItem(5, 1, new QTableWidgetItem(violatingAddress));\n\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = stackViolationAlert->StackHistory;\n        stackHistorySize = stackViolationAlert->StackHistorySize;\n        alertName = \"Stack Violation Alert\";\n        break;\n    case FilterViolation:\n        filterViolationAlert = RCAST<PFILTER_VIOLATION_ALERT>(AlertInfo);\n        this->ui->AlertDetailsTable->setRowCount(6);\n        this->ui->AlertDetailsTable->setItem(5, 0, new QTableWidgetItem(\"Filter Type\"));\n        switch(filterViolationAlert->AlertInformation.AlertSource)\n        {\n        case FileFilterMatch:\n            this->ui->AlertDetailsTable->setItem(5, 1, new QTableWidgetItem(\"Filesystem Filter\"));\n            break;\n        case RegistryFilterMatch:\n            this->ui->AlertDetailsTable->setItem(5, 1, new QTableWidgetItem(\"Registry Filter\"));\n            break;\n        }\n\n        //this->ui->AlertDetailsTable->setItem(6, 0, new QTableWidgetItem(\"Filter Content\"));\n\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = filterViolationAlert->StackHistory;\n        stackHistorySize = filterViolationAlert->StackHistorySize;\n        alertName = \"Filter Violation Alert\";\n        break;\n    case ParentProcessIdSpoofing:\n        remoteOperationAlert = RCAST<PREMOTE_OPERATION_ALERT>(AlertInfo);\n        this->ui->AlertDetailsTable->setRowCount(6);\n        this->ui->AlertDetailsTable->setItem(5, 0, new QTableWidgetItem(\"Target Id\"));\n        this->ui->AlertDetailsTable->setItem(5, 1, new QTableWidgetItem(QString::number(RCAST<ULONG64>(remoteOperationAlert->RemoteTargetId))));\n\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = remoteOperationAlert->StackHistory;\n        stackHistorySize = remoteOperationAlert->StackHistorySize;\n        alertName = \"Parent Process ID Spoofing\";\n        break;\n    case RemoteThreadCreation:\n        remoteOperationAlert = RCAST<PREMOTE_OPERATION_ALERT>(AlertInfo);\n        this->ui->AlertDetailsTable->setRowCount(6);\n        this->ui->AlertDetailsTable->setItem(5, 0, new QTableWidgetItem(\"Target Id\"));\n        this->ui->AlertDetailsTable->setItem(5, 1, new QTableWidgetItem(QString::number(RCAST<ULONG64>(remoteOperationAlert->RemoteTargetId))));\n\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = remoteOperationAlert->StackHistory;\n        stackHistorySize = remoteOperationAlert->StackHistorySize;\n        alertName = \"Remote Thread Creation\";\n        break;\n    }\n\n    this->ui->AlertDetailsTable->setItem(0, 1, new QTableWidgetItem(alertName));\n    this->ui->AlertDetailsTable->setItem(1, 1, new QTableWidgetItem(alertSource));\n\n    this->ui->AlertDetailsTable->resizeRowsToContents();\n\n    //\n    // Copy the stack history.\n    //\n    InitializeCommonTable(this->ui->AlertStackHistoryTable);\n    this->ui->AlertStackHistoryTable->setRowCount(stackHistorySize);\n    this->ui->AlertStackHistoryTable->setColumnCount(1);\n    for(i = 0; i < stackHistorySize; i++)\n    {\n        stackHistoryString = \"\";\n        stackHistoryViolation = false;\n\n        //\n        // First, try a symbol lookup.\n        //\n        if(SymFromAddr(GetCurrentProcess(), RCAST<DWORD64>(stackHistory[i].RawAddress), &offset, currentSymbolInformation))\n        {\n            stackHistoryString = stackHistoryString.sprintf(\"%s+0x%llx\", currentSymbolInformation->Name, offset);\n            tooltip = tooltip.sprintf(\"%ls+0x%llx\", stackHistory[i].BinaryPath, stackHistory[i].BinaryOffset);\n        }\n        else\n        {\n            if(wcslen(stackHistory[i].BinaryPath) == 0)\n            {\n                stackHistoryString = stackHistoryString.sprintf(\"0x%llx\", stackHistory[i].RawAddress);\n                stackHistoryViolation = true;\n            }\n            else\n            {\n                stackHistoryString = stackHistoryString.sprintf(\"%ls+0x%llx\", stackHistory[i].BinaryPath, stackHistory[i].BinaryOffset);\n            }\n            tooltip = stackHistoryString;\n        }\n\n        this->ui->AlertStackHistoryTable->setRowCount(i + 1);\n        newWidget = new QTableWidgetItem(stackHistoryString);\n        newWidget->setToolTip(tooltip);\n        if(stackHistoryViolation)\n        {\n            newWidget->setBackground(Qt::red);\n        }\n        this->ui->AlertStackHistoryTable->setItem(i, 0, newWidget);\n        this->ui->AlertStackHistoryTable->resizeRowsToContents();\n    }\n}\n"
  },
  {
    "path": "PeaceMakerGUI/detailedalertwindow.h",
    "content": "#ifndef DETAILEDALERTWINDOW_H\n#define DETAILEDALERTWINDOW_H\n\n#include <QWidget>\n#include <QTableWidget>\n#include <QScrollBar>\n\n#include <Windows.h>\n#include <DbgHelp.h>\n#include \"shared.h\"\n\nnamespace Ui {\nclass DetailedAlertWindow;\n}\n\nclass DetailedAlertWindow : public QWidget\n{\n    Q_OBJECT\n\n    void InitializeCommonTable(QTableWidget* table);\npublic:\n    explicit DetailedAlertWindow(QWidget *parent = nullptr);\n    ~DetailedAlertWindow();\n\n    void UpdateDisplayAlert(PBASE_ALERT_INFO AlertInfo);\n\nprivate:\n    Ui::DetailedAlertWindow *ui;\n};\n\n#endif // DETAILEDALERTWINDOW_H\n"
  },
  {
    "path": "PeaceMakerGUI/detailedalertwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>DetailedAlertWindow</class>\n <widget class=\"QWidget\" name=\"DetailedAlertWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>770</width>\n    <height>550</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Alert Details</string>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"AssetResources.qrc\">\n    <normaloff>:/assets/PeaceMakerIcon.ico</normaloff>:/assets/PeaceMakerIcon.ico</iconset>\n  </property>\n  <property name=\"styleSheet\">\n   <string notr=\"true\">background-color: #404040;</string>\n  </property>\n  <widget class=\"QTableWidget\" name=\"AlertDetailsTable\">\n   <property name=\"geometry\">\n    <rect>\n     <x>20</x>\n     <y>30</y>\n     <width>731</width>\n     <height>231</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background-color: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QTableWidget\" name=\"AlertStackHistoryTable\">\n   <property name=\"geometry\">\n    <rect>\n     <x>20</x>\n     <y>290</y>\n     <width>731</width>\n     <height>231</height>\n    </rect>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\">background-color: white;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"AlertStackHistoryLabel\">\n   <property name=\"geometry\">\n    <rect>\n     <x>320</x>\n     <y>270</y>\n     <width>131</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/AlertStackHistory.png&quot;/&gt;</string>\n   </property>\n  </widget>\n  <widget class=\"QLabel\" name=\"label\">\n   <property name=\"geometry\">\n    <rect>\n     <x>345</x>\n     <y>10</y>\n     <width>87</width>\n     <height>17</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>&lt;img src=&quot;:/assets/AlertDetails.png&quot;/&gt;</string>\n   </property>\n  </widget>\n </widget>\n <resources>\n  <include location=\"AssetResources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "PeaceMakerGUI/main.cpp",
    "content": "#include \"mainwindow.h\"\n\n#include <Windows.h>\n#include <QApplication>\n\nint main(int argc, char *argv[])\n{\n    AllocConsole();\n    freopen(\"CONOUT$\", \"w\", stdout);\n    QApplication a(argc, argv);\n    MainWindow w;\n    w.show();\n    return a.exec();\n}\n"
  },
  {
    "path": "PeaceMakerGUI/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nVOID\npmlog (\n    const char* format,\n    ...\n    )\n{\n    va_list vargs;\n    va_start(vargs, format);\n    printf(\"[PeaceMaker] \");\n    vprintf(format, vargs);\n    printf(\"\\n\");\n    va_end(vargs);\n}\n\n/**\n * @brief MainWindow::InitializeCommonTable - Common initialization across all tables.\n * @param table\n */\nvoid MainWindow::InitializeCommonTable(QTableWidget *table)\n{\n    //\n    // Set properties that are common across tables.\n    //\n    table->horizontalHeader()->setStretchLastSection(true);\n    table->horizontalHeader()->setHighlightSections(false);\n    table->verticalHeader()->setVisible(false);\n    table->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    table->setSelectionBehavior(QAbstractItemView::SelectRows);\n    table->setSelectionMode(QAbstractItemView::SingleSelection);\n    table->verticalScrollBar()->setStyleSheet(\"color: white;\");\n    table->setSortingEnabled(false);\n    table->setWordWrap(true);\n}\n\n/**\n * @brief MainWindow::InitializeAlertsTable - Initialize the table used for alerts.\n */\nvoid MainWindow::InitializeAlertsTable()\n{\n    QStringList headers;\n\n    this->AlertsTableSize = 0;\n\n    this->ui->AlertsTable->setColumnCount(2);\n    this->ui->AlertsTable->setRowCount(100);\n\n    headers << \"Date\" << \"Alert Name\";\n    this->ui->AlertsTable->setHorizontalHeaderLabels(headers);\n    this->ui->AlertsTable->setColumnWidth(0, 200);\n\n    InitializeCommonTable(this->ui->AlertsTable);\n\n    //\n    // Add the table as an \"associated element\".\n    //\n    this->ui->AlertsLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->AlertsTable));\n    this->ui->AlertsLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->OpenAlertButton));\n    this->ui->AlertsLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->DeleteAlertButton));\n}\n\n/**\n * @brief MainWindow::InitializeProcessesTable - Initialize the processes table.\n */\nvoid MainWindow::InitializeProcessesTable()\n{\n    QStringList headers;\n\n    this->ProcessesTableSize = 0;\n\n    this->ui->ProcessesTable->setColumnCount(3);\n    this->ui->ProcessesTable->setRowCount(100);\n\n    headers << \"Process Id\" << \"Execution Date\" << \"Path\";\n    this->ui->ProcessesTable->setHorizontalHeaderLabels(headers);\n\n    InitializeCommonTable(this->ui->ProcessesTable);\n\n    this->ui->ProcessesTable->setColumnWidth(1, 200);\n    this->ui->ProcessesTable->setColumnWidth(2, 400);\n\n    //\n    // Add the table as an \"associated element\".\n    //\n    this->ui->ProcessesLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->ProcessesTable));\n    this->ui->ProcessesLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->InvestigateProcessButton));\n    this->ui->ProcessesLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->ProcessSearch));\n    this->ui->ProcessesLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->ProcessSearchLabel));\n}\n\n/**\n * @brief MainWindow::InitializeFiltersTable - Initialize the filters table.\n */\nvoid MainWindow::InitializeFiltersTable()\n{\n    QStringList headers;\n\n    this->FiltersTableSize = 0;\n    this->FilesystemFiltersCount = 0;\n    this->RegistryFiltersCount = 0;\n\n    this->ui->FiltersTable->setColumnCount(3);\n    this->ui->FiltersTable->setRowCount(0);\n\n    headers << \"Filter Type\" << \"Filter Flags\" << \"Filter Content\";\n    this->ui->FiltersTable->setHorizontalHeaderLabels(headers);\n    this->ui->FiltersTable->setColumnWidth(2, 100);\n\n    InitializeCommonTable(this->ui->FiltersTable);\n\n    //\n    // Add the table as an \"associated element\".\n    //\n    this->ui->FiltersLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->FiltersTable));\n    this->ui->FiltersLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->AddFilterButton));\n    this->ui->FiltersLabel->AddAssociatedElement(RCAST<QWidget*>(this->ui->DeleteFilterButton));\n}\n\n/**\n * @brief MainWindow::ImportConfigFilters - One-time config filter import.\n */\nvoid MainWindow::ImportConfigFilters()\n{\n    std::vector<FILTER_INFO> configFilters;\n    BOOLEAN filterExists;\n\n    configFilters = config.GetConfigFilters();\n    for(FILTER_INFO configFilter : configFilters)\n    {\n        filterExists = FALSE;\n        //\n        // Make sure we don't add an existing filter.\n        //\n        for(FILTER_INFO existingFilter : filters)\n        {\n            if(existingFilter.Type == configFilter.Type &&\n               wcscmp(existingFilter.MatchString, configFilter.MatchString) == 0)\n            {\n                filterExists = TRUE;\n                break;\n            }\n        }\n        if(filterExists)\n        {\n            printf(\"MainWindow!ImportConfigFilters: Ignoring filter with content %ls. Already exists.\\n\", configFilter.MatchString);\n            continue;\n        }\n        communicator.AddFilter(configFilter.Type, configFilter.Flags, configFilter.MatchString, configFilter.MatchStringSize);\n        printf(\"MainWindow!ImportConfigFilters: Added config filter with content %ls.\\n\", configFilter.MatchString);\n    }\n}\n\n/**\n * @brief MainWindow::ThreadUpdateTables - Thread callback that updates all tables.\n * @param This - This pointer for the MainWindow instance.\n */\nvoid MainWindow::ThreadUpdateTables(MainWindow *This)\n{\n    BOOLEAN connected;\n    ULONG i;\n    ULONG c;\n\n    PBASE_ALERT_INFO currentAlert;\n    GLOBAL_SIZES globalSizes;\n    ULONG newProcessCount;\n    PPROCESS_SUMMARY_REQUEST processSummaries;\n    ULONG totalFilterSize;\n    ULONG filesystemFilterIterations;\n    ULONG registryFilterIterations;\n    LIST_FILTERS_REQUEST filterRequest;\n\n    connected = FALSE;\n\n    while(connected == FALSE)\n    {\n        if(This->communicator.ConnectDevice() == FALSE)\n        {\n            pmlog(\"Failed to connect to device. Retrying in 2 seconds.\");\n            Sleep(2000);\n            continue;\n        }\n        connected = TRUE;\n    }\n\n    pmlog(\"Established connection.\");\n\n    //\n    // Loop update tables.\n    //\n    while(true)\n    {\n        //\n        // Check for alerts.\n        //\n        while(This->communicator.QueuedAlerts())\n        {\n            currentAlert = This->communicator.PopAlert();\n            if(currentAlert == NULL)\n            {\n                break;\n            }\n\n            This->AddAlertSummary(currentAlert);\n        }\n\n        //\n        // Get global sizes.\n        //\n        globalSizes = This->communicator.GetGlobalSizes();\n\n        //\n        // Check for processes.\n        //\n        if(globalSizes.ProcessHistorySize != This->ProcessesTableSize)\n        {\n            newProcessCount = globalSizes.ProcessHistorySize - This->ProcessesTableSize;\n            if(newProcessCount > 0)\n            {\n                processSummaries = This->communicator.RequestProcessSummary(This->ProcessesTableSize, newProcessCount);\n                if(processSummaries)\n                {\n                    for(i = 0; i < processSummaries->ProcessHistorySize; i++)\n                    {\n                        This->AddProcessSummary(processSummaries->ProcessHistory[i]);\n                    }\n                    free(processSummaries);\n                    This->ui->ProcessesTable->resizeRowsToContents();\n                } else\n                {\n                    pmlog(\"processSummaries is NULL.\");\n                }\n            }\n        }\n\n        totalFilterSize = globalSizes.FilesystemFilterSize + globalSizes.RegistryFilterSize;\n        printf(\"FS Size: %i, RY Size: %i, This Size: %i\\n\", globalSizes.FilesystemFilterSize, globalSizes.RegistryFilterSize, This->FiltersTableSize);\n        //\n        // Look for new filters.\n        //\n        if(totalFilterSize != This->FiltersTableSize)\n        {\n            filesystemFilterIterations = (globalSizes.FilesystemFilterSize - This->FilesystemFiltersCount) % 10;\n            registryFilterIterations = (globalSizes.RegistryFilterSize - This->RegistryFiltersCount) % 10;\n\n            for(i = 0; i < filesystemFilterIterations; i++)\n            {\n                filterRequest = This->communicator.RequestFilters(FilesystemFilter, This->FilesystemFiltersCount);\n                for(c = 0; c < filterRequest.CopiedFilters; c++)\n                {\n                    This->AddFilterSummary(filterRequest.Filters[c], FilesystemFilter);\n                }\n            }\n\n            for(i = 0; i < registryFilterIterations; i++)\n            {\n                filterRequest = This->communicator.RequestFilters(RegistryFilter, This->RegistryFiltersCount);\n                for(c = 0; c < filterRequest.CopiedFilters; c++)\n                {\n                    This->AddFilterSummary(filterRequest.Filters[c], RegistryFilter);\n                }\n            }\n        }\n        //\n        // Import filters defined in our config if not done before.\n        //\n        if(This->importedConfigFilters == FALSE)\n        {\n            This->ImportConfigFilters();\n            This->importedConfigFilters = TRUE;\n        }\n        Sleep(3000);\n    }\n}\n\nMainWindow::MainWindow(QWidget *parent)\n    : QMainWindow(parent)\n    , ui(new Ui::MainWindow)\n    , config(CONFIG_FILE_NAME)\n{\n    ui->setupUi(this);\n    this->setFixedSize(QSize(990, 610));\n\n    InitializeAlertsTable();\n    InitializeProcessesTable();\n    InitializeFiltersTable();\n\n    //\n    // By default set the \"activeTab\" to the alerts tab.\n    //\n    ui->AlertsLabel->SwapActiveState();\n    this->activeTab = ui->AlertsLabel;\n\n    this->investigatorWindow = new InvestigateProcessWindow();\n    this->investigatorWindow->communicator = &this->communicator;\n    this->alertWindow = new DetailedAlertWindow();\n    this->addFilterWindow = new AddFilterWindow();\n    this->addFilterWindow->communicator = &this->communicator;\n    this->alertFalsePositives = config.GetConfigFalsePositives();\n\n    CreateThread(NULL, 0, RCAST<LPTHREAD_START_ROUTINE>(this->ThreadUpdateTables), this, 0, NULL);\n\n    SymInitialize(GetCurrentProcess(), NULL, TRUE);\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n    delete investigatorWindow;\n    delete alertWindow;\n}\n\n/**\n * @brief MainWindow::NotifyTabClick - Swap the active tab when a click is detected.\n * @param tab - The tab to swap to.\n */\nvoid MainWindow::NotifyTabClick(ClickableTab *tab)\n{\n    std::string tabName;\n\n    //\n    // The tab name is just its object name.\n    //\n    tabName = tab->objectName().toStdString();\n\n    //\n    // Swap the active/inactive state because of the click.\n    //\n    activeTab->SwapActiveState();\n    activeTab = tab;\n    activeTab->SwapActiveState();\n}\n\n/**\n * @brief MainWindow::AddAlertSummary - Add an alert to the table of alerts.\n * @param Alert - The alert to add.\n */\nvoid MainWindow::AddAlertSummary(PBASE_ALERT_INFO Alert)\n{\n    std::time_t currentTime;\n    std::string date;\n    std::string alertName;\n\n    PSTACK_VIOLATION_ALERT stackViolationAlert;\n    PFILTER_VIOLATION_ALERT filterViolationAlert;\n    PREMOTE_OPERATION_ALERT remoteOperationAlert;\n    STACK_RETURN_INFO* stackHistory;\n    ULONG stackHistorySize;\n    ULONG i;\n\n    //\n    // Filter source path.\n    //\n    for(std::wstring filteredSourcePath : alertFalsePositives.SourcePathFilter)\n    {\n        if(wcsstr(Alert->SourcePath, filteredSourcePath.c_str()) != NULL)\n        {\n            printf(\"MainWindow!AddAlertSummary: Ignoring alert, matched source path filter %ls.\\n\", filteredSourcePath.c_str());\n            return;\n        }\n    }\n    //\n    // Filter target path.\n    //\n    for(std::wstring filteredTargetPath : alertFalsePositives.TargetPathFilter)\n    {\n        if(wcsstr(Alert->TargetPath, filteredTargetPath.c_str()) != NULL)\n        {\n            printf(\"MainWindow!AddAlertSummary: Ignoring alert, matched target path filter %ls.\\n\", filteredTargetPath.c_str());\n            return;\n        }\n    }\n\n    //\n    // Get the current time.\n    //\n    currentTime = std::time(nullptr);\n    date = std::ctime(&currentTime);\n    date[date.length()-1] = '\\0'; // Remove the newline.\n\n    //\n    // Determine the alert type.\n    //\n    switch(Alert->AlertType)\n    {\n    case StackViolation:\n        alertName = \"Stack Violation\";\n        stackViolationAlert = RCAST<PSTACK_VIOLATION_ALERT>(Alert);\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = stackViolationAlert->StackHistory;\n        stackHistorySize = stackViolationAlert->StackHistorySize;\n        break;\n    case FilterViolation:\n        alertName = \"Filter Violation\";\n        filterViolationAlert = RCAST<PFILTER_VIOLATION_ALERT>(Alert);\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = filterViolationAlert->StackHistory;\n        stackHistorySize = filterViolationAlert->StackHistorySize;\n        break;\n    case ParentProcessIdSpoofing:\n        alertName = \"Parent Process ID Spoofing\";\n        remoteOperationAlert = RCAST<PREMOTE_OPERATION_ALERT>(Alert);\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = remoteOperationAlert->StackHistory;\n        stackHistorySize = remoteOperationAlert->StackHistorySize;\n        break;\n    case RemoteThreadCreation:\n        alertName = \"Remote Thread Creation\";\n        remoteOperationAlert = RCAST<PREMOTE_OPERATION_ALERT>(Alert);\n        //\n        // Set the stack history info for this alert.\n        //\n        stackHistory = remoteOperationAlert->StackHistory;\n        stackHistorySize = remoteOperationAlert->StackHistorySize;\n        break;\n    }\n\n    //\n    // Filter stack history.\n    //\n    for(i = 0; i < stackHistorySize; i++)\n    {\n        for(std::wstring filteredStackHistory : alertFalsePositives.StackHistoryFilter)\n        {\n            if(wcsstr(stackHistory[i].BinaryPath, filteredStackHistory.c_str()) != NULL)\n            {\n                printf(\"MainWindow!AddAlertSummary: Ignoring alert, matched stack history filter %ls.\\n\", filteredStackHistory.c_str());\n                return;\n            }\n        }\n    }\n\n\n    this->ui->AlertsTable->setRowCount(this->AlertsTableSize + 1);\n    this->ui->AlertsTable->insertRow(0);\n    this->ui->AlertsTable->setItem(0, 0, new QTableWidgetItem(QString::fromStdString(date)));\n    this->ui->AlertsTable->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(alertName)));\n    this->AlertsTableSize++;\n\n    alerts.push_back(Alert);\n    this->ui->AlertsLabel->SetCustomText(\"<img src=\\\":/assets/PendingAlertsTab.png\\\"/>\");\n}\n\n/**\n * @brief MainWindow::AddProcessSummary - Add a process to the processes table.\n * @param ProcessSummary - The process to add.\n */\nvoid MainWindow::AddProcessSummary(PROCESS_SUMMARY_ENTRY ProcessSummary)\n{\n    std::time_t processExecutionDate;\n    std::string dateString;\n    QTableWidgetItem* pathItem;\n\n    //\n    // First, we need to convert the epoch time to a date.\n    //\n    processExecutionDate = ProcessSummary.EpochExecutionTime;\n    dateString = std::ctime(&processExecutionDate);\n    dateString[dateString.length()-1] = '\\0'; // Remove the newline.\n\n    //\n    // Next, add the appropriate information to the table.\n    //\n    this->ui->ProcessesTable->setRowCount(this->ProcessesTableSize + 1);\n    this->ui->ProcessesTable->insertRow(0);\n    this->ui->ProcessesTable->setItem(0, 0, new QTableWidgetItem(QString::number(RCAST<ULONG64>(ProcessSummary.ProcessId))));\n    this->ui->ProcessesTable->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(dateString)));\n\n    pathItem = new QTableWidgetItem(QString::fromWCharArray(ProcessSummary.ImageFileName));\n    pathItem->setToolTip(QString::fromWCharArray(ProcessSummary.ImageFileName));\n    this->ui->ProcessesTable->setItem(0, 2, pathItem);\n    //this->ui->ProcessesTable->resizeRowsToContents();\n    this->ProcessesTableSize++;\n\n    processes.push_back(ProcessSummary);\n}\n\n/**\n * @brief MainWindow::AddFilterSummary - Add a filter to the filters table.\n * @param FilterInfo - The filter to add.\n * @param FilterType - The type of filter to add.\n */\nvoid MainWindow::AddFilterSummary(FILTER_INFO FilterInfo, STRING_FILTER_TYPE FilterType)\n{\n    std::string filterType;\n    std::string filterFlags;\n\n    //\n    // Depending on the filter type, make the enum value a string.\n    //\n    switch(FilterType)\n    {\n    case FilesystemFilter:\n        filterType = \"Filesystem Filter\";\n        this->FilesystemFiltersCount++;\n        break;\n    case RegistryFilter:\n        filterType = \"Registry Filter\";\n        this->RegistryFiltersCount++;\n        break;\n    }\n\n    //\n    // Now convert the flags.\n    //\n    if(FlagOn(FilterInfo.Flags, FILTER_FLAG_DELETE))\n    {\n        filterFlags = \"Delete\";\n    }\n    if(FlagOn(FilterInfo.Flags, FILTER_FLAG_WRITE))\n    {\n        //\n        // Add a comma if this is the second flag.\n        //\n        if(FlagOn(FilterInfo.Flags, FILTER_FLAG_DELETE))\n        {\n            filterFlags += \", \";\n        }\n        filterFlags += \"Write\";\n    }\n    if(FlagOn(FilterInfo.Flags, FILTER_FLAG_EXECUTE))\n    {\n        //\n        // Add a comma if this is the third flag.\n        //\n        if(FlagOn(FilterInfo.Flags, FILTER_FLAG_DELETE) || FlagOn(FilterInfo.Flags, FILTER_FLAG_WRITE))\n        {\n            filterFlags += \", \";\n        }\n        filterFlags += \"Execute\";\n    }\n\n    this->ui->FiltersTable->setRowCount(this->FiltersTableSize + 1);\n    this->ui->FiltersTable->setItem(this->FiltersTableSize, 0, new QTableWidgetItem(QString::fromStdString(filterType)));\n    this->ui->FiltersTable->setItem(this->FiltersTableSize, 1, new QTableWidgetItem(QString::fromStdString(filterFlags)));\n    this->ui->FiltersTable->setItem(this->FiltersTableSize, 2, new QTableWidgetItem(QString::fromWCharArray(FilterInfo.MatchString)));\n    this->FiltersTableSize++;\n\n    filters.push_back(FilterInfo);\n}\n\n/**\n * @brief MainWindow::on_InvestigateProcessButton_clicked - Open the process investigation window for the selected process.\n */\nvoid MainWindow::on_InvestigateProcessButton_clicked()\n{\n    PPROCESS_DETAILED_REQUEST processDetailed;\n    PROCESS_SIZES_REQUEST processSizes;\n    int selectedRow;\n\n    if(this->ui->ProcessesTable->selectedItems().size() == 0)\n    {\n        return;\n    }\n\n    //\n    // Since rows start from 0, we need to subtract\n    // the row count from the table size to get the\n    // right index.\n    //\n    selectedRow = processes.size() - 1 - this->ui->ProcessesTable->selectedItems()[0]->row();\n\n    processSizes = communicator.GetProcessSizes(processes[selectedRow].ProcessId, processes[selectedRow].EpochExecutionTime);\n    processDetailed = communicator.RequestDetailedProcess(processes[selectedRow].ProcessId, processes[selectedRow].EpochExecutionTime, processSizes.ImageSize, processSizes.StackSize);\n    if (processDetailed == NULL || processDetailed->Populated == FALSE)\n    {\n        pmlog(\"main: Failed to retrieve a detailed process report.\");\n        return;\n    }\n\n    this->investigatorWindow->UpdateNewProcess(*processDetailed);\n    free(processDetailed);\n    this->investigatorWindow->show();\n    this->investigatorWindow->RefreshWidgets();\n}\n\n/**\n * @brief MainWindow::on_ProcessSearch_editingFinished - Search for the specified process.\n */\nvoid MainWindow::on_ProcessSearch_editingFinished()\n{\n    QList<QTableWidgetItem*> searchResults;\n    QModelIndexList indexList;\n    int firstSelectedRow;\n    QTableWidgetItem* nextWidgetItem;\n\n    nextWidgetItem = NULL;\n\n    indexList = this->ui->ProcessesTable->selectionModel()->selectedIndexes();\n    if(indexList.count() >= 1)\n    {\n        firstSelectedRow = indexList[0].row();\n    }\n    else\n    {\n        firstSelectedRow = 0;\n    }\n\n\n    //\n    // Search for the first widget after whatever row I have selected.\n    // Allows for searching of multiple items, not just one.\n    //\n    searchResults = this->ui->ProcessesTable->findItems(this->ui->ProcessSearch->text(), Qt::MatchContains);\n    for(QTableWidgetItem* result : searchResults)\n    {\n        if(result->row() > firstSelectedRow)\n        {\n            nextWidgetItem = result;\n            break;\n        }\n    }\n    if(nextWidgetItem)\n    {\n        this->ui->ProcessesTable->selectRow(nextWidgetItem->row());\n    }\n}\n\n/**\n * @brief MainWindow::on_OpenAlertButton_clicked - Open the selected alert.\n */\nvoid MainWindow::on_OpenAlertButton_clicked()\n{\n    int selectedRow;\n\n    if(this->ui->AlertsTable->selectedItems().size() == 0)\n    {\n        return;\n    }\n\n    //\n    // Since rows start from 0, we need to subtract\n    // the row count from the table size to get the\n    // right index.\n    //\n    selectedRow = alerts.size() - 1 - this->ui->AlertsTable->selectedItems()[0]->row();\n\n    alertWindow->UpdateDisplayAlert(alerts[selectedRow]);\n    alertWindow->show();\n}\n\n/**\n * @brief MainWindow::on_DeleteAlertButton_clicked - Delete the selected alert.\n */\nvoid MainWindow::on_DeleteAlertButton_clicked()\n{\n    int selectedRow;\n\n    if(this->ui->AlertsTable->selectedItems().size() == 0)\n    {\n        return;\n    }\n\n    selectedRow = this->ui->AlertsTable->selectedItems()[0]->row();\n    this->ui->AlertsTable->removeRow(selectedRow);\n}\n\n/**\n * @brief MainWindow::on_AddFilterButton_clicked - Add a filter.\n */\nvoid MainWindow::on_AddFilterButton_clicked()\n{\n    this->addFilterWindow->ClearStates();\n    this->addFilterWindow->show();\n}\n\n/**\n * @brief MainWindow::on_DeleteFilterButton_clicked - Make a request to delete the selected filter.\n */\nvoid MainWindow::on_DeleteFilterButton_clicked()\n{\n    int selectedRow;\n\n    if(this->ui->FiltersTable->selectedItems().size() == 0)\n    {\n        return;\n    }\n\n    //\n    // Since rows start from 0, we need to subtract\n    // the row count from the table size to get the\n    // right index.\n    //\n    selectedRow = this->ui->FiltersTable->selectedItems()[0]->row();\n    //\n    // If we successfully deleted the filter, remove the row.\n    //\n    if(communicator.DeleteFilter(filters[selectedRow]))\n    {\n        this->ui->FiltersTable->removeRow(selectedRow);\n\n        //\n        // Delete the filter from our records.\n        //\n        switch(filters[selectedRow].Type)\n        {\n        case FilesystemFilter:\n            this->FilesystemFiltersCount--;\n            break;\n        case RegistryFilter:\n            this->RegistryFiltersCount--;\n            break;\n        }\n\n        filters.erase(filters.begin() + selectedRow);\n        this->FiltersTableSize--;\n    }\n}\n"
  },
  {
    "path": "PeaceMakerGUI/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <QMainWindow>\n#include <QTableWidgetItem>\n#include <QScrollBar>\n#include <QString>\n#include <QMessageBox>\n#include <QDir>\n\n#include <ctime>\n#include <string>\n#include <vector>\n#include \"shared.h\"\n#include \"InvestigateProcessWindow.h\"\n#include \"detailedalertwindow.h\"\n#include \"addfilterwindow.h\"\n#include \"ClickableTab.h\"\n#include \"IOCTLCommunicationUser.h\"\n#include \"configparser.h\"\n\nQT_BEGIN_NAMESPACE\nnamespace Ui { class MainWindow; }\nQT_END_NAMESPACE\n\nVOID\npmlog (\n    const char* format,\n    ...\n    );\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n    ClickableTab* activeTab;\n    int AlertsTableSize;\n    ULONG64 ProcessesTableSize;\n    ULONG FiltersTableSize;\n\n    int FilesystemFiltersCount;\n    int RegistryFiltersCount;\n\n    std::vector<PBASE_ALERT_INFO> alerts;\n    std::vector<PROCESS_SUMMARY_ENTRY> processes;\n    std::vector<FILTER_INFO> filters;\n\n    ConfigParser config;\n    FALSE_POSITIVES alertFalsePositives;\n\n    IOCTLCommunication communicator;\n\n    void InitializeCommonTable(QTableWidget* table);\n\n    void InitializeAlertsTable();\n    void InitializeProcessesTable();\n    void InitializeFiltersTable();\n\n    void ImportConfigFilters();\n    BOOLEAN importedConfigFilters = FALSE;\n\n    static void ThreadUpdateTables(MainWindow* This);\n\n    InvestigateProcessWindow* investigatorWindow;\n    DetailedAlertWindow* alertWindow;\n    AddFilterWindow* addFilterWindow;\npublic:\n    MainWindow(QWidget *parent = nullptr);\n    ~MainWindow();\n\n    void NotifyTabClick(ClickableTab* tab);\n\n    void AddAlertSummary(PBASE_ALERT_INFO Alert);\n    void AddProcessSummary(PROCESS_SUMMARY_ENTRY ProcessSummary);\n    void AddFilterSummary(FILTER_INFO FilterInfo, STRING_FILTER_TYPE FilterType);\n\n    void ActivateAlertsWindow();\n    void ActivateProcessesWindow();\n    void ActivateFiltersWindow();\n    void ActivateConfigWindow();\nprivate slots:\n\n    void on_InvestigateProcessButton_clicked();\n\n    void on_ProcessSearch_editingFinished();\n\n    void on_OpenAlertButton_clicked();\n\n    void on_DeleteAlertButton_clicked();\n\n    void on_AddFilterButton_clicked();\n\n    void on_DeleteFilterButton_clicked();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "PeaceMakerGUI/mainwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>990</width>\n    <height>610</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>PeaceMaker</string>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"AssetResources.qrc\">\n    <normaloff>:/assets/PeaceMakerIcon.ico</normaloff>:/assets/PeaceMakerIcon.ico</iconset>\n  </property>\n  <property name=\"styleSheet\">\n   <string notr=\"true\">background-color: #404040;</string>\n  </property>\n  <widget class=\"QWidget\" name=\"centralwidget\">\n   <widget class=\"QLabel\" name=\"LogoLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>20</x>\n      <y>20</y>\n      <width>225</width>\n      <height>36</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/assets/PeaceMakerLogo.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"ClickableTab\" name=\"AlertsLabel\" native=\"true\">\n    <property name=\"geometry\">\n     <rect>\n      <x>350</x>\n      <y>30</y>\n      <width>95</width>\n      <height>28</height>\n     </rect>\n    </property>\n    <property name=\"text\" stdset=\"0\">\n     <string>&lt;img src=&quot;:/assets/AlertsTabInactive.png&quot;/&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"ClickableTab\" name=\"ProcessesLabel\" native=\"true\">\n    <property name=\"geometry\">\n     <rect>\n      <x>500</x>\n      <y>30</y>\n      <width>147</width>\n      <height>28</height>\n     </rect>\n    </property>\n    <property name=\"text\" stdset=\"0\">\n     <string>&lt;img src=&quot;:/assets/ProcessesTabInactive.png&quot;/&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"ClickableTab\" name=\"FiltersLabel\" native=\"true\">\n    <property name=\"geometry\">\n     <rect>\n      <x>700</x>\n      <y>30</y>\n      <width>96</width>\n      <height>28</height>\n     </rect>\n    </property>\n    <property name=\"text\" stdset=\"0\">\n     <string>&lt;img src=&quot;:/assets/FiltersTabInactive.png&quot;/&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"ClickableTab\" name=\"ConfigLabel\" native=\"true\">\n    <property name=\"geometry\">\n     <rect>\n      <x>850</x>\n      <y>30</y>\n      <width>89</width>\n      <height>28</height>\n     </rect>\n    </property>\n    <property name=\"text\" stdset=\"0\">\n     <string>&lt;img src=&quot;:/assets/ConfigTabInactive.png&quot;/&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"QTableWidget\" name=\"AlertsTable\">\n    <property name=\"geometry\">\n     <rect>\n      <x>10</x>\n      <y>70</y>\n      <width>971</width>\n      <height>481</height>\n     </rect>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background: white;</string>\n    </property>\n   </widget>\n   <widget class=\"QTableWidget\" name=\"ProcessesTable\">\n    <property name=\"geometry\">\n     <rect>\n      <x>10</x>\n      <y>70</y>\n      <width>971</width>\n      <height>481</height>\n     </rect>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background: white;</string>\n    </property>\n   </widget>\n   <widget class=\"QTableWidget\" name=\"FiltersTable\">\n    <property name=\"geometry\">\n     <rect>\n      <x>10</x>\n      <y>70</y>\n      <width>971</width>\n      <height>481</height>\n     </rect>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background: white;</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"CopyrightLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>700</x>\n      <y>580</y>\n      <width>280</width>\n      <height>18</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>&lt;img src=&quot;:/assets/Copyright.png&quot;/&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"InvestigateProcessButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>210</x>\n      <y>570</y>\n      <width>151</width>\n      <height>31</height>\n     </rect>\n    </property>\n    <property name=\"visible\">\n     <bool>false</bool>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background: white;</string>\n    </property>\n    <property name=\"text\">\n     <string>Investigate Process</string>\n    </property>\n   </widget>\n   <widget class=\"QLineEdit\" name=\"ProcessSearch\">\n    <property name=\"geometry\">\n     <rect>\n      <x>10</x>\n      <y>580</y>\n      <width>181</width>\n      <height>21</height>\n     </rect>\n    </property>\n    <property name=\"visible\">\n     <bool>false</bool>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background: white;</string>\n    </property>\n   </widget>\n   <widget class=\"QLabel\" name=\"ProcessSearchLabel\">\n    <property name=\"geometry\">\n     <rect>\n      <x>75</x>\n      <y>560</y>\n      <width>49</width>\n      <height>17</height>\n     </rect>\n    </property>\n    <property name=\"visible\">\n     <bool>false</bool>\n    </property>\n    <property name=\"text\">\n     <string>&lt;img src=&quot;:/assets/Search.png&quot;/&gt;</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"OpenAlertButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>10</x>\n      <y>570</y>\n      <width>151</width>\n      <height>31</height>\n     </rect>\n    </property>\n    <property name=\"visible\">\n     <bool>false</bool>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background-color: white;</string>\n    </property>\n    <property name=\"text\">\n     <string>Open Alert</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"DeleteAlertButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>170</x>\n      <y>570</y>\n      <width>151</width>\n      <height>31</height>\n     </rect>\n    </property>\n    <property name=\"visible\">\n     <bool>false</bool>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background-color: white;</string>\n    </property>\n    <property name=\"text\">\n     <string>Delete Alert</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"AddFilterButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>10</x>\n      <y>570</y>\n      <width>151</width>\n      <height>31</height>\n     </rect>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background-color: white;</string>\n    </property>\n    <property name=\"text\">\n     <string>Add Filter</string>\n    </property>\n   </widget>\n   <widget class=\"QPushButton\" name=\"DeleteFilterButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>170</x>\n      <y>570</y>\n      <width>151</width>\n      <height>31</height>\n     </rect>\n    </property>\n    <property name=\"styleSheet\">\n     <string notr=\"true\">background-color: white;</string>\n    </property>\n    <property name=\"text\">\n     <string>Delete Filter</string>\n    </property>\n   </widget>\n   <zorder>FiltersTable</zorder>\n   <zorder>LogoLabel</zorder>\n   <zorder>AlertsLabel</zorder>\n   <zorder>ProcessesLabel</zorder>\n   <zorder>FiltersLabel</zorder>\n   <zorder>ConfigLabel</zorder>\n   <zorder>ProcessesTable</zorder>\n   <zorder>AlertsTable</zorder>\n   <zorder>CopyrightLabel</zorder>\n   <zorder>InvestigateProcessButton</zorder>\n   <zorder>ProcessSearch</zorder>\n   <zorder>ProcessSearchLabel</zorder>\n   <zorder>OpenAlertButton</zorder>\n   <zorder>DeleteAlertButton</zorder>\n   <zorder>AddFilterButton</zorder>\n   <zorder>DeleteFilterButton</zorder>\n  </widget>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>ClickableTab</class>\n   <extends>QWidget</extends>\n   <header>clickabletab.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"AssetResources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "README.md",
    "content": "# PeaceMaker Threat Detection\nPeaceMaker Threat Detection is a kernel-mode utility designed to detect a variety of methods commonly used in advanced forms of malware. Compared to a stereotypical anti-virus that may detect via hashes or patterns, PeaceMaker targets the techniques malware commonly uses in order to catch them in the act. Furthermore, PeaceMaker is designed to provide an incredible amount of detail when a malicious technique is detected, allowing for effective containment and response.\n\n## Motivation\nPeaceMaker was designed primarily as a weapon to detect custom malware in virtualized environments. Specifically, this project was started in pursuit of preparing for the [Information Security Talent Search](https://www.ists.io/) blue/red team competition hosted by RIT's Security Club, [RITSEC](https://www.ritsec.club/). The competition's red team is primarily industry security professionals, which is why I decided my own defense platform would be useful. In a project like this, I can make sacrifices to factors such as performance that widely-employed AV/EDR companies can't make, allowing me to make decisions I couldn't get away with in a real product.\n\n## Features\n- View what code started a process (stack trace).\n- View what code loaded an image into a process (stack trace).\n- Detect unmapped (hidden) code via Stack Walking common operations such as:\n\t- Process Creation\n\t- Image Load\n\t- Thread Creation\n- Detect remote thread creation.\n- Detect parent process ID spoofing.\n- Detect threat creation on unmapped (hidden) code.\n- Block basic tamper operations on the GUI Client.\n- Block filesystem/registry write, delete, or execute operations that violate a user-specified filter.\n- Detect filesystem/registry write, delete, or execute operations that violate a user-specified filter.\n\t- Logs the source process and stack of the operation.\n- Filter for known false positives.\n\n## Notable properties\n- Heavily commented code.\n- All detection routines are in the kernel driver.\n- Designed to detect user-mode malware.\n- Tested using Driver Verifier standard configuration.\n- Tested by putting it on my \"daily driver\" laptop and monitoring for issues (none occurred).\n\n## Shortcomings\n- Inefficient time and space complexity.\n\t- Performs useful, but expensive forensics that slow down common operations.\n\t- Often allocates more memory than needed, doesn't utilize space optimization techniques such as compression.\n- Weak operation filtering mechanism.\n\t- For example, filters that prevent deletion of a file or registry key can be bypassed.\n\t- You can only filter on the target of an operation (i.e file/key name).\n- Weak tamper protection.\n\t- Only protects against process termination of the GUI, nothing else.\n- Incomplete GUI.\n\n## Screenshots\n![Alerts Tab](https://i.imgur.com/5L7fcsu.png)\n![Processes Tab](https://i.imgur.com/v6NtDXH.png)\n![Filters Tab](https://i.imgur.com/PL2clda.png)\n![Process Information](https://i.imgur.com/Jefp8ac.png)\n"
  }
]