added PagingDbgExt project

This commit is contained in:
winterknife
2025-05-18 15:44:46 -04:00
parent f3f2fd2310
commit 1287e9bea7
14 changed files with 1097 additions and 0 deletions
+4
View File
@@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReadCRDbgExt", "ReadCRDbgEx
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReadMSW", "ReadMSW\ReadMSW.vcxproj", "{F9AB9899-9F93-4252-B634-740F19CCC1DC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PagingDbgExt", "PagingDbgExt\PagingDbgExt.vcxproj", "{4321EA53-183E-4104-887D-5CBFC14E4211}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
@@ -16,6 +18,8 @@ Global
{78BD9103-3B0A-46DF-9261-148EA8F34DF0}.Release|x64.Build.0 = Release|x64
{F9AB9899-9F93-4252-B634-740F19CCC1DC}.Release|x64.ActiveCfg = Release|x64
{F9AB9899-9F93-4252-B634-740F19CCC1DC}.Release|x64.Build.0 = Release|x64
{4321EA53-183E-4104-887D-5CBFC14E4211}.Release|x64.ActiveCfg = Release|x64
{4321EA53-183E-4104-887D-5CBFC14E4211}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+74
View File
@@ -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
+155
View File
@@ -0,0 +1,155 @@
// ========================================================================
// File: Common.h
//
// Author: winterknife
//
// Description: Contains the common stuff for this project
//
// Modifications:
// 2021-08-21 Created
// 2025-05-13 Updated
// ========================================================================
// ========================================================================
// Pragmas
// ========================================================================
#pragma once
// Specify program entry point
#pragma comment(linker, "/ENTRY:DllInit")
// 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
// ========================================================================
#define WIN32_LEAN_AND_MEAN
#define _NO_CRT_STDIO_INLINE
#include <Windows.h>
#include <intrin.h>
#include <stdio.h>
#include "BaseDataTypes.h"
#pragma intrinsic(__stosb)
#pragma intrinsic(__movsb)
#pragma intrinsic(strlen)
#pragma intrinsic(strcmp)
// ========================================================================
// Macros
// ========================================================================
#pragma region MACROS
// Module name
#define __MODULE__ "PagingDbgExt"
// 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_, ...) printf(DEBUG_PREFIX _x_, ##__VA_ARGS__);
#else
#define DEBUG_PRINT(_x_, ...) void(0)
#endif
// 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;
// Check if a function is in a delay loaded module, use on a global scope
#define CHECK_DELAY_LOAD(f) extern "C" extern void* __imp_load_ ##f; void test_delay_load ##f(){ (__imp_load_ ##f) ? 1 : 0; }
// 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
+59
View File
@@ -0,0 +1,59 @@
// ========================================================================
// File: DbgExt.h
//
// Author: winterknife
//
// Description: Header file for DbgExt.cpp source file
//
// Modifications:
// 2024-10-08 Created
// 2024-10-08 Updated
// ========================================================================
// ========================================================================
// Pragmas
// ========================================================================
#pragma once
// ========================================================================
// Includes
// ========================================================================
#include "Common.h"
#define KDEXT_64BIT
#include <WDBGEXTS.H>
#include <ntverp.h>
// ========================================================================
// C routine declarations
// ========================================================================
#pragma region DECLARATIONS
/// @brief Load and initialize the extension module
/// @param pWindbgExtensionApis Pointer to WINDBG_EXTENSION_APIS64 structure
/// @param woMajorVersion Specifies the Microsoft Windows build type
/// @param woMinorVersion Specifies the Windows build number of the target system
/// @return None
extern "C" __declspec(dllexport) VOID __stdcall WinDbgExtensionDllInit(
_In_ PWINDBG_EXTENSION_APIS pWindbgExtensionApis,
_In_ WORD woMajorVersion,
_In_ WORD woMinorVersion
);
/// @brief Returns version information about the extension DLL
/// @param None
/// @return Pointer to EXT_API_VERSION structure
extern "C" __declspec(dllexport) LPEXT_API_VERSION __stdcall ExtensionApiVersion(
VOID
);
/// @brief Verifies that the extension module version matches the debugger version, and outputs a warning message if there is a mismatch
/// @param None
/// @return None
extern "C" __declspec(dllexport) VOID __stdcall CheckVersion(
VOID
);
#pragma endregion
@@ -0,0 +1,184 @@
// ========================================================================
// File: GetKernelDirectoryTableBase.h
//
// Author: winterknife
//
// Description: Header file for GetKernelDirectoryTableBase.cpp source file
//
// Modifications:
// 2025-05-13 Created
// 2025-05-18 Updated
// ========================================================================
// ========================================================================
// Pragmas
// ========================================================================
#pragma once
// ========================================================================
// Includes
// ========================================================================
#include "Common.h"
// ========================================================================
// Macros
// ========================================================================
#pragma region MACROS
#define PSB_GDT32_NULL 0 * 16
#define PSB_GDT32_CODE64 1 * 16
#define PSB_GDT32_DATA32 2 * 16
#define PSB_GDT32_CODE32 3 * 16
#define PSB_GDT32_MAX 3
#define KUSER_SHARED_DATA_RO_MAPPING_X64_KVA 0xFFFFF78000000000
#define ACTIVEPROCESSORCOUNT_OFFSET 0x03C0
#pragma endregion
// ========================================================================
// Structures/Enumerations/Unions
// ========================================================================
#pragma region STRUCTS_ENUMS_UNIONS
#pragma pack(push, 2)
typedef struct _FAR_JMP_16 {
UCHAR OpCode; // opcode = 0xE9
USHORT Offset;
} FAR_JMP_16, *PFAR_JMP_16;
typedef struct _FAR_TARGET_32 {
ULONG Offset;
USHORT Selector;
} FAR_TARGET_32, *PFAR_TARGET_32;
typedef struct _PSEUDO_DESCRIPTOR_32 {
USHORT Limit;
ULONG Base;
} PSEUDO_DESCRIPTOR_32, *PPSEUDO_DESCRIPTOR_32;
#pragma pack(pop)
// 0x10 bytes (sizeof)
#pragma warning(push)
#pragma warning(disable: 4201) // anonymous unions warning
typedef union _KGDTENTRY64 {
struct {
USHORT LimitLow;
USHORT BaseLow;
union {
struct {
UCHAR BaseMiddle;
UCHAR Flags1;
UCHAR Flags2;
UCHAR BaseHigh;
} Bytes;
struct {
ULONG BaseMiddle : 8;
ULONG Type : 5;
ULONG Dpl : 2;
ULONG Present : 1;
ULONG LimitHigh : 4;
ULONG System : 1;
ULONG LongMode : 1;
ULONG DefaultBig : 1;
ULONG Granularity : 1;
ULONG BaseHigh : 8;
} Bits;
};
ULONG BaseUpper;
ULONG MustBeZero;
};
ULONG64 Alignment;
} KGDTENTRY64, *PKGDTENTRY64;
#pragma warning(pop)
typedef struct _KDESCRIPTOR {
USHORT Pad[3];
USHORT Limit;
PVOID Base;
} KDESCRIPTOR, *PKDESCRIPTOR;
typedef struct _KSPECIAL_REGISTERS {
ULONG64 Cr0;
ULONG64 Cr2;
ULONG64 Cr3;
ULONG64 Cr4;
ULONG64 KernelDr0;
ULONG64 KernelDr1;
ULONG64 KernelDr2;
ULONG64 KernelDr3;
ULONG64 KernelDr6;
ULONG64 KernelDr7;
KDESCRIPTOR Gdtr;
KDESCRIPTOR Idtr;
USHORT Tr;
USHORT Ldtr;
ULONG MxCsr;
ULONG64 DebugControl;
ULONG64 LastBranchToRip;
ULONG64 LastBranchFromRip;
ULONG64 LastExceptionToRip;
ULONG64 LastExceptionFromRip;
ULONG64 Cr8;
ULONG64 MsrGsBase;
ULONG64 MsrGsSwap;
ULONG64 MsrStar;
ULONG64 MsrLStar;
ULONG64 MsrCStar;
ULONG64 MsrSyscallMask;
ULONG64 Xcr0;
ULONG64 MsrFsBase;
ULONG64 SpecialPadding0;
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;
typedef struct _KPROCESSOR_STATE {
KSPECIAL_REGISTERS SpecialRegisters;
CONTEXT ContextFrame;
} KPROCESSOR_STATE, *PKPROCESSOR_STATE;
// nt!HalpLowStub
typedef struct _PROCESSOR_START_BLOCK* PPROCESSOR_START_BLOCK;
typedef struct _PROCESSOR_START_BLOCK {
FAR_JMP_16 Jmp; // The block starts with a jmp instruction to the end of the block
ULONG CompletionFlag; // Completion flag is set to non-zero when the target processor has started
PSEUDO_DESCRIPTOR_32 Gdt32; // Pseudo descriptors for GDT
PSEUDO_DESCRIPTOR_32 Idt32; // Pseudo descriptors for IDT
KGDTENTRY64 Gdt[PSB_GDT32_MAX + 1]; // The temporary 32-bit GDT itself resides here
ULONG64 TiledCr3; // Physical address of the 64-bit top-level identity-mapped page table
FAR_TARGET_32 PmTarget; // Far jump target from Rm to Pm code
FAR_TARGET_32 LmIdentityTarget; // Far jump target from Pm to Lm code
PVOID LmTarget; // Address of LmTarget
PPROCESSOR_START_BLOCK SelfMap; // Linear address of this structure
ULONG64 MsrPat; // Contents of the PAT msr
ULONG64 MsrEFER; // Contents of the EFER msr
KPROCESSOR_STATE ProcessorState; // Initial processor state for the processor to be started
} PROCESSOR_START_BLOCK;
#pragma endregion
// ========================================================================
// C routine declarations
// ========================================================================
#pragma region DECLARATIONS
/// @brief Built-in command to find the kernel's DTB (DirectoryTableBase) which is the physical address of the base of the paging-structure hierarchy for KVAS contained in CR3 from the Low Stub
/// @param hCurrentProcess Handle for the current process
/// @param hCurrentThread Handle for the current thread
/// @param qwCurrentPc Program counter
/// @param dwProcessor Current processor
/// @param strArgs Command line arguments
/// @return None
extern "C" __declspec(dllexport) VOID __stdcall get_kernel_dtb(
_In_ HANDLE hCurrentProcess,
_In_ HANDLE hCurrentThread,
_In_ QWORD qwCurrentPc,
_In_ DWORD dwProcessor,
_In_z_ PCSTR strArgs
);
#pragma endregion
+46
View File
@@ -0,0 +1,46 @@
// ========================================================================
// File: Help.h
//
// Author: winterknife
//
// Description: Header file for Help.cpp source file
//
// Modifications:
// 2025-05-14 Created
// 2025-05-14 Updated
// ========================================================================
// ========================================================================
// Pragmas
// ========================================================================
#pragma once
// ========================================================================
// Includes
// ========================================================================
#include "Common.h"
// ========================================================================
// C routine declarations
// ========================================================================
#pragma region DECLARATIONS
/// @brief Built-in help command for the debugger extension DLL
/// @param hCurrentProcess Handle for the current process
/// @param hCurrentThread Handle for the current thread
/// @param qwCurrentPc Program counter
/// @param dwProcessor Current processor
/// @param strArgs Command line arguments
/// @return None
extern "C" __declspec(dllexport) VOID __stdcall help(
_In_ HANDLE hCurrentProcess,
_In_ HANDLE hCurrentThread,
_In_ QWORD qwCurrentPc,
_In_ DWORD dwProcessor,
_In_z_ PCSTR strArgs
);
#pragma endregion
+89
View File
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" 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">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{4321ea53-183e-4104-887d-5cbfc14e4211}</ProjectGuid>
<RootNamespace>PagingDbgExt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>.\Bin\x64\</OutDir>
<IntDir>.\Temp\x64\</IntDir>
<GenerateManifest>false</GenerateManifest>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<TreatWarningAsError>true</TreatWarningAsError>
<Optimization>Disabled</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<OmitFramePointers>false</OmitFramePointers>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<ExceptionHandling>false</ExceptionHandling>
<SuppressStartupBanner>false</SuppressStartupBanner>
<AdditionalOptions>%(AdditionalOptions) /homeparams</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Native</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/EMITPOGOPHASEINFO /NOVCFEATURE /NOCOFFGRPINFO /FILEALIGN:0x200 /PDBALTPATH:$(ProjectName).pdb /Brepro /RELEASE /EMITTOOLVERSIONINFO:NO /NOIMPLIB /NOEXP %(AdditionalOptions)</AdditionalOptions>
<ShowProgress>LinkVerbose</ShowProgress>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Inc\BaseDataTypes.h" />
<ClInclude Include="Inc\Common.h" />
<ClInclude Include="Inc\DbgExt.h" />
<ClInclude Include="Inc\GetKernelDirectoryTableBase.h" />
<ClInclude Include="Inc\Help.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Src\DbgExt.cpp" />
<ClCompile Include="Src\DllMain.cpp" />
<ClCompile Include="Src\GetKernelDirectoryTableBase.cpp" />
<ClCompile Include="Src\Help.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
</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\DbgExt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Inc\GetKernelDirectoryTableBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Inc\Help.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Src\DbgExt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Src\GetKernelDirectoryTableBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Src\DllMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Src\Help.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
+137
View File
@@ -0,0 +1,137 @@
# EVENSTAR - PagingDbgExt
## Version
- `v10.0.6`
## Brief
- `ISA: x86`
- `Mode: Long`
- `Bitness: 64-bit`
- `CPL: 3`
- `OS: Windows`
- `Language: C`
- _WdbgExts_ "old style" debugger extension `DLL` that contains various experiments around `IA-32e Paging`
## Usage
- Set up kernel-mode debugging of the target
```shell
0: kd> vertarget
Windows 10 Kernel Version 22000 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 22000.1.amd64fre.co_release.210604-1628
Kernel base = 0xfffff804`4b40f000 PsLoadedModuleList = 0xfffff804`4c038b90
Debug session time: Sun May 18 13:37:25.707 2025 (UTC - 4:00)
System Uptime: 0 days 3:28:02.923
0: kd> .load PagingDbgExt.dll
0: kd> .chain
--snip--
Extension DLL chain:
PagingDbgExt: API 10.0.6,
[path: C:\Users\winterknife\Desktop\Tools\WinDbgExtensions\PagingDbgExt.dll]
--snip--
0: kd> .extmatch /D /e PagingDbgExt *
!PagingDbgExt.get_kernel_dtb
!PagingDbgExt.help
0: kd> !PagingDbgExt.help
Help for debugger extension DLL PagingDbgExt.dll
help - Show help menu
get_kernel_dtb - Find the kernel's DTB (DirectoryTableBase) which is the physical address of the base of the paging-structure hierarchy for KVAS contained in CR3 from the Low Stub
0: kd> !PagingDbgExt.get_kernel_dtb
[+] nt!_PROCESSOR_START_BLOCK structure found at PA=0x13000
[+] HAL Heap base KVA=0xFFFFF7F000000000
[+] nt!_PROCESSOR_START_BLOCK.ProcessorState.SpecialRegisters.Cr3=0x1AE000
0: kd> ? poi(nt!HalpLowStubPhysicalAddress)
Evaluate expression: 77824 = 00000000`00013000
0: kd> ? poi(nt!HalpOriginalHeapStart)
Evaluate expression: -8864812498944 = fffff7f0`00000000
0: kd> r @cr3
cr3=00000000001ae000
0: kd> !process 4 0
Searching for Process with Cid == 4
PROCESS ffffce849b2f1040
SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 001ae000 ObjectTable: ffffaa0c84203dc0 HandleCount: 1818.
Image: System
0: kd> dt nt!_KPROCESS ffffce849b2f1040 DirectoryTableBase
+0x028 DirectoryTableBase : 0x1ae000
0: kd> dt /p nt!_KPROCESSOR_STATE 0x13090 SpecialRegisters.Cr3
+0x000 SpecialRegisters :
+0x010 Cr3 : 0x1ae000
0: kd> !db 0x13000
# 13000 e9 4d 06 00 01 00 00 00-01 00 00 00 3f 00 18 30 .M..........?..0
# 13010 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 13020 00 00 00 00 00 00 00 00-00 00 00 00 00 9b 20 00 .............. .
# 13030 00 00 00 00 00 00 00 00-ff ff 00 00 00 93 cf 00 ................
# 13040 00 00 00 00 00 00 00 00-ff ff 00 00 00 9b cf 00 ................
# 13050 00 00 00 00 00 00 00 00-00 20 af 7a 00 00 00 00 ......... .z....
# 13060 79 36 01 00 30 00 d7 36-01 00 10 00 00 00 00 00 y6..0..6........
# 13070 70 18 82 4b 04 f8 ff ff-00 c0 00 00 f0 f7 ff ff p..K............
0: kd> db poi(nt!HalpLowStub)
fffff7f0`0000c000 e9 4d 06 00 01 00 00 00-01 00 00 00 3f 00 18 30 .M..........?..0
fffff7f0`0000c010 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
fffff7f0`0000c020 00 00 00 00 00 00 00 00-00 00 00 00 00 9b 20 00 .............. .
fffff7f0`0000c030 00 00 00 00 00 00 00 00-ff ff 00 00 00 93 cf 00 ................
fffff7f0`0000c040 00 00 00 00 00 00 00 00-ff ff 00 00 00 9b cf 00 ................
fffff7f0`0000c050 00 00 00 00 00 00 00 00-00 20 af 7a 00 00 00 00 ......... .z....
fffff7f0`0000c060 79 36 01 00 30 00 d7 36-01 00 10 00 00 00 00 00 y6..0..6........
fffff7f0`0000c070 70 18 82 4b 04 f8 ff ff-00 c0 00 00 f0 f7 ff ff p..K............
0: kd> dps poi(nt!HalpLowStub) L10
fffff7f0`0000c000 00000001`00064de9
fffff7f0`0000c008 3018003f`00000001
fffff7f0`0000c010 00000000`00000001
fffff7f0`0000c018 00000000`00000000
fffff7f0`0000c020 00000000`00000000
fffff7f0`0000c028 00209b00`00000000
fffff7f0`0000c030 00000000`00000000
fffff7f0`0000c038 00cf9300`0000ffff
fffff7f0`0000c040 00000000`00000000
fffff7f0`0000c048 00cf9b00`0000ffff
fffff7f0`0000c050 00000000`00000000
fffff7f0`0000c058 00000000`7aaf2000
fffff7f0`0000c060 36d70030`00013679
fffff7f0`0000c068 00000000`00100001
fffff7f0`0000c070 fffff804`4b821870 nt!HalpLMStub
fffff7f0`0000c078 fffff7f0`0000c000
0: kd> !pte poi(nt!HalpLowStub)
VA fffff7f00000c000
PXE at FFFFBA5D2E974F78 PPE at FFFFBA5D2E9EFE00 PDE at FFFFBA5D3DFC0000 PTE at FFFFBA7BF8000060
contains 0000000002182063 contains 8000000002185063 contains 8000000002186063 contains 8000000000013963
pfn 2182 ---DA--KWEV pfn 2185 ---DA--KW-V pfn 2186 ---DA--KW-V pfn 13 -G-DA--KW-V
0: kd> !vtop 0x1ae000 0xfffff7f00000c000
Amd64VtoP: Virt fffff7f00000c000, pagedir 00000000001ae000
Amd64VtoP: PML4E 00000000001aef78
Amd64VtoP: PDPE 0000000002182e00
Amd64VtoP: PDE 0000000002185000
Amd64VtoP: PTE 0000000002186060
Amd64VtoP: Mapped phys 0000000000013000
Virtual address fffff7f00000c000 translates to physical address 13000.
0: kd> .unload PagingDbgExt.dll
Unloading PagingDbgExt extension DLL
```
## Tested OS Versions
- `Windows 11 21H2 Build 22000 Revision 675 64-bit`
## References
1. [Getting Physical with USB Type-C: Windows 10 RAM Forensics and UEFI Attacks - Alex Ionescu](http://publications.alex-ionescu.com/Recon/ReconBru%202017%20-%20Getting%20Physical%20with%20USB%20Type-C,%20Windows%2010%20RAM%20Forensics%20and%20UEFI%20Attacks.pdf)
2. [VmmWinInit_DTB_FindValidate_X64_LowStub](https://github.com/ufrisk/MemProcFS/blob/master/vmm/vmmwininit.c#L801)
3. [find_low_stub](https://github.com/chompie1337/SMBGhost_RCE_PoC/blob/master/exploit.py#L396)
4. [DriverInitPageTableBase](https://github.com/Cr4sh/KernelForge/blob/master/kforge_driver/kforge_driver.cpp#L60)
5. [WinIoQueryPML4Value](https://github.com/hfiref0x/WinObjEx64/blob/master/Source/WinObjEx64/drivers/winio.c#L188)
+61
View File
@@ -0,0 +1,61 @@
// ========================================================================
// File: DbgExt.cpp
//
// Author: winterknife
//
// Description: Source file that contains the basic template for a
// WdbgExts extension DLL
//
// Modifications:
// 2024-10-08 Created
// 2024-10-08 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/DbgExt.h"
// ========================================================================
// Globals
// ========================================================================
#pragma region GLOBALS
EXT_API_VERSION ApiVersion = { (VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff), EXT_API_VERSION_NUMBER64, 0 };
WINDBG_EXTENSION_APIS ExtensionApis;
DWORD SavedMajorVersion;
DWORD SavedMinorVersion;
#pragma endregion
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
VOID __stdcall WinDbgExtensionDllInit(
_In_ PWINDBG_EXTENSION_APIS pWindbgExtensionApis,
_In_ WORD woMajorVersion,
_In_ WORD woMinorVersion
) {
ExtensionApis = *pWindbgExtensionApis;
SavedMajorVersion = woMajorVersion;
SavedMinorVersion = woMinorVersion;
}
LPEXT_API_VERSION __stdcall ExtensionApiVersion(
VOID
) {
return &ApiVersion;
}
VOID __stdcall CheckVersion(
VOID
) {
return;
}
#pragma endregion
+57
View File
@@ -0,0 +1,57 @@
// ========================================================================
// File: DllMain.cpp
//
// Author: winterknife
//
// Description: Source file that contains the DLL entry point
//
// Modifications:
// 2024-10-08 Created
// 2024-10-08 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/Common.h"
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
#pragma CODE_BEGIN
/// @brief DLL entry point
/// @param hModule A handle to the DLL module
/// @param dwReason The reason code that indicates why the DLL entry-point function is being called
/// @param dwReserved Reserved
/// @return TRUE if DLL initialization succeeds or FALSE if it fails
extern "C" __declspec(noinline) BOOLEAN __stdcall DllInit(
_In_ HMODULE hModule,
_In_ DWORD dwReason,
_In_opt_ DWORD dwReserved
) {
UNREFERENCED_PARAMETER(hModule);
UNREFERENCED_PARAMETER(dwReserved);
switch (dwReason) {
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_ATTACH:
break;
}
return TRUE;
}
#pragma CODE_END
#pragma endregion
@@ -0,0 +1,135 @@
// ========================================================================
// File: GetKernelDirectoryTableBase.cpp
//
// Author: winterknife
//
// Description: Source file that contains the necessary routines to find the
// kernel's DirectoryTableBase using an arbitrary physical memory read primitive
// to locate the Low Stub with heuristic scanning
//
// Modifications:
// 2025-05-13 Created
// 2025-05-18 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/GetKernelDirectoryTableBase.h"
#include "../Inc/DbgExt.h"
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
_Use_decl_annotations_
VOID __stdcall get_kernel_dtb(
HANDLE hCurrentProcess,
HANDLE hCurrentThread,
QWORD qwCurrentPc,
DWORD dwProcessor,
PCSTR strArgs
) {
UNREFERENCED_PARAMETER(hCurrentProcess);
UNREFERENCED_PARAMETER(hCurrentThread);
UNREFERENCED_PARAMETER(qwCurrentPc);
UNREFERENCED_PARAMETER(dwProcessor);
UNREFERENCED_PARAMETER(strArgs);
// Init local variables
PVOID pBuffer = NULL;
DWORD dwActiveProcessorCount = 0;
QWORD qwPhysicalAddress = 0;
DWORD dwBytesRead = 0;
PPROCESSOR_START_BLOCK pProcessorStartBlock = NULL;
QWORD qwKernelDirectoryTableBase = 0;
// Determine if the target uses 64-bit pointers
if (!IsPtr64()) {
dprintf("[-] IA-32 target is not supported by this extension!\n");
goto cleanup;
}
// Allocate 0x1000 (PAGE_SIZE_4KB) bytes worth of heap memory to read the Low Stub
pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
if (pBuffer == NULL) {
dprintf("[-] Error allocating heap memory!\n");
goto cleanup;
}
// This technique of finding the Low Stub doesn't work if the number of Application Processors (APs) == 1
// This happens because the nt!_PROCESSOR_START_BLOCK structure is filled incorrectly in this case
// Get nt!_KUSER_SHARED_DATA.ActiveProcessorCount
if (!ReadMemory((KUSER_SHARED_DATA_RO_MAPPING_X64_KVA + ACTIVEPROCESSORCOUNT_OFFSET), &dwActiveProcessorCount, 0x04, NULL)) {
dprintf("[-] Error reading virtual memory!\n");
goto cleanup;
}
// Check nt!_KUSER_SHARED_DATA.ActiveProcessorCount
if (dwActiveProcessorCount < 2) {
dprintf("[-] This technique does not work for UniProcessor (UP) systems!\n");
goto cleanup;
}
// Locate the Low Stub with heuristic scanning
// The Low Stub is always present on x86 APIC systems in one of the physical pages in the range starting at 0x1000 (4 KB) and less than 0x100000 (1 MB)
// It is a piece of 16-bit code that aids in CPU mode transitions (Real Mode to Protected Mode to Long Mode) on boot or waking up from S2 and S3 sleeps
// nt!HalpLowStub contains the KVA of nt!_PROCESSOR_START_BLOCK structure
// nt!HalpLowStubPhysicalAddress contains the PA of nt!_PROCESSOR_START_BLOCK structure
for (qwPhysicalAddress = 0x1000; qwPhysicalAddress < 0x100000; qwPhysicalAddress += 0x1000) {
ReadPhysical(qwPhysicalAddress, pBuffer, 0x1000, &dwBytesRead);
if (dwBytesRead != 0x1000) {
dprintf("[-] Error reading physical memory!\n");
goto cleanup;
}
// Low Stub is the nt!_PROCESSOR_START_BLOCK structure
pProcessorStartBlock = (PPROCESSOR_START_BLOCK)pBuffer;
// nt!_PROCESSOR_START_BLOCK structure starts with the following bytes decoded as the JMP rel16 instruction:
// E9 4D 06 jmp 0x650
// This piece of 16-bit x86 code jumps to the end of the nt!_PROCESSOR_START_BLOCK structure
// The size of this structure is 0x650/0n1616 bytes starting from Windows 10 1703 Creators Update (RS2) Build 15063
if (pProcessorStartBlock->Jmp.OpCode != 0xE9)
continue;
if (pProcessorStartBlock->Jmp.Offset != 0x06)
continue;
// nt!_PROCESSOR_START_BLOCK.CompletionFlag should be set when the Application Processor (AP) has been initialized
if (pProcessorStartBlock->CompletionFlag != 1)
continue;
// nt!_PROCESSOR_START_BLOCK.LmTarget should point to nt!HalpLMStub
if (pProcessorStartBlock->LmTarget == 0)
continue;
// nt!_PROCESSOR_START_BLOCK.ProcessorState.SpecialRegisters.Cr3 should not be zero
if (pProcessorStartBlock->ProcessorState.SpecialRegisters.Cr3 == 0)
continue;
// Found!
dprintf("[+] nt!_PROCESSOR_START_BLOCK structure found at PA=0x%I64X\n", qwPhysicalAddress);
// Get the base address of the HAL Heap which is pointed to by nt!HalpOriginalHeapStart
dprintf("[+] HAL Heap base KVA=0x%I64X\n", ((QWORD)(pProcessorStartBlock->SelfMap) & 0xFFFFFFFFF0000000));
// Get the physical address of the first table that is used in virtual address translation for KVAS contained in CR3
qwKernelDirectoryTableBase = pProcessorStartBlock->ProcessorState.SpecialRegisters.Cr3;
dprintf("[+] nt!_PROCESSOR_START_BLOCK.ProcessorState.SpecialRegisters.Cr3=0x%I64X\n", qwKernelDirectoryTableBase);
break;
}
// Cleanup
cleanup:
if (pBuffer)
HeapFree(GetProcessHeap(), 0, pBuffer);
return;
}
#pragma endregion
+48
View File
@@ -0,0 +1,48 @@
// ========================================================================
// File: Help.cpp
//
// Author: winterknife
//
// Description: Source file that contains the implementation of the built-in
// help command for the debugger extension DLL
//
// Modifications:
// 2025-05-14 Created
// 2025-05-18 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/Help.h"
#include "../Inc/DbgExt.h"
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
_Use_decl_annotations_
VOID __stdcall help(
HANDLE hCurrentProcess,
HANDLE hCurrentThread,
QWORD qwCurrentPc,
DWORD dwProcessor,
PCSTR strArgs
) {
UNREFERENCED_PARAMETER(hCurrentProcess);
UNREFERENCED_PARAMETER(hCurrentThread);
UNREFERENCED_PARAMETER(qwCurrentPc);
UNREFERENCED_PARAMETER(dwProcessor);
UNREFERENCED_PARAMETER(strArgs);
dprintf(
"Help for debugger extension DLL PagingDbgExt.dll\n"
" help - Show help menu\n"
" get_kernel_dtb - Find the kernel's DTB (DirectoryTableBase) which is the physical address of the base of the paging-structure hierarchy for KVAS contained in CR3 from the Low Stub\n"
);
}
#pragma endregion