added new project to check processor's CPL

This commit is contained in:
winterknife
2025-06-17 08:21:08 -04:00
parent bc16f431ab
commit 7cd5bf68dd
13 changed files with 145 additions and 104 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ VisualStudioVersion = 17.11.35312.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReadCRDbgExt", "ReadCRDbgExt\ReadCRDbgExt.vcxproj", "{78BD9103-3B0A-46DF-9261-148EA8F34DF0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReadMSW", "ReadMSW\ReadMSW.vcxproj", "{F9AB9899-9F93-4252-B634-740F19CCC1DC}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GetCPL", "GetCPL\GetCPL.vcxproj", "{F9AB9899-9F93-4252-B634-740F19CCC1DC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PagingDbgExt", "PagingDbgExt\PagingDbgExt.vcxproj", "{4321EA53-183E-4104-887D-5CBFC14E4211}"
EndProject
@@ -10,7 +10,7 @@
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{f9ab9899-9f93-4252-b634-740f19ccc1dc}</ProjectGuid>
<RootNamespace>ReadMSW</RootNamespace>
<RootNamespace>GetCPL</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -72,14 +72,14 @@
<ClCompile Include="Src\ExeMain.cpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="Src\ReadMsw64.asm">
<MASM Include="Src\GetCurrentPrivilegeLevel64.asm">
<FileType>Document</FileType>
</MASM>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Inc\BaseDataTypes.h" />
<ClInclude Include="Inc\Common.h" />
<ClInclude Include="Inc\ReadMsw.h" />
<ClInclude Include="Inc\GetCurrentPrivilegeLevel.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -16,7 +16,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="Src\ReadMsw64.asm">
<MASM Include="Src\GetCurrentPrivilegeLevel64.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
@@ -27,7 +27,7 @@
<ClInclude Include="Inc\Common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Inc\ReadMsw.h">
<ClInclude Include="Inc\GetCurrentPrivilegeLevel.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
+23 -12
View File
@@ -7,7 +7,7 @@
//
// Modifications:
// 2021-08-21 Created
// 2025-01-09 Updated
// 2025-06-16 Updated
// ========================================================================
// ========================================================================
@@ -17,7 +17,7 @@
#pragma once
// Specify program entry point
#pragma comment(linker, "/ENTRY:ExeInit")
#pragma comment(linker, "/ENTRY:ExeEntry")
// Merge sections
#if defined (_MSC_VER)
@@ -36,8 +36,10 @@
// ========================================================================
#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)
@@ -52,10 +54,19 @@
#pragma region MACROS
// Module name
#define __MODULE__ "ReadMSW"
#define __MODULE__ "GetCPL"
// Comment out for final build
//#define DEBUG_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
@@ -110,12 +121,12 @@
#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)
// 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)
// 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
@@ -126,11 +137,11 @@
#pragma region INLINES
// Brief: To compare two blocks of memory and return the number of bytes that match
// Parameter1: pcSource1 = Pointer to the first block of memory
// Parameter2: pcSource2 = Pointer to the second block of memory
// Parameter3: 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
/// @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;
@@ -1,13 +1,13 @@
// ========================================================================
// File: ReadMsw.h
// File: GetCurrentPrivilegeLevel.h
//
// Author: winterknife
//
// Description: Header file for ReadMsw32/64.asm source file
// Description: Header file for GetCurrentPrivilegeLevel32/64.asm source file
//
// Modifications:
// 2025-01-09 Created
// 2025-01-09 Updated
// 2025-06-16 Created
// 2025-06-16 Updated
// ========================================================================
// ========================================================================
@@ -28,11 +28,11 @@
#pragma region DECLARATIONS
/// @brief Check if segment-level protection is enabled
/// @brief Check the Current Privilege Level (CPL) of the processor
/// @param None
/// @return Returns TRUE if protected mode is enabled or FALSE if real-address mode is enabled
_Success_(return != 0) _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL)
extern "C" __declspec(noinline) BOOLEAN __fastcall is_protected_mode_enabled(
/// @return Returns TRUE if CPL < 3 (supervisor-mode) or FALSE if CPL = 3 (user-mode)
_Success_(return != 0) _Must_inspect_result_ _IRQL_requires_max_(HIGH_LEVEL)
extern "C" __declspec(noinline) BOOLEAN __fastcall is_supervisor_mode(
VOID
);
+42
View File
@@ -0,0 +1,42 @@
# EVENSTAR - GetCPL
## Version
- `v1.0.0`
## Brief
- `ISA: x86`
- `Mode: Real, Protected, Long`
- `Bitness: 16-bit, 32-bit, 64-bit`
- `CPL: 0, 3`
- `OS: Windows`
- `Language: C`
- Sample code that demonstrates the usage of the `SMSW` instruction to fetch the the `Machine Status Word` (bits 0 through 15 of control register `CR0`) and check the processor's `Current Privilege Level (CPL)` if the processor is running in `Protected` mode.
## Usage
- There aren't a lot of useful bits in the `MSW`
- One notable exception: `PE (Protection Enable)` bit (0)
- This flag enables Segmentation
- The processor maintains an internal state called `CPL` which is defined as the privilege level of the currently executing code
- `CPL` is used to determine whether certain operations are permitted or not
- `CPL` is given by `CS.RPL` (bits 0 and 1)
```shell
C:\pub\bld\DriverRun>GetCPL.exe
[*] GetCPL Built Jun 16 2025 18:13:39
Press any key to continue . . .
[DBG]: user-mode
Press any key to continue . . .
[DBG]: +++ GetCPL.sys Loaded +++
[DBG]: GetCPL.sys Built Jun 17 2025 07:12:51
[DBG]: GetCPL: DriverObject = FFFFC486721BDAF0
[DBG]: GetCPL: RegistryPath = \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\GetCPL
[DBG]: supervisor-mode
[DBG]: --- GetCPL.sys Unloaded ---
```
## Tested OS Versions
- `Windows 11 21H2 Build 22000 Revision 675 64-bit`
## References
1. [SMSW — Store Machine Status Word](https://namazso.github.io/x86/html/SMSW.html)
2. [The Segmented Memory Model and How It Works in Windows x64](https://antonioparata.blogspot.com/2023/01/the-segment-memory-model-and-how-it.html)
@@ -7,7 +7,7 @@
//
// Modifications:
// 2025-01-08 Created
// 2025-01-09 Updated
// 2025-06-16 Updated
// ========================================================================
// ========================================================================
@@ -15,7 +15,7 @@
// ========================================================================
#include "../Inc/Common.h"
#include "../Inc/ReadMsw.h"
#include "../Inc/GetCurrentPrivilegeLevel.h"
#define _NO_CRT_STDIO_INLINE
#include <stdio.h>
#include <process.h>
@@ -30,7 +30,7 @@
/// @brief EXE entry point
/// @param None
/// @return None
extern "C" __declspec(noreturn) VOID __stdcall ExeInit(
extern "C" __declspec(noreturn) VOID __stdcall ExeEntry(
VOID
) {
printf("[*] %s Built %s %s\n", __MODULE__, __DATE__, __TIME__);
@@ -45,14 +45,16 @@ extern "C" __declspec(noreturn) VOID __stdcall ExeInit(
__nop();
// Init local variables
BOOLEAN bProtectionEnable = FALSE;
BOOLEAN bSupervisorMode = FALSE;
// Check if Segmentation is enabled
bProtectionEnable = is_protected_mode_enabled();
if (bProtectionEnable)
printf("Processor Execution Mode == Protected Mode\n");
else
printf("Processor Execution Mode == Real-Address Mode\n");
// Check processor's CPL
bSupervisorMode = is_supervisor_mode();
if (bSupervisorMode) {
DEBUG_PRINT("supervisor-mode\n");
}
else {
DEBUG_PRINT("user-mode\n");
}
__nop();
__nop();
+54
View File
@@ -0,0 +1,54 @@
; ------------------------------------------------------------------------
; File: GetCurrentPrivilegeLevel64.asm
;
; Author: winterknife
;
; Description: x64 assembly routine to read the
; Machine Status Word (bits 0 through 15 of control register CR0) using
; the SMSW instruction and determine the Current Privilege Level (CPL)
; if the execution mode of the processor is protected mode
;
; Modifications:
; 2025-06-16 Created
; 2025-06-16 Updated
; ------------------------------------------------------------------------
; Start of .text segment
.CODE
; Align by 16 bytes
ALIGN 16
; Check the Current Privilege Level (CPL) of the processor
is_supervisor_mode PROC PUBLIC
; Store the Machine Status Word (bits 0 through 15 of control register CR0) into AX register
smsw ax ; AX = CR0[15:0]
; Check if CR0.PE flag is set
; Protection Enable (bit 0 of CR0) enables protected mode when set and enables real-address mode when clear
bt ax, 0h ; EFLAGS.CF = Bit(AX, 0)
jnc cleanup ; if (EFLAGS.CF == 0) goto cleanup
; Store the Code Segment (CS) register value in AX
mov ax, cs ; AX = CS
; Check the CPL of the processor
; Processor maintains an internal state called Current Privilege Level (CPL) which is defined as the privilege level of the currently executing code
; CPL is used to determine whether certain operations are permitted or not
; CPL is given by CS.RPL (bits 0 and 1)
; Windows OS only uses CPL0 and CPL3
and ax, 3h ; AX = AX & 0x03
jz supervisor ; if (EFLAGS.ZF == 1) goto supervisor
xor ax, ax ; AX = AX ^ AX = 0
jmp cleanup ; goto cleanup
supervisor:
inc ax ; AX = AX + 0x01
; Cleanup
cleanup:
; Return AX register value to the calling procedure
ret ; IP = [SP] and SP = SP + 0x02
is_supervisor_mode ENDP
; End of MASM source
END
-34
View File
@@ -1,34 +0,0 @@
# EVENSTAR - ReadMSW
## Version
- `v1.0.0`
## Brief
- `ISA: x86`
- `Mode: Real, Protected, Long`
- `Bitness: 16-bit, 32-bit, 64-bit`
- `CPL: 0, 3`
- `OS: Windows`
- `Language: C`
- Sample code that demonstrates the usage of the `SMSW` instruction to fetch the the `Machine Status Word` (bits 0 through 15 of control register `CR0`) and check if the processor is running in `Protected` mode.
## Usage
- There aren't a lot of useful bits in the `MSW`
- One notable exception: `PE (Protection Enable)` bit (0)
- This flag enables Segmentation
- Under normal circumstances, the sample code will always inform that `CR0.PE` bit is set
- Only useful for low-level code such as `OS` and `Hypervisors`
- Another possible use might be for `VM` detection but more testing is needed
```shell
C:\Users\winterknife\Desktop\ACED\EVENSTAR\ReadMSW\Bin\x64>ReadMSW.exe
[*] ReadMSW Built Jan 14 2025 14:12:25
Press any key to continue . . .
Processor Execution Mode == Protected Mode
Press any key to continue . . .
```
## Tested OS Versions
- `Windows 11 24H2 Build 26100 Revision 1882 64-bit`
## References
1. [SMSW—Store Machine Status Word](https://namazso.github.io/x86/html/SMSW.html)
-34
View File
@@ -1,34 +0,0 @@
; ------------------------------------------------------------------------
; File: ReadMsw64.asm
;
; Author: winterknife
;
; Description: x64 assembly routine to read the
; Machine Status Word (bits 0 through 15 of control register CR0) using
; the SMSW instruction
;
; Modifications:
; 2025-01-09 Created
; 2025-01-14 Updated
; ------------------------------------------------------------------------
; Start of .text segment
.CODE
; Align by 16 bytes
ALIGN 16
; Check if segment-level protection is enabled
is_protected_mode_enabled PROC PUBLIC
; Store the Machine Status Word (bits 0 through 15 of control register CR0) into AX register
smsw ax ; AX = CR0[15:0]
; Get CR0.PE flag
and ax, 0001h ; AX = AX & 0x0001
; Return AX register value to the calling procedure
ret ; IP = [SP] and SP = SP + 0x08
is_protected_mode_enabled ENDP
; End of MASM source
END