mirror of
https://github.com/winterknife/EVENSTAR
synced 2026-06-21 14:13:51 +00:00
added KernelWriteProtect project
This commit is contained in:
@@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GetCurrentProcessorNumber",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KernelToUserInjector", "KernelToUserInjector\KernelToUserInjector.vcxproj", "{455ED3CD-DF55-4D4F-8C22-895E06AE469B}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KernelToUserInjector", "KernelToUserInjector\KernelToUserInjector.vcxproj", "{455ED3CD-DF55-4D4F-8C22-895E06AE469B}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KernelWriteProtect", "KernelWriteProtect\KernelWriteProtect.vcxproj", "{E81DEF46-8802-4B42-AC86-09E3052D488F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Release|x64 = Release|x64
|
Release|x64 = Release|x64
|
||||||
@@ -33,6 +35,9 @@ Global
|
|||||||
{455ED3CD-DF55-4D4F-8C22-895E06AE469B}.Release|x64.ActiveCfg = Release|x64
|
{455ED3CD-DF55-4D4F-8C22-895E06AE469B}.Release|x64.ActiveCfg = Release|x64
|
||||||
{455ED3CD-DF55-4D4F-8C22-895E06AE469B}.Release|x64.Build.0 = Release|x64
|
{455ED3CD-DF55-4D4F-8C22-895E06AE469B}.Release|x64.Build.0 = Release|x64
|
||||||
{455ED3CD-DF55-4D4F-8C22-895E06AE469B}.Release|x64.Deploy.0 = Release|x64
|
{455ED3CD-DF55-4D4F-8C22-895E06AE469B}.Release|x64.Deploy.0 = Release|x64
|
||||||
|
{E81DEF46-8802-4B42-AC86-09E3052D488F}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{E81DEF46-8802-4B42-AC86-09E3052D488F}.Release|x64.Build.0 = Release|x64
|
||||||
|
{E81DEF46-8802-4B42-AC86-09E3052D488F}.Release|x64.Deploy.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// File: BaseDataTypes.h
|
||||||
|
//
|
||||||
|
// Author: winterknife
|
||||||
|
//
|
||||||
|
// Description: Type definitions for common Windows base data types made
|
||||||
|
// for maintaining uniformity across all User Mode and Kernel Mode code
|
||||||
|
//
|
||||||
|
// Modifications:
|
||||||
|
// 2021-07-31 Created
|
||||||
|
// 2022-08-13 Updated
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Pragmas
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Type definitions
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma region TYPEDEFS
|
||||||
|
|
||||||
|
// 8-bit unsigned integer, range = 0 - 255, unsigned char
|
||||||
|
typedef unsigned __int8 BYTE, *PBYTE;
|
||||||
|
|
||||||
|
// 16-bit unsigned integer, range = 0 - 65535, unsigned short
|
||||||
|
typedef unsigned __int16 WORD, *PWORD;
|
||||||
|
|
||||||
|
// 32-bit unsigned integer, range = 0 - 4294967295, unsigned int or unsigned long
|
||||||
|
typedef unsigned long DWORD, *PDWORD;
|
||||||
|
|
||||||
|
// 64-bit unsigned integer, range = 0 - 18446744073709551615, unsigned long long
|
||||||
|
typedef unsigned __int64 QWORD, *PQWORD;
|
||||||
|
|
||||||
|
// Should be TRUE(1) or FALSE(0), unsigned char or bool
|
||||||
|
typedef unsigned __int8 BOOLEAN, *PBOOLEAN;
|
||||||
|
|
||||||
|
// 8-bit UTF-8/Multibyte/ANSI character, char
|
||||||
|
typedef __int8 CHAR, *PCHAR;
|
||||||
|
|
||||||
|
// 16-bit UTF-16/Wide/UNICODE character, unsigned short
|
||||||
|
typedef wchar_t WCHAR, *PWCHAR;
|
||||||
|
|
||||||
|
// Pointer to any type, size = 4 bytes or 8 bytes depending on code bitness
|
||||||
|
typedef void* PVOID;
|
||||||
|
|
||||||
|
// Pointer to a constant of any type
|
||||||
|
typedef const void* PCVOID;
|
||||||
|
|
||||||
|
// Pointer to constant null-terminated string of ANSI characters
|
||||||
|
typedef _Null_terminated_ const __int8* PCSTR;
|
||||||
|
|
||||||
|
// Pointer to constant null-terminated string of UNICODE characters
|
||||||
|
typedef _Null_terminated_ const wchar_t* PCWSTR;
|
||||||
|
|
||||||
|
// Pointer to constant null-terminated string of ANSI or UNICODE characters depending on character encoding scheme
|
||||||
|
#if defined(UNICODE)
|
||||||
|
typedef const __wchar_t* PCTSTR;
|
||||||
|
#else
|
||||||
|
typedef const __int8* PCTSTR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 32-bit or 64-bit unsigned integer, range = 0 - 4294967295 or 18446744073709551615 depending on compiler bitness
|
||||||
|
// Used for casting pointers
|
||||||
|
#if defined(_WIN64)
|
||||||
|
typedef unsigned __int64 DWORD_PTR, *PDWORD_PTR;
|
||||||
|
#else
|
||||||
|
typedef unsigned long DWORD_PTR, *PDWORD_PTR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// File: Common.h
|
||||||
|
//
|
||||||
|
// Author: winterknife
|
||||||
|
//
|
||||||
|
// Description: Contains the common stuff for this project
|
||||||
|
//
|
||||||
|
// Modifications:
|
||||||
|
// 2021-08-21 Created
|
||||||
|
// 2026-05-12 Updated
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Pragmas
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Specify program entry point
|
||||||
|
#pragma comment(linker, "/ENTRY:DriverEntry")
|
||||||
|
|
||||||
|
// Merge sections
|
||||||
|
#if defined (_MSC_VER)
|
||||||
|
#if (_MSC_VER >= 1920)
|
||||||
|
#pragma comment(linker, "/MERGE:_RDATA=.rdata")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Emit error message at compile time if trying to build for 32-bit x86 target
|
||||||
|
#if !defined(_WIN64)
|
||||||
|
#error x86 build target is unsupported!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Includes
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#include <ntifs.h>
|
||||||
|
#include <ntddk.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
#include "BaseDataTypes.h"
|
||||||
|
|
||||||
|
#pragma intrinsic(__stosb)
|
||||||
|
#pragma intrinsic(__movsb)
|
||||||
|
#pragma intrinsic(strlen)
|
||||||
|
#pragma intrinsic(strcmp)
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Macros
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma region MACROS
|
||||||
|
|
||||||
|
// Module name
|
||||||
|
#define __MODULE__ "KernelWriteProtect"
|
||||||
|
|
||||||
|
// Comment out for final build
|
||||||
|
#define DEBUG_BUILD
|
||||||
|
|
||||||
|
// Print debug message macro
|
||||||
|
#ifdef DEBUG_BUILD
|
||||||
|
#define STRIP(...) __VA_ARGS__
|
||||||
|
#define DEBUG_PREFIX "[DBG]: "
|
||||||
|
#define DEBUG_PRINT(_x_, ...) DbgPrint(DEBUG_PREFIX _x_, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DEBUG_PRINT(_x_, ...) void(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pool tag macro in reverse order due to Little Endianness
|
||||||
|
#define __POOLTAG__ 'ONC'
|
||||||
|
|
||||||
|
// Stringizing operator macro
|
||||||
|
#ifndef _CRT_STRINGIZE
|
||||||
|
#define _CRT_STRINGIZE_(x) #x
|
||||||
|
#define _CRT_STRINGIZE(x) _CRT_STRINGIZE_(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get mangled name of a function
|
||||||
|
#define GET_MANGLED_FUNCTION_NAME __pragma(message(__FILE__ _CRT_STRINGIZE((__LINE__): \nfunction:\t) __FUNCSIG__ " is mangled to: " __FUNCDNAME__))
|
||||||
|
|
||||||
|
// To set alternate name of decorated x86 IAT global function pointer
|
||||||
|
#ifdef _X86_
|
||||||
|
// Uses undocumented /ALTERNATENAME linker flag
|
||||||
|
#define ALT_NAME(name, n) __pragma(comment(linker, _CRT_STRINGIZE(/ALTERNATENAME:__imp__##name##@##n####=___imp_##name)))
|
||||||
|
#else
|
||||||
|
#define ALT_NAME(name, n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// To declare/initialize global IAT function pointers for run-time dynamic linking, use on global scope
|
||||||
|
#define IMP_FUNC(name, n) EXTERN_C_START PVOID __imp_##name = NULL; EXTERN_C_END ALT_NAME(name, n)
|
||||||
|
|
||||||
|
// To declare/initialize local function pointers for run-time dynamic linking, use on local scope
|
||||||
|
// Warning: will ignore SAL annotations
|
||||||
|
#define IMP_FUNC_PIC(name) typedef decltype(name) __type_##name; __type_##name* ##name = NULL;
|
||||||
|
|
||||||
|
// Macro to indicate a specific function to the linker as the first in the link order
|
||||||
|
#define CODE_BEGIN code_seg(push, ".text")
|
||||||
|
|
||||||
|
// Macro to indicate the end of the specific function to the linker
|
||||||
|
#define CODE_END code_seg(pop)
|
||||||
|
|
||||||
|
// Macro to disable all compiler optimizations for a specific function
|
||||||
|
#define OPTIMIZATION_OFF optimize("", off)
|
||||||
|
|
||||||
|
// Macro to re-enable/reset compiler optimizations for a specific function
|
||||||
|
#define OPTIMIZATION_ON optimize("", on)
|
||||||
|
|
||||||
|
// Macro to enable compiler optimizations for generating short sequences of machine code for a specific function
|
||||||
|
#if defined(_M_IX86)
|
||||||
|
#define OPTIMIZATION_SIZE optimize("gsy", on)
|
||||||
|
#else
|
||||||
|
#define OPTIMIZATION_SIZE optimize("gs", on)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macro to enable compiler optimizations for generating fast sequences of machine code for a specific function
|
||||||
|
#if defined(_M_IX86)
|
||||||
|
#define OPTIMIZATION_SPEED optimize("gty", on)
|
||||||
|
#else
|
||||||
|
#define OPTIMIZATION_SPEED optimize("gt", on)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macro to fill a block of memory with zeroes given it's address and length in bytes by generating store string instruction(rep stosb)
|
||||||
|
// Enhanced REP STOSB/MOVSB(ERMSB) are only available since Ivy Bridge Intel microarchitecture(2012/2013)
|
||||||
|
// Processors that provide support for enhanced MOVSB/STOSB operations are enumerated by the CPUID feature flag: CPUID:(EAX=7H, ECX=0H):EBX.ERMSB[bit 9] = 1
|
||||||
|
#define ZERO_MEMORY(Destination, Length) __stosb((PBYTE)Destination, 0, Length)
|
||||||
|
|
||||||
|
// Macro to copy a block of memory given it's source address, destination address and the number of bytes to copy by generating move string instruction(rep movsb)
|
||||||
|
#define COPY_MEMORY(Destination, Source, Count) __movsb((PBYTE)Destination, (const PBYTE)Source, Count)
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// C inline routines
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma region INLINES
|
||||||
|
|
||||||
|
/// @brief To compare two blocks of memory and return the number of bytes that match
|
||||||
|
/// @param pcSource1 Pointer to the first block of memory
|
||||||
|
/// @param pcSource2 Pointer to the second block of memory
|
||||||
|
/// @param dwptrLength The number of bytes to compare
|
||||||
|
/// @return Number of bytes in the two blocks that match, if all bytes match up to the specified Length value, the Length value is returned
|
||||||
|
extern "C" __forceinline DWORD_PTR __stdcall compare_memory(_In_ const PVOID pcSource1, _In_ const PVOID pcSource2, _In_ DWORD_PTR dwptrLength) {
|
||||||
|
// Init local variables
|
||||||
|
DWORD_PTR dwptrIndex = 0;
|
||||||
|
|
||||||
|
// Start comparing the two blocks of memory
|
||||||
|
for (dwptrIndex = 0; (dwptrIndex < dwptrLength) && (((PBYTE)pcSource1)[dwptrIndex] == ((PBYTE)pcSource2)[dwptrIndex]); dwptrIndex++);
|
||||||
|
|
||||||
|
return dwptrIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// File: WriteProtectBypass.h
|
||||||
|
//
|
||||||
|
// Author: winterknife
|
||||||
|
//
|
||||||
|
// Description: Header file for WriteProtectBypass.cpp source file
|
||||||
|
//
|
||||||
|
// Modifications:
|
||||||
|
// 2026-05-12 Created
|
||||||
|
// 2026-05-14 Updated
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Pragmas
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Includes
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// C routine declarations
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma region DECLARATIONS
|
||||||
|
|
||||||
|
/// @brief Copies the contents of a source memory block to a destination memory block with write protect bypass using CR0.WP manipulation
|
||||||
|
/// @param pDestination Pointer to the destination memory block to copy the bytes to
|
||||||
|
/// @param pcSource Pointer to the source memory block to copy the bytes from
|
||||||
|
/// @param dwptrLength Number of bytes to copy from the source to the destination
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
EXTERN_C DECLSPEC_NOINLINE VOID __stdcall copy_memory_cr0_wp(
|
||||||
|
_Out_writes_bytes_all_(dwptrLength) VOID* pDestination,
|
||||||
|
_In_reads_bytes_(dwptrLength) CONST VOID* pcSource,
|
||||||
|
_In_ DWORD_PTR dwptrLength
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @brief Copies the contents of a source memory block to a destination memory block with write protect bypass using double mapping
|
||||||
|
/// @param pDestination Pointer to the destination memory block to copy the bytes to
|
||||||
|
/// @param pcSource Pointer to the source memory block to copy the bytes from
|
||||||
|
/// @param dwptrLength Number of bytes to copy from the source to the destination
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
EXTERN_C DECLSPEC_NOINLINE VOID __stdcall copy_memory_double_mapping(
|
||||||
|
_Out_writes_bytes_all_(dwptrLength) VOID* pDestination,
|
||||||
|
_In_reads_bytes_(dwptrLength) CONST VOID* pcSource,
|
||||||
|
_In_ DWORD_PTR dwptrLength
|
||||||
|
);
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{E81DEF46-8802-4B42-AC86-09E3052D488F}</ProjectGuid>
|
||||||
|
<TemplateGuid>{dd38f7fc-d7bd-488b-9242-7d8754cde80d}</TemplateGuid>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
|
||||||
|
<RootNamespace>KernelWriteProtect</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<TargetVersion>Windows10</TargetVersion>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||||
|
<ConfigurationType>Driver</ConfigurationType>
|
||||||
|
<DriverType>WDM</DriverType>
|
||||||
|
<Driver_SpectreMitigation>Spectre</Driver_SpectreMitigation>
|
||||||
|
<ALLOW_DATE_TIME>1</ALLOW_DATE_TIME>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
|
||||||
|
<OutDir>.\Bin\x64\</OutDir>
|
||||||
|
<IntDir>.\Temp\x64\</IntDir>
|
||||||
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
|
<EnableInf2cat>false</EnableInf2cat>
|
||||||
|
<DiagnosticMode>true</DiagnosticMode>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<Optimization>MinSpace</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<ControlFlowGuard>false</ControlFlowGuard>
|
||||||
|
<AdditionalOptions>/KERNEL /homeparams %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||||
|
<EnablePREfast>false</EnablePREfast>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalOptions>/EMITPOGOPHASEINFO /NOVCFEATURE /NOCOFFGRPINFO /FILEALIGN:0x200 /PDBALTPATH:$(ProjectName).pdb /Brepro /RELEASE /EMITTOOLVERSIONINFO:NO %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EntryPointSymbol />
|
||||||
|
<AdditionalDependencies>Ntoskrnl.lib</AdditionalDependencies>
|
||||||
|
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
|
||||||
|
<ShowProgress>LinkVerbose</ShowProgress>
|
||||||
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
|
</Link>
|
||||||
|
<DriverSign>
|
||||||
|
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
|
||||||
|
</DriverSign>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<FilesToPackage Include="$(TargetPath)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Inc\BaseDataTypes.h" />
|
||||||
|
<ClInclude Include="Inc\Common.h" />
|
||||||
|
<ClInclude Include="Inc\WriteProtectBypass.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Src\DrvMain.cpp" />
|
||||||
|
<ClCompile Include="Src\WriteProtectBypass.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{a88b16d9-5c2c-48e4-9eb1-23dddf6ea064}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{1c52dd49-2f39-4d9a-ab53-2ba8836d6616}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Inc\BaseDataTypes.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Inc\Common.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Inc\WriteProtectBypass.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Src\DrvMain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Src\WriteProtectBypass.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# EVENSTAR - KernelWriteProtect
|
||||||
|
|
||||||
|
## Version
|
||||||
|
|
||||||
|
- `v1.0.0`
|
||||||
|
|
||||||
|
## Brief
|
||||||
|
|
||||||
|
- `ISA: x86`
|
||||||
|
- `Mode: Long`
|
||||||
|
- `Bitness: 64-bit`
|
||||||
|
- `CPL: 0`
|
||||||
|
- `OS: Windows`
|
||||||
|
- `Language: C`
|
||||||
|
- Sample code that demonstrates two techniques for writing into read-only pages in kernel space using `CR0.WP` manipulation and `MDL` double mapping
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
[DBG]: +++ KernelWriteProtect.sys Loaded +++
|
||||||
|
[DBG]: KernelWriteProtect.sys Built May 14 2026 18:20:42
|
||||||
|
[DBG]: KernelWriteProtect: DriverObject = FFFF808F23410E20
|
||||||
|
[DBG]: KernelWriteProtect: RegistryPath = \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\KernelWriteProtect
|
||||||
|
Break instruction exception - code 80000003 (first chance)
|
||||||
|
*******************************************************************************
|
||||||
|
* *
|
||||||
|
* You are seeing this message because you pressed either *
|
||||||
|
* CTRL+C (if you run console kernel debugger) or, *
|
||||||
|
* CTRL+BREAK (if you run GUI kernel debugger), *
|
||||||
|
* on your debugger machine's keyboard. *
|
||||||
|
* *
|
||||||
|
* THIS IS NOT A BUG OR A SYSTEM CRASH *
|
||||||
|
* *
|
||||||
|
* If you did not intend to break into the debugger, press the "g" key, then *
|
||||||
|
* press the "Enter" key now. This message might immediately reappear. If it *
|
||||||
|
* does, press "g" and "Enter" again. *
|
||||||
|
* *
|
||||||
|
*******************************************************************************
|
||||||
|
nt!DbgBreakPointWithStatus:
|
||||||
|
fffff801`d1efb1b0 cc int 3
|
||||||
|
0: kd> !pte 0xFFFFF78000000000
|
||||||
|
VA fffff78000000000
|
||||||
|
PXE at FFFFEFF7FBFDFF78 PPE at FFFFEFF7FBFEF000 PDE at FFFFEFF7FDE00000 PTE at FFFFEFFBC0000000
|
||||||
|
contains 0000000000285063 contains 0000000000284063 contains 0000000000283063 contains 8A00000000282161
|
||||||
|
pfn 285 ---DA--KWEV pfn 284 ---DA--KWEV pfn 283 ---DA--KWEV pfn 282 -G-DA--KR-V
|
||||||
|
|
||||||
|
0: kd> db 0xFFFFF78000000000 L8
|
||||||
|
fffff780`00000000 41 41 41 41 41 41 41 41 AAAAAAAA
|
||||||
|
0: kd> g
|
||||||
|
[DBG]: --- KernelWriteProtect.sys Unloaded ---
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tested OS Versions
|
||||||
|
|
||||||
|
- `Windows 11 25H2 Build 26200 Revision 8246 64-bit`
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
1. [BattlEye hypervisor detection](https://secret.club/2020/01/12/battleye-hypervisor-detection.html)
|
||||||
|
2. [ac](https://github.com/donnaskiez/ac)
|
||||||
|
3. [EfiGuard](https://github.com/Mattiwatti/EfiGuard)
|
||||||
|
4. [kernelhook](https://github.com/adrianyy/kernelhook)
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// File: DrvMain.cpp
|
||||||
|
//
|
||||||
|
// Author: winterknife
|
||||||
|
//
|
||||||
|
// Description: Source file that contains the SYS entry point
|
||||||
|
//
|
||||||
|
// Modifications:
|
||||||
|
// 2026-04-13 Created
|
||||||
|
// 2026-05-14 Updated
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Includes
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#include "../Inc/Common.h"
|
||||||
|
#include "../Inc/WriteProtectBypass.h"
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Routines
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma region ROUTINES
|
||||||
|
|
||||||
|
/// @brief DRIVER_UNLOAD callback routine that gets called to uninitialize the driver when it is unloaded
|
||||||
|
/// @param pDriverObject Pointer to DRIVER_OBJECT structure representing the driver's driver object
|
||||||
|
_IRQL_requires_(PASSIVE_LEVEL)
|
||||||
|
EXTERN_C __declspec(code_seg("PAGE")) VOID __stdcall driver_unload(
|
||||||
|
_In_ PDRIVER_OBJECT pDriverObject
|
||||||
|
) {
|
||||||
|
// Suppress W4 warning - C4100
|
||||||
|
UNREFERENCED_PARAMETER(pDriverObject);
|
||||||
|
|
||||||
|
DEBUG_PRINT("--- %s.sys Unloaded ---\n", __MODULE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief DRIVER_INITIALIZE callback routine that gets called to initialize the driver when it is loaded
|
||||||
|
/// @param pDriverObject Pointer to DRIVER_OBJECT structure representing the driver's driver object
|
||||||
|
/// @param puncRegistryPath Pointer to UNICODE_STRING structure specifying the path to the driver's registry key
|
||||||
|
/// @return STATUS_SUCCESS or an appropriate error status
|
||||||
|
_Success_(return >= 0) _Must_inspect_result_ _IRQL_requires_(PASSIVE_LEVEL)
|
||||||
|
EXTERN_C __declspec(code_seg("INIT")) NTSTATUS __stdcall DriverEntry(
|
||||||
|
_In_ PDRIVER_OBJECT pDriverObject,
|
||||||
|
_In_ PUNICODE_STRING puncRegistryPath
|
||||||
|
) {
|
||||||
|
DEBUG_PRINT("+++ %s.sys Loaded +++\n", __MODULE__);
|
||||||
|
DEBUG_PRINT("%s.sys Built %s %s\n", __MODULE__, __DATE__, __TIME__);
|
||||||
|
DEBUG_PRINT("%s: DriverObject = %p\n", __MODULE__, pDriverObject);
|
||||||
|
DEBUG_PRINT("%s: RegistryPath = %wZ\n", __MODULE__, puncRegistryPath);
|
||||||
|
|
||||||
|
// Set routine to be called on driver unload
|
||||||
|
pDriverObject->DriverUnload = static_cast<PDRIVER_UNLOAD>(driver_unload);
|
||||||
|
|
||||||
|
// Write data into RO _KUSER_SHARED_DATA structure
|
||||||
|
BYTE byarrPayload[] = { 0x41, 0x41, 0x41, 0x41 };
|
||||||
|
QWORD qwKuserSharedData = 0xFFFFF78000000000ULL;
|
||||||
|
copy_memory_cr0_wp(reinterpret_cast<PVOID>(qwKuserSharedData), byarrPayload, sizeof(byarrPayload));
|
||||||
|
copy_memory_double_mapping(reinterpret_cast<PVOID>(qwKuserSharedData + 0x4ULL), byarrPayload, sizeof(byarrPayload));
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// File: WriteProtectBypass.cpp
|
||||||
|
//
|
||||||
|
// Author: winterknife
|
||||||
|
//
|
||||||
|
// Description: Source file that contains the necessary routines to bypass
|
||||||
|
// the Write Protect (WP) mitigation to allow supervisor-level procedures
|
||||||
|
// to write into read-only pages
|
||||||
|
//
|
||||||
|
// Modifications:
|
||||||
|
// 2026-05-12 Created
|
||||||
|
// 2026-05-14 Updated
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Includes
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#include "../Inc/WriteProtectBypass.h"
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Routines
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
#pragma region ROUTINES
|
||||||
|
|
||||||
|
_Use_decl_annotations_
|
||||||
|
VOID __stdcall copy_memory_cr0_wp(
|
||||||
|
VOID* pDestination,
|
||||||
|
CONST VOID* pcSource,
|
||||||
|
DWORD_PTR dwptrLength
|
||||||
|
) {
|
||||||
|
// Init local variables
|
||||||
|
DWORD dwCurrentProcessorNumber = 0;
|
||||||
|
KAFFINITY kaffinityNew = 0;
|
||||||
|
KAFFINITY kaffinityOld = 0;
|
||||||
|
KIRQL kirqlOld = 0;
|
||||||
|
QWORD qwCr4Value = 0;
|
||||||
|
BOOLEAN bCetDisabled = false;
|
||||||
|
QWORD qwCr0Value = 0;
|
||||||
|
BOOLEAN bWpDisabled = false;
|
||||||
|
|
||||||
|
// Get the current processor number
|
||||||
|
dwCurrentProcessorNumber = KeGetCurrentProcessorNumber();
|
||||||
|
|
||||||
|
// Set a processor affinity mask for the current thread
|
||||||
|
// This will lock the current thread to the logical processor it is running on (CPU pinning)
|
||||||
|
kaffinityNew = __ll_lshift(0x1, static_cast<int>(dwCurrentProcessorNumber));
|
||||||
|
kaffinityOld = KeSetSystemAffinityThreadEx(kaffinityNew);
|
||||||
|
|
||||||
|
// Raise the Interrupt Request Level (IRQL) of the current processor to the highest level
|
||||||
|
// This will prevent the thread scheduler from preempting the current thread
|
||||||
|
KeRaiseIrql(HIGH_LEVEL, &kirqlOld);
|
||||||
|
|
||||||
|
// Disable interrupts by clearing the RFLAGS.IF bit
|
||||||
|
// This will prevent the current processor from servicing any maskable interrupts
|
||||||
|
_disable(); // CLI - Clear Interrupt Flag
|
||||||
|
|
||||||
|
// Read the CR4 register value
|
||||||
|
qwCr4Value = __readcr4();
|
||||||
|
|
||||||
|
// Clear the CR4.CET bit
|
||||||
|
// CR0.WP cannot be cleared as long as CR4.CET is set
|
||||||
|
// WARNING: HyperGuard / Secure Kernel Patch Guard (SKPG) intercepts writes to CR0 and CR4 registers
|
||||||
|
bCetDisabled = _bittestandreset64(reinterpret_cast<LONG64*>(&qwCr4Value), 23LL);
|
||||||
|
__writecr4(qwCr4Value);
|
||||||
|
|
||||||
|
// Read the CR0 register value
|
||||||
|
qwCr0Value = __readcr0();
|
||||||
|
|
||||||
|
// Clear the CR0.WP bit
|
||||||
|
// When clear, it allows kernel-mode code to write into read-only pages
|
||||||
|
bWpDisabled = _bittestandreset64(reinterpret_cast<LONG64*>(&qwCr0Value), 16LL);
|
||||||
|
__writecr0(qwCr0Value);
|
||||||
|
|
||||||
|
// Write into RO pages
|
||||||
|
__movsb(static_cast<PUCHAR>(pDestination), static_cast<UCHAR const*>(pcSource), dwptrLength);
|
||||||
|
|
||||||
|
// Set the CR0.WP bit if it was cleared before
|
||||||
|
// When set, it inhibits kernel-mode code from writing into read-only pages
|
||||||
|
if (bWpDisabled) {
|
||||||
|
_bittestandset64(reinterpret_cast<LONG64*>(&qwCr0Value), 16LL);
|
||||||
|
__writecr0(qwCr0Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the CR4.CET bit if it was cleared before
|
||||||
|
// This flag can be set only if CR0.WP is set
|
||||||
|
if (bCetDisabled) {
|
||||||
|
_bittestandset64(reinterpret_cast<LONG64*>(&qwCr4Value), 23LL);
|
||||||
|
__writecr4(qwCr4Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable interrupts by setting the RFLAGS.IF bit
|
||||||
|
_enable(); // STI - Set Interrupt Flag
|
||||||
|
|
||||||
|
// Restore the original IRQL of the current processor
|
||||||
|
KeLowerIrql(kirqlOld);
|
||||||
|
|
||||||
|
// Restore the original processor affinity mask for the current thread
|
||||||
|
KeRevertToUserAffinityThreadEx(kaffinityOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Use_decl_annotations_
|
||||||
|
VOID __stdcall copy_memory_double_mapping(
|
||||||
|
VOID* pDestination,
|
||||||
|
CONST VOID* pcSource,
|
||||||
|
DWORD_PTR dwptrLength
|
||||||
|
) {
|
||||||
|
// Init local variables
|
||||||
|
PMDL pMdl = nullptr;
|
||||||
|
BOOLEAN bLocked = false;
|
||||||
|
PVOID pBufferKva = nullptr;
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
// Allocate a MDL for the read-only destination memory block in KVAS
|
||||||
|
pMdl = IoAllocateMdl(pDestination, static_cast<ULONG>(dwptrLength), false, false, nullptr);
|
||||||
|
if (pMdl == nullptr) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock the pages in the MDL
|
||||||
|
__try {
|
||||||
|
MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
|
||||||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
bLocked = true;
|
||||||
|
|
||||||
|
// Map the locked pages into KVAS effectively creating a second read-write mapping of the same physical memory
|
||||||
|
pBufferKva = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, nullptr, false, HighPagePriority | MdlMappingNoExecute);
|
||||||
|
if (pBufferKva == nullptr) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the protection type for the double mapping to RW
|
||||||
|
status = MmProtectMdlSystemAddress(pMdl, PAGE_READWRITE);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write into RW pages
|
||||||
|
// WARNING: If the page is protected by KDP then it will be marked as read-only in the SLAT entry
|
||||||
|
__movsb(static_cast<PUCHAR>(pBufferKva), static_cast<UCHAR const*>(pcSource), dwptrLength);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
cleanup:
|
||||||
|
// Release the double mapping
|
||||||
|
if (pBufferKva)
|
||||||
|
MmUnmapLockedPages(pBufferKva, pMdl);
|
||||||
|
|
||||||
|
// Unlock the pages in the MDL
|
||||||
|
if (bLocked)
|
||||||
|
MmUnlockPages(pMdl);
|
||||||
|
|
||||||
|
// Release the MDL
|
||||||
|
if (pMdl)
|
||||||
|
IoFreeMdl(pMdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
Reference in New Issue
Block a user