[
  {
    "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/main/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[Ww][Ii][Nn]32/\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# ASP.NET Scaffolding\nScaffoldingReadMe.txt\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*.tlog\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# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\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 6 auto-generated project file (contains which files were open etc.)\n*.vbp\n\n# Visual Studio 6 workspace and project file (working project files containing files to include in project)\n*.dsw\n*.dsp\n\n# Visual Studio 6 technical files\n*.ncb\n*.aps\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# Visual Studio History (VSHistory) files\n.vshistory/\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\n# Fody - auto-generated XML schema\nFodyWeavers.xsd\n\n# VS Code files for those working on multiple tools\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n*.code-workspace\n\n# Local History for Visual Studio Code\n.history/\n\n# Windows Installer files from build outputs\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# JetBrains Rider\n*.sln.iml\n"
  },
  {
    "path": "PatchGuardBypass/PatchGuardBypass.inf",
    "content": ";\n; PatchGuardBypass.inf\n;\n\n[Version]\nSignature=\"$WINDOWS NT$\"\nClass=Sample ; TODO: edit Class\nClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid\nProvider=%ManufacturerName%\nCatalogFile=PatchGuardBypass.cat\nDriverVer= ; TODO: set DriverVer in stampinf property pages\nPnpLockDown=1\n\n[DestinationDirs]\nDefaultDestDir = 12\nPatchGuardBypass_Device_CoInstaller_CopyFiles = 11\n\n; ================= Class section =====================\n\n[ClassInstall32]\nAddreg=SampleClassReg\n\n[SampleClassReg]\nHKR,,,0,%ClassName%\nHKR,,Icon,,-5\n\n[SourceDisksNames]\n1 = %DiskName%,,,\"\"\n\n[SourceDisksFiles]\nPatchGuardBypass.sys  = 1,,\nWdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames\n\n;*****************************************\n; Install Section\n;*****************************************\n\n[Manufacturer]\n%ManufacturerName%=Standard,NT$ARCH$\n\n[Standard.NT$ARCH$]\n%PatchGuardBypass.DeviceDesc%=PatchGuardBypass_Device, Root\\PatchGuardBypass ; TODO: edit hw-id\n\n[PatchGuardBypass_Device.NT]\nCopyFiles=Drivers_Dir\n\n[Drivers_Dir]\nPatchGuardBypass.sys\n\n;-------------- Service installation\n[PatchGuardBypass_Device.NT.Services]\nAddService = PatchGuardBypass,%SPSVCINST_ASSOCSERVICE%, PatchGuardBypass_Service_Inst\n\n; -------------- PatchGuardBypass driver install sections\n[PatchGuardBypass_Service_Inst]\nDisplayName    = %PatchGuardBypass.SVCDESC%\nServiceType    = 1               ; SERVICE_KERNEL_DRIVER\nStartType      = 3               ; SERVICE_DEMAND_START\nErrorControl   = 1               ; SERVICE_ERROR_NORMAL\nServiceBinary  = %12%\\PatchGuardBypass.sys\n\n;\n;--- PatchGuardBypass_Device Coinstaller installation ------\n;\n\n[PatchGuardBypass_Device.NT.CoInstallers]\nAddReg=PatchGuardBypass_Device_CoInstaller_AddReg\nCopyFiles=PatchGuardBypass_Device_CoInstaller_CopyFiles\n\n[PatchGuardBypass_Device_CoInstaller_AddReg]\nHKR,,CoInstallers32,0x00010000, \"WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller\"\n\n[PatchGuardBypass_Device_CoInstaller_CopyFiles]\nWdfCoInstaller$KMDFCOINSTALLERVERSION$.dll\n\n[PatchGuardBypass_Device.NT.Wdf]\nKmdfService =  PatchGuardBypass, PatchGuardBypass_wdfsect\n[PatchGuardBypass_wdfsect]\nKmdfLibraryVersion = $KMDFVERSION$\n\n[Strings]\nSPSVCINST_ASSOCSERVICE= 0x00000002\nManufacturerName=\"<Your manufacturer name>\" ;TODO: Replace with your manufacturer name\nClassName=\"Samples\" ; TODO: edit ClassName\nDiskName = \"PatchGuardBypass Installation Disk\"\nPatchGuardBypass.DeviceDesc = \"PatchGuardBypass Device\"\nPatchGuardBypass.SVCDESC = \"PatchGuardBypass Service\"\n"
  },
  {
    "path": "PatchGuardBypass/PatchGuardBypass.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  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{57A68F53-C563-405D-B2E1-C66585DA64E4}</ProjectGuid>\n    <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid>\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\n    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>\n    <Configuration>Debug</Configuration>\n    <Platform Condition=\"'$(Platform)' == ''\">Win32</Platform>\n    <RootNamespace>PatchGuardBypass</RootNamespace>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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>KMDF</DriverType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\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    <Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>\n    <Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>\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  <ItemGroup>\n    <Inf Include=\"PatchGuardBypass.inf\" />\n  </ItemGroup>\n  <ItemGroup>\n    <FilesToPackage Include=\"$(TargetPath)\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"src\\core\\features\\Disable.cpp\" />\n    <ClCompile Include=\"src\\core\\features\\Evade.cpp\" />\n    <ClCompile Include=\"src\\core\\flows\\Flows.cpp\" />\n    <ClCompile Include=\"src\\core\\symbols\\Globals.cpp\" />\n    <ClCompile Include=\"src\\core\\symbols\\Offsets.cpp\" />\n    <ClCompile Include=\"src\\utils\\log\\Log.cpp\" />\n    <ClCompile Include=\"src\\main.cpp\" />\n    <ClCompile Include=\"src\\core\\timers\\Timer.cpp\" />\n    <ClCompile Include=\"src\\core\\features\\Verify.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"src\\core\\flows\\Flows.h\" />\n    <ClInclude Include=\"src\\core\\symbols\\Globals.h\" />\n    <ClInclude Include=\"src\\utils\\log\\Log.h\" />\n    <ClInclude Include=\"src\\core\\PatchGuard.h\" />\n    <ClInclude Include=\"src\\core\\timers\\Timer.h\" />\n    <ClInclude Include=\"src\\core\\symbols\\Offsets.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "PatchGuardBypass/PatchGuardBypass.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  </ItemGroup>\n  <ItemGroup>\n    <Inf Include=\"PatchGuardBypass.inf\">\n      <Filter>Driver Files</Filter>\n    </Inf>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"src\\main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\utils\\log\\Log.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\timers\\Timer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\features\\Disable.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\flows\\Flows.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\features\\Evade.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\features\\Verify.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\symbols\\Globals.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\core\\symbols\\Offsets.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"src\\utils\\log\\Log.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\core\\timers\\Timer.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\core\\PatchGuard.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\core\\flows\\Flows.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\core\\symbols\\Offsets.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\core\\symbols\\Globals.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "PatchGuardBypass/src/core/PatchGuard.h",
    "content": "#pragma once\n#include <ntdef.h>\n\nnamespace PG\n{\n\tnamespace Disable\n\t{\n\t\tBOOLEAN\n\t\tExecute(\n\t\t\tVOID\n\t\t);\n\n\t\tVOID\n\t\tUnload(\n\t\t\tVOID\n\t\t);\n\t};\n\n\tnamespace Evade\n\t{\n\t\tBOOLEAN\n\t\tExecute(\n\t\t\tVOID\n\t\t);\n\n\t\tVOID\n\t\tUnload(\n\t\t\tVOID\n\t\t);\n\t};\n\n\tnamespace Verify\n\t{\n\t\tBOOLEAN\n\t\tExecute(\n\t\t\tVOID\n\t\t);\n\n\t\tVOID\n\t\tUnload(\n\t\t\tVOID\n\t\t);\n\t};\n};\n"
  },
  {
    "path": "PatchGuardBypass/src/core/features/Disable.cpp",
    "content": "#include \"../PatchGuard.h\"\n#include \"../timers/Timer.h\"\n#include \"../flows/Flows.h\"\n#include \"../../utils/Log/Log.h\"\n#include <ntddk.h>\n\n/**\nFor each Timer encountered, checks if it's PG related and removes it if so.\nCompatible with the TIMER_CALLBACK signature, passed to SearchSystemTimers.\n*/\nTIMER_SEARCH_STATUS\nRemoveTimer(\n\tPKTIMER Timer,\n\tPKDPC DecodedDpc\n)\n{\n    if (Flows::ContextAwareTimer::IsTargetTimer(Timer, DecodedDpc))\n    {\n        KeCancelTimer(Timer);\n\n        Log(\"Removed Context-Aware Timer/DPC: %p/%p\\n\", Timer, DecodedDpc);\n    }\n\n    if (Flows::ContextUnawareTimer::IsTargetTimer(Timer, DecodedDpc))\n    {\n        KeCancelTimer(Timer);\n\n        Log(\"Removed Context-Unaware Timer/DPC: %p/%p\\n\", Timer, DecodedDpc);\n    }\n\n    return ContinueTimerSearch;\n}\n\n/**\nRemoves the DPC stored in the Prcb structure, i.e. NULLs it.\nAccording to HalpMcaQueueDpc, a NULL DPC does not result in an error.\n*/\nBOOLEAN\nRemovePrcbDpc(\n    VOID\n)\n{\n    PKDPC *PrcbDpc = Flows::PrcbDpc::GetTargetDpc();\n    \n    if (!PrcbDpc)\n        return FALSE;\n\n    if (!*PrcbDpc)\n        return TRUE;\n\n    Log(\"Removed Prcb DPC: %p\\n\", *PrcbDpc);\n\n    *PrcbDpc = NULL;\n\n    return TRUE;\n}\n\nBOOLEAN\nPG::Disable::Execute(\n\tVOID\n)\n{\n    /* Disable all PG related Timers (prevents ContextAware/Unaware flows) */\n    SearchSystemTimers(&RemoveTimer);\n\n    /* Remove DPC from Prcb (prevents Prcb DPC flow) */\n    if (!RemovePrcbDpc())\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID\nPG::Disable::Unload(\n    VOID\n)\n{\n    /* Nothing to do here */\n}\n"
  },
  {
    "path": "PatchGuardBypass/src/core/features/Evade.cpp",
    "content": "#include \"../PatchGuard.h\"\n#include \"../timers/Timer.h\"\n#include \"../flows/Flows.h\"\n#include \"../../utils/Log/Log.h\"\n#include <ntddk.h>\n\n/**\nMacro to convert milliseconds to hecto-nanoseconds, i.e. 100-nanoseconds.\nThis is the term for Windows interrupt time units.\n*/\n#define MS_TO_HNS(x) (x * 10000)\n\n/* Initial StopTimer expiry cooldown (DueTime parameter) */\n#define STOP_INITIAL_COOLOWN 1000\n/* StopTimer cooldown after initial expiry (Period parameter) */\n#define STOP_COOLOWN 500\n\n/**\nGlobal context for the evasion feature.\n*/\ntypedef struct _EVADE_CONTEXT\n{\n    /*\n    Array of PG-related KTIMERs. The array can contain up to 10 entries.\n    I'm using an array for this because I'm not 100% confident that only 2 timers\n    can exist at a time. If that's the case, this design is redundant and will change.\n    */\n#define MAX_PG_TIMERS 10\n    PKTIMER Timers[MAX_PG_TIMERS];\n    UINT32 TimerCount;\n    /* The expiration time of the Timer we're currently avoiding */\n    ULONGLONG LastAvoidedExpiration;\n    /* Define a Timer for starting the evasion process */\n    KDPC StartEvasionDpc;\n    KTIMER StartEvasionTimer;\n    /* Define a Timer for stopping the evasion process */\n    KDPC StopEvasionDpc;\n    KTIMER StopEvasionTimer;\n} EVADE_CONTEXT, PEVADE_CONTEXT;\n\nEVADE_CONTEXT g_EvadeContext = { 0 };\n\nVOID\nInsertTimerToContext(\n    PKTIMER Timer\n)\n{\n    if (g_EvadeContext.TimerCount >= MAX_PG_TIMERS)\n    {\n        g_EvadeContext.TimerCount++;\n        return;\n    }\n\n    g_EvadeContext.Timers[g_EvadeContext.TimerCount++] = Timer;\n}\n\nFORCEINLINE\nBOOLEAN\nTimerOverflow(\n    VOID\n)\n{\n    return g_EvadeContext.TimerCount > MAX_PG_TIMERS;\n}\n\n/**\nFor each Timer encountered, checks if it's PG related and saves it if so.\nCompatible with the TIMER_CALLBACK signature, passed to IterateSystemTimers.\n*/\nTIMER_SEARCH_STATUS\nFindTimer(\n    PKTIMER Timer,\n    PKDPC DecodedDpc\n)\n{\n    if (Flows::ContextAwareTimer::IsTargetTimer(Timer, DecodedDpc))\n    {\n        InsertTimerToContext(Timer);\n    }\n\n    if (Flows::ContextUnawareTimer::IsTargetTimer(Timer, DecodedDpc))\n    {\n        InsertTimerToContext(Timer);\n    }\n\n    return ContinueTimerSearch;\n}\n\nBOOLEAN\nUpdateTimers(\n    VOID\n)\n{\n    /* Reset all previously found Timers */\n    g_EvadeContext.TimerCount = 0;\n    /* Find all PG related Timers */\n    SearchSystemTimers(&FindTimer);\n\n    if (TimerOverflow())\n        return FALSE;\n\n    return TRUE;\n}\n\nULONGLONG\nEarliestTimerExpiration(\n    VOID\n)\n{\n    ULONGLONG earliestTime = MAXLONGLONG;\n\n    for (UINT32 i = 0; i < g_EvadeContext.TimerCount; i++)\n    {\n        PKTIMER currentTimer = g_EvadeContext.Timers[i];\n\n        if (!currentTimer)\n            continue;\n\n        ULONGLONG currentTime = currentTimer->DueTime.QuadPart;\n\n        if (currentTimer->Period)\n        {\n            /* BP if Timer is periodical. Need to figure out how to calculate the DueTime */\n            DbgBreakPoint();\n        }\n\n        if (currentTime < earliestTime)\n            earliestTime = currentTime;\n    }\n\n    return earliestTime;\n}\n\n/* Start hiding a bit earlier than the Timers expire */\n#define EVASION_TIMER_UNDERSHOOT 500\n\nBOOLEAN\nSetStopEvasionTimer(\n    VOID\n);\n\nVOID\nStartEvasion(\n    PKDPC Dpc,\n    PVOID DeferredContext,\n    PVOID SystemArgument1,\n    PVOID SystemArgument2\n)\n{\n    UNREFERENCED_PARAMETER(Dpc);\n    UNREFERENCED_PARAMETER(DeferredContext);\n    UNREFERENCED_PARAMETER(SystemArgument1);\n    UNREFERENCED_PARAMETER(SystemArgument2);\n\n    // DisableAllPatches();\n\n    SetStopEvasionTimer();\n}\n\n#define AVOIDING_TIMER ((PVOID) 0x1)\n#define AVOIDING_DPC ((PVOID) 0x0)\n\nBOOLEAN\nSetStartEvasionTimer(\n    BOOLEAN RequiresUpdate\n)\n{\n    /* If we require an update and the update failed */\n    if (RequiresUpdate && !UpdateTimers())\n        return FALSE;\n\n    ULONGLONG timerExpiration = EarliestTimerExpiration();\n    ULONG dpcExecution = Flows::PrcbDpc::NextExecutionTime();\n\n    if (timerExpiration < dpcExecution)\n    {\n        g_EvadeContext.LastAvoidedExpiration = timerExpiration;\n        /* Indicate to the DPC that we're avoiding a Timer, and not the Prcb DPC */\n        g_EvadeContext.StartEvasionDpc.SystemArgument1 = AVOIDING_TIMER;\n    }\n    else\n    {\n        g_EvadeContext.LastAvoidedExpiration = dpcExecution;\n        /* Indicate to the DPC that we're avoiding the Prcb DPC, and not a Timer */\n        g_EvadeContext.StartEvasionDpc.SystemArgument1 = AVOIDING_DPC;\n    }\n\n    LARGE_INTEGER startEvasionTime;\n    startEvasionTime.QuadPart = g_EvadeContext.LastAvoidedExpiration - EVASION_TIMER_UNDERSHOOT;\n\n    if (KeSetTimer(\n        &g_EvadeContext.StartEvasionTimer,\n        startEvasionTime,\n        &g_EvadeContext.StartEvasionDpc\n    ))\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID\nStopEvasion(\n    VOID\n)\n{\n    // EnableAllPatches();\n\n    SetStartEvasionTimer(FALSE);\n}\n\nVOID\nTryStopEvasion(\n    PKDPC Dpc,\n    PVOID DeferredContext,\n    PVOID IsAvoidingTimer,\n    PVOID pvAttemptCount\n)\n{\n    UNREFERENCED_PARAMETER(Dpc);\n    UNREFERENCED_PARAMETER(DeferredContext);\n\n    /* Convert from PVOID to UINT64 */\n    UINT64 attemptCount = (UINT64) pvAttemptCount;\n\n    if (attemptCount >= 5)\n    {\n        /*\n        BP if we've attempted & failed more than 5 times.\n        TODO: Better error handling (log error to user, exit program?)\n        */\n        DbgBreakPoint();\n        goto Exit;\n    }\n\n    /* Increment attempt count. Why am I using global variables smh */\n    g_EvadeContext.StopEvasionDpc.SystemArgument2 = (PVOID) (attemptCount + 1);\n\n    /* Timer count before evasion started */\n    UINT32 prevTimerCount = g_EvadeContext.TimerCount;\n\n    /* Search again for all PG related Timers */\n    if (!UpdateTimers())\n        return;\n    \n    /* If we're avoiding a Timer, ensure it was actually removed (it's no longer the earliest) */\n    if (IsAvoidingTimer == AVOIDING_TIMER &&\n        g_EvadeContext.LastAvoidedExpiration == EarliestTimerExpiration())\n    {\n        /* TODO: Maybe do other stuff, we can sleep longer or something */\n        return;\n    }\n\n    /* Check that a new replacement Timer was inserted, i.e. execution finished */\n    if (prevTimerCount == g_EvadeContext.TimerCount)\n    /* && CurrentTime < GetEarliestTimer(), make sure next Timer isn't already executing? not sure if necessary */\n    {\n        StopEvasion();\n\n        Exit:\n        /* If we finished avoiding, cancel the Timer */\n        KeCancelTimer(&g_EvadeContext.StopEvasionTimer);\n    }\n}\n\nBOOLEAN\nSetStopEvasionTimer(\n    VOID\n)\n{\n    LARGE_INTEGER dueTime;\n    dueTime.QuadPart = /* CurrentTime + */ MS_TO_HNS(STOP_INITIAL_COOLOWN);\n\n    /* Notify StopEvasionDpc whether we're avoiding a Timer or the Prcb DPC */\n    g_EvadeContext.StopEvasionDpc.SystemArgument1 = g_EvadeContext.StartEvasionDpc.SystemArgument1;\n    /* Initialize attempt count to zero */\n    g_EvadeContext.StartEvasionDpc.SystemArgument2 = 0;\n\n    if (KeSetTimerEx(\n        &g_EvadeContext.StopEvasionTimer,\n        dueTime,\n        STOP_COOLOWN,\n        &g_EvadeContext.StopEvasionDpc\n    ))\n        return FALSE;\n\n    return TRUE;\n}\n\nBOOLEAN\nPrepareContext(\n    VOID\n)\n{\n    KeInitializeDpc(\n        &g_EvadeContext.StartEvasionDpc,\n        StartEvasion,\n        NULL\n    );\n\n    KeInitializeTimerEx(\n        &g_EvadeContext.StartEvasionTimer,\n        NotificationTimer\n    );\n\n    KeInitializeDpc(\n        &g_EvadeContext.StopEvasionDpc,\n        TryStopEvasion,\n        NULL\n    );\n\n    KeInitializeTimerEx(\n        &g_EvadeContext.StopEvasionTimer,\n        NotificationTimer\n    );\n\n    return TRUE;\n}\n\nBOOLEAN\nPG::Evade::Execute(\n    VOID\n)\n{\n    if (!PrepareContext())\n        return FALSE;\n\n    if (!SetStartEvasionTimer(TRUE))\n        return FALSE;\n\n    return TRUE;\n}\n\nVOID\nPG::Evade::Unload(\n    VOID\n)\n{\n    /* Cancel current Timers */\n    KeCancelTimer(&g_EvadeContext.StartEvasionTimer);\n    KeCancelTimer(&g_EvadeContext.StopEvasionTimer);\n}\n"
  },
  {
    "path": "PatchGuardBypass/src/core/features/Verify.cpp",
    "content": "#include \"../PatchGuard.h\"\n#include \"../timers/Timer.h\"\n#include \"../flows/Flows.h\"\n#include \"../../utils/Log/Log.h\"\n#include <ntddk.h>\n\ntypedef struct _VERIFY_CONTEXT\n{\n    BOOLEAN bContextAwareTimer;\n    BOOLEAN bContextUnawareTimer;\n    BOOLEAN bPrcbDpc;\n} VERIFY_CONTEXT, *PVERIFY_CONTEXT;\n\nVERIFY_CONTEXT g_VerifyContext = { FALSE };\n\n/**\nFor each Timer encountered, checks if it's PG related and removes it if so.\nCompatible with the TIMER_CALLBACK signature, passed to IterateSystemTimers.\n*/\nTIMER_SEARCH_STATUS\nVerifyTimer(\n    PKTIMER Timer,\n    PKDPC DecodedDpc\n)\n{\n    if (Flows::ContextAwareTimer::IsTargetTimer(Timer, DecodedDpc))\n    {\n        g_VerifyContext.bContextAwareTimer = TRUE;\n    }\n\n    if (Flows::ContextUnawareTimer::IsTargetTimer(Timer, DecodedDpc))\n    {\n        g_VerifyContext.bContextUnawareTimer = TRUE;\n    }\n\n    return ContinueTimerSearch;\n}\n\nBOOLEAN\nVerifyPrcbDpc(\n    VOID\n)\n{\n    PKDPC *PrcbDpc = Flows::PrcbDpc::GetTargetDpc();\n\n    if (!PrcbDpc)\n        return FALSE;\n\n    if (!*PrcbDpc)\n        return FALSE;\n\n    return TRUE;\n}\n\nBOOLEAN\nPG::Verify::Execute(\n    VOID\n)\n{\n    /* Verify all PG related Timers exist */\n    SearchSystemTimers(&VerifyTimer);\n\n    /* TODO: Not loving this global context variable */\n    g_VerifyContext.bPrcbDpc = VerifyPrcbDpc();\n\n    return\n        g_VerifyContext.bContextAwareTimer &&\n        g_VerifyContext.bContextUnawareTimer &&\n        g_VerifyContext.bPrcbDpc;\n}\n\nVOID\nPG::Verify::Unload(\n    VOID\n)\n{\n    /* Nothing to do here */\n}\n"
  },
  {
    "path": "PatchGuardBypass/src/core/flows/Flows.cpp",
    "content": "#include \"Flows.h\"\n#include <ntddk.h>\n#include \"../symbols/Globals.h\"\n#include \"../symbols/Offsets.h\"\n\nBOOLEAN\nFlows::ContextAwareTimer::IsTargetTimer(\n\tPKTIMER Timer,\n\tPKDPC DecodedDpc\n)\n{\n\tUNREFERENCED_PARAMETER(Timer);\n\n    if (!MmIsAddressValid(DecodedDpc))\n        return FALSE;\n\n    INT64 SpecialBit = (INT64) DecodedDpc->DeferredContext >> 47;\n    return SpecialBit != 0 && SpecialBit != -1;\n}\n\nBOOLEAN\nFlows::ContextUnawareTimer::IsTargetTimer(\n\tPKTIMER Timer,\n\tPKDPC DecodedDpc\n)\n{\n\tUNREFERENCED_PARAMETER(Timer);\n\n\tif (!MmIsAddressValid(DecodedDpc))\n\t\treturn FALSE;\n\n\treturn DecodedDpc->DeferredRoutine == Globals::Functions::CcBcbProfiler;\n}\n\nULONG\nFlows::PrcbDpc::NextExecutionTime(\n\tVOID\n)\n{\n\treturn *reinterpret_cast<PULONG>((PBYTE) *Globals::Variables::HalpClockTimer + Offsets::HalpClockTimer::NextExecutionTime);\n}\n\nPKDPC *\nFlows::PrcbDpc::GetTargetDpc(\n\tVOID\n)\n{\n\tPKPRCB Prcb = Globals::Functions::KeGetPrcb(0);\n\t\n\tif (!Prcb)\n\t\treturn NULL;\n\n\treturn reinterpret_cast<PKDPC *>((PBYTE) Prcb + Offsets::Prcb::PatchGuardDpc);\n}\n"
  },
  {
    "path": "PatchGuardBypass/src/core/flows/Flows.h",
    "content": "#pragma once\n#include <ntdef.h>\n\n/* Forward declaration of KTIMER struct */\ntypedef struct _KTIMER\nKTIMER, *PKTIMER;\n/* Forward declaration of KDPC struct */\ntypedef struct _KDPC\nKDPC, *PKDPC;\n\n/**\nContains sub-namespaces defining each execution flow for PatchGuard checks.\n*/\nnamespace Flows\n{\n\t/**\n\tPatchGuard issues a check through a Timer inserted to Prcb index 0.\n\tThis Timer receives the PatchGuard Context struct as a parameter and uses it.\n\t*/\n\tnamespace ContextAwareTimer\n\t{\n\t\tBOOLEAN\n\t\tIsTargetTimer(\n\t\t\tPKTIMER Timer,\n\t\t\tPKDPC DecodedDpc\n\t\t);\n\t};\n\n\t/**\n\tPatchGuard issues a check through a Timer inserted to Prcb index 0.\n\tThis Timer does not receive the PatchGuard Context struct as a parameter.\n\tIt is more static & less complex than the context aware Timer.\n\t*/\n\tnamespace ContextUnawareTimer\n\t{\n\t\tBOOLEAN\n\t\tIsTargetTimer(\n\t\t\tPKTIMER Timer,\n\t\t\tPKDPC DecodedDpc\n\t\t);\n\t};\n\n\t/**\n\tPatchGuad issues a check through a DPC saved to Prcb index 0.\n\tThis DPC is inserted to the HalReserved[7] field from FsRtlMdlReadCompleteDevEx.\n\tIt is executed every 2 minutes from HalpMcaQueueDpc.\n\t*/\n\tnamespace PrcbDpc\n\t{\n\t\t/**\n\t\t@return The next execution time of the DPC stored in the Prcb.\n\t\tThis value is returned as an interrupt timestamp.\n\t\t*/\n\t\tULONG\n\t\tNextExecutionTime(\n\t\t\tVOID\n\t\t);\n\n\t\t/**\n\t\t@return Pointer to the target DPC stored in the Prcb.\n\t\tThis returns a pointer to allow easily overwriting the DPC.\n\t\t*/\n\t\tPKDPC *\n\t\tGetTargetDpc(\n\t\t\tVOID\n\t\t);\n\t};\n};\n"
  },
  {
    "path": "PatchGuardBypass/src/core/symbols/Globals.cpp",
    "content": "#include \"Globals.h\"\n\n/*\nJust grouping together all offsets into a single namespace.\nNot necessary, but more convenient for modifying and hiding the vars from global scope.\n*/\nnamespace GlobalOffsets\n{\n\t/* Keys used for decoding/encoding DPCs within KTIMERs */\n\tconstexpr UINT64 KiWaitAlways = 0xCFC9F8;\n\tconstexpr UINT64 KiWaitNever = 0xCFC7F8;\n\t/* Number of processor on the system. Also indicates number of PRCBs */\n\tconstexpr UINT64 KeNumberProcessors_0 = 0xCFC404;\n\tconstexpr UINT64 HalpClockTimer = 0xC4BFC8;\n\n\t/* Offset of some known routine that we can use to calculate ImageBase */\n\tconstexpr UINT64 KeBugCheckEx = 0x3f5210;\n\t/* Undocumented function that returns the Prcb at the given index */\n\tconstexpr UINT64 KeGetPrcb = 0x32DAD0;\n\tconstexpr UINT64 CcBcbProfiler = 0x3D7330;\n};\n\n/**\nTemplate function to return a Global variable.\n@param Type is the type of the variable.\n@param GlobalOffset is the offset of the variable from the image base.\n*/\ntemplate <typename Type, UINT64 GlobalOffset>\nType GetGlobal(UINT64 ImageBase)\n{\n\treturn reinterpret_cast<Type>(ImageBase + GlobalOffset);\n}\n\n/**\nInitializes all Globals.\n*/\nBOOLEAN\nGlobals::Initialize(\n\tVOID\n)\n{\n\t/* Not sure if this is ok or completely mentally ill */\n\tUINT64 ImageBase = (UINT64) &KeBugCheckEx - GlobalOffsets::KeBugCheckEx;\n\n\tGlobals::Variables::KiWaitAlways = GetGlobal<PINT64, GlobalOffsets::KiWaitAlways>(ImageBase);\n\tGlobals::Variables::KiWaitNever = GetGlobal<PINT64, GlobalOffsets::KiWaitNever>(ImageBase);\n\tGlobals::Variables::KeNumberProcessors_0 = GetGlobal<PULONG, GlobalOffsets::KeNumberProcessors_0>(ImageBase);\n\tGlobals::Variables::HalpClockTimer = GetGlobal<PVOID *, GlobalOffsets::HalpClockTimer>(ImageBase);\n\n\tGlobals::Functions::KeGetPrcb = GetGlobal<PKPRCB (__fastcall *) (ULONG), GlobalOffsets::KeGetPrcb>(ImageBase);\n\tGlobals::Functions::CcBcbProfiler = GetGlobal<PVOID, GlobalOffsets::CcBcbProfiler>(ImageBase);\n\n\treturn TRUE;\n}\n\n/* Define all externs */\nPINT64 Globals::Variables::KiWaitAlways = NULL;\nPINT64 Globals::Variables::KiWaitNever = NULL;\nPULONG Globals::Variables::KeNumberProcessors_0 = NULL;\nPVOID *Globals::Variables::HalpClockTimer = NULL;\nPKPRCB (__fastcall *Globals::Functions::KeGetPrcb) (ULONG) = NULL;\nPVOID Globals::Functions::CcBcbProfiler = NULL;\n"
  },
  {
    "path": "PatchGuardBypass/src/core/symbols/Globals.h",
    "content": "#pragma once\n#include <ntddk.h>\n\n/* The Kernel KPRCB structure is undocumented, so we'll treat it as a void-pointer */\ntypedef PVOID PKPRCB;\n\nnamespace Globals\n{\n\tnamespace Variables\n\t{\n\t\textern PINT64 KiWaitAlways;\n\t\textern PINT64 KiWaitNever;\n\t\textern PULONG KeNumberProcessors_0;\n\t\textern PVOID *HalpClockTimer;\n\t};\n\n\tnamespace Functions\n\t{\n\t\t/* Function pointer to KeGetPrcb, which is undocumented */\n\t\textern PKPRCB (__fastcall *KeGetPrcb) (ULONG PrcbNumber);\n\t\t/* Invoked by the Context-Unaware Timers */\n\t\textern PVOID CcBcbProfiler;\n\t};\n\n\tBOOLEAN\n\tInitialize(\n\t\tVOID\n\t);\n};\n"
  },
  {
    "path": "PatchGuardBypass/src/core/symbols/Offsets.cpp",
    "content": "#include \"Offsets.h\"\n\nUINT32 Offsets::Prcb::TimerTable = 0x3940;\nUINT32 Offsets::Prcb::PatchGuardDpc = 0x80;\n\nUINT32 Offsets::HalpClockTimer::NextExecutionTime = 0x3C;\n"
  },
  {
    "path": "PatchGuardBypass/src/core/symbols/Offsets.h",
    "content": "#pragma once\n#include <windef.h>\n\nnamespace Offsets\n{\n\t/* Offsets to fields within a Prcb (struct _KPRCB) */\n\tnamespace Prcb\n\t{\n\t\t/* Offset to TimerTable field */\n\t\textern UINT32 TimerTable;\n\t\textern UINT32 PatchGuardDpc;\n\t};\n\n\tnamespace HalpClockTimer\n\t{\n\t\textern UINT32 NextExecutionTime;\n\t};\n};\n"
  },
  {
    "path": "PatchGuardBypass/src/core/timers/Timer.cpp",
    "content": "#include \"Timer.h\"\n#include <ntifs.h>\n#include <ntddk.h>\n#include \"../symbols/Offsets.h\"\n#include \"../symbols/Globals.h\"\n\n/**\n* Kernel structure defining an entry within a KTIMER_TABLE.\n* Each entry contains a linked-list of KTIMERs.\n*/\ntypedef struct _KTIMER_TABLE_ENTRY\n{\n    /* Locked used to synchronize access to the entry */\n    unsigned __int64 Lock;\n    /* Head of a linked-list of KTIMERs */\n    LIST_ENTRY Entry;\n    /* Earliest expiration time within this entry's Timers (used in insertion process, iirc) */\n    ULARGE_INTEGER Time;\n} KTIMER_TABLE_ENTRY, *PKTIMER_TABLE_ENTRY;\n\n/* Size of the TimerExpiry array */\n#define TIMER_EXPIRY_SIZE 64\n/* Size of the TimerEntries array */\n#define TIMER_ENTRIES_SIZE 256\n\ntypedef struct _KTIMER_TABLE\n{\n    /* An array of KTIMER pointers, representing all expired Timers that need processing */\n    PKTIMER TimerExpiry[TIMER_EXPIRY_SIZE];\n    /*\n    A 2-dimensional array of KTIMER_TABLE_ENTRIES, containing all user-mode & kernel-mode\n    (I think?) non-expired Timers. TimerEntries[0] is for kernel-mode, TimerEntries[1] for user-mode.\n    */\n    KTIMER_TABLE_ENTRY TimerEntries[2][TIMER_ENTRIES_SIZE];\n    /* TimerState structure (size=0x18), we do not care for this */\n    char TableState[0x18]; \n} KTIMER_TABLE, *PKTIMER_TABLE;\n\n/* Retrieves the TimerTable field of a KPRCB */\nPKTIMER_TABLE\nGetTimerTable(\n    PKPRCB Prcb\n)\n{\n    return (PKTIMER_TABLE) ((PCHAR) Prcb + Offsets::Prcb::TimerTable);\n}\n\n/*\nReturns the decoded pointer to the DPC stored in a KTIMER structre.\nThese DPC pointers are encoded during insertion of the Timers.\nThe encoding/decoding can be seen in KTIMER-related functions in ntoskrnl.exe.\n*/\n#define DECODE_TIMER_DPC(Timer) \\\n    (PKDPC) (*Globals::Variables::KiWaitAlways ^ _byteswap_uint64( \\\n        (UINT64) Timer ^ _rotl64( \\\n            (INT64) Timer->Dpc ^ *Globals::Variables::KiWaitNever, \\\n            (UCHAR) *Globals::Variables::KiWaitNever \\\n        )))\n\n/** \nIterates over all entries of a linked-list of KTIMERs.\nFor each KTIMER, the given callback function is invoked.\n@param TimerListHead is the head entry of the list, from a KTIMER_TABLE_ENTRY structure.\n@param TimerCallbacks is a fixed array of TIMER_CALLBACK routines, invoked for each KTIMER.\n@return search instructions for the caller.\n*/\nTIMER_SEARCH_STATUS\nSearchTimerList(\n    PKTIMER_TABLE_ENTRY TimerTableEntry,\n    PTIMER_CALLBACK TimerCallback\n)\n{\n    /*\n    TODO: Acquire & Release SpinLock of TimerTableEntry.\n    */\n\n    PLIST_ENTRY pListEntry = TimerTableEntry->Entry.Flink;\n\n    /* As long as the current entry is valid and we haven't reached the end */\n    while (pListEntry && pListEntry != &TimerTableEntry->Entry)\n    {\n        /* Get the KTIMER that contains the current list entry */\n        PKTIMER pTimer = CONTAINING_RECORD(\n            pListEntry,\n            KTIMER,\n            TimerListEntry\n        );\n\n        /* Get the decoded DPC */\n        PKDPC pDpc = DECODE_TIMER_DPC(pTimer);\n\n        /* Invoke registered callback */\n        if (TimerCallback(pTimer, pDpc) == StopTimerSearch)\n            return StopTimerSearch;\n\n        /* Advance to the next Timer entry */\n        pListEntry = pListEntry->Flink;\n    }\n\n    return ContinueTimerSearch;\n}\n\n/**\nIterates all pending KTIMERs in the given KTIMER_TABLE.\n@param TimerTable is the KTIMER_TABLE we want to iterate.\n@param TimerCallbacks is a fixed array of TIMER_CALLBACK routines, invoked for each KTIMER.\n*/\nVOID\nSearchTimerTable(\n    PKTIMER_TABLE TimerTable,\n    PTIMER_CALLBACK TimerCallback\n)\n{\n    /* Get the array of kernel-mode KTIMER_TABLE_ENTRYs */\n    PKTIMER_TABLE_ENTRY pKernelEntries = TimerTable->TimerEntries[KernelMode];\n    /* Get the array of user-mode KTIMER_TABLE_ENTRYs */\n    PKTIMER_TABLE_ENTRY pUserEntries = TimerTable->TimerEntries[UserMode];\n\n    /* Iterate over all KTIMER_TABLE_ENTRYs in both arrays */\n    for (USHORT i = 0; i < TIMER_ENTRIES_SIZE; i++)\n    {\n        /* Iterate linked-list of KTIMERs within each KTIMER_TABLE_ENTRY */\n\n        if (SearchTimerList(&pKernelEntries[i], TimerCallback) == StopTimerSearch)\n            break;\n\n        if (SearchTimerList(&pUserEntries[i], TimerCallback) == StopTimerSearch)\n            break;\n    }\n}\n\n/**\nIterates over all Timers in the system, invokes the given callbacks for each Timer.\n@param TimerCallbacks is the fixed array of callbacks to be invoked.\n*/\nBOOLEAN\nSearchSystemTimers(\n    PTIMER_CALLBACK TimerCallback\n)\n{\n    /* Get the matching KPRCB struct (current code is wrong, just a placeholder) */\n    PKPRCB pPrcb = Globals::Functions::KeGetPrcb(0);\n\n    if (!pPrcb)\n        return FALSE;\n\n    /* Get the KPRCB's TimerTable, then iterate its Timers */\n    SearchTimerTable(GetTimerTable(pPrcb), TimerCallback);\n\n    return TRUE;\n}\n"
  },
  {
    "path": "PatchGuardBypass/src/core/timers/Timer.h",
    "content": "#pragma once\n#include <ntdef.h>\n\n/* Forward declaration of KTIMER struct */\ntypedef struct _KTIMER\nKTIMER, *PKTIMER;\n/* Forward declaration of KDPC struct */\ntypedef struct _KDPC\nKDPC, *PKDPC;\n\n/**\nEnum returned by TIMER_CALLBACK to indicate how the search should continue.\n*/\ntypedef enum _TIMER_SEARCH_STATUS\n{\n    StopTimerSearch,\n    ContinueTimerSearch,\n} TIMER_SEARCH_STATUS, *PTIMER_SEARCH_STATUS;\n\n/**\nSignature of a callback routine for each KTIMER encountered.\n@param Timer is the KTIMER encountered.\n@param DecodedDpc is the decoded DPC used by the Timer.\n@return TRUE if execution should continue, FASLE if it should stop.\n*/\ntypedef\nTIMER_SEARCH_STATUS\nTIMER_CALLBACK(\n    PKTIMER Timer,\n    PKDPC DecodedDpc\n);\ntypedef TIMER_CALLBACK *PTIMER_CALLBACK;\n\n/**\nIterates over all Timers in the system, invokes the given callbacks for each Timer.\n*/\nBOOLEAN\nSearchSystemTimers(\n    PTIMER_CALLBACK TimerCallback\n);\n"
  },
  {
    "path": "PatchGuardBypass/src/main.cpp",
    "content": "#pragma once\n#include <ntifs.h>\n#include <ntddk.h>\n#include \"utils/log/Log.h\"\n#include \"core/PatchGuard.h\"\n\nVOID\nDriverUnload(\n    _In_ PDRIVER_OBJECT pDriverObject\n)\n{\n    UNREFERENCED_PARAMETER(pDriverObject);\n}\n\n#include \"core/symbols/Globals.h\"\n\nEXTERN_C\nNTSTATUS\nDriverEntry(\n    _In_ PDRIVER_OBJECT DriverObject,\n    _In_ PUNICODE_STRING RegistryPath\n)\n{\n    UNREFERENCED_PARAMETER(DriverObject);\n    UNREFERENCED_PARAMETER(RegistryPath);\n\n    DriverObject->DriverUnload = DriverUnload;\n\n    Globals::Initialize();\n\n    PG::Disable::Execute();\n\n    Log(\"%p\\n\", Globals::Functions::CcBcbProfiler);\n\n    return STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "PatchGuardBypass.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.32802.440\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"PatchGuardBypass\", \"PatchGuardBypass\\PatchGuardBypass.vcxproj\", \"{57A68F53-C563-405D-B2E1-C66585DA64E4}\"\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{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|ARM.Deploy.0 = Debug|ARM\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|x64.Build.0 = Debug|x64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|x86.Build.0 = Debug|Win32\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Debug|x86.Deploy.0 = Debug|Win32\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|ARM.Build.0 = Release|ARM\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|ARM.Deploy.0 = Release|ARM\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|x64.ActiveCfg = Release|x64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|x64.Build.0 = Release|x64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|x64.Deploy.0 = Release|x64\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|x86.ActiveCfg = Release|Win32\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|x86.Build.0 = Release|Win32\n\t\t{57A68F53-C563-405D-B2E1-C66585DA64E4}.Release|x86.Deploy.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {8AD89A08-9F84-4021-B1FA-0CA109C2D418}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "# **PatchGuardBypass**\n\nI've had the delightful opportunity to research PatchGuard for the past couple of weeks, and it was mostly pretty fun.\n\nI'll be writing a paper about my experience and my findings, hopefully it could help anyone else who's hesitant to do something like this :)\n\nIn the meantime, I'll also be writing a dynamic PatchGuard bypass for modern Windows 10 systems. **This is still a bit far from done, so please don't expect anything to work at this stage.**\nHopefully when it is finished it'll include 3 main features:\n\n### **Disable**\nDisables PatchGuard completely and prevents its execution.\n\n### **Evade** \nEvades PatchGuard detection by reverting patches prior to the PG check times.\n\n### **Verify**\nChecks if PatchGuard has been disabled on the system. Basically the opposite of Disabling.\n\n**DISCLAMER: The feature names are work-in-progress, my sincerest apologies for the poor choice <3**\n\n"
  }
]