added GetCurrentProcessorNumber project

This commit is contained in:
winterknife
2025-07-07 10:39:59 -04:00
parent 834bd6dc12
commit 6a175cd31f
12 changed files with 606 additions and 2 deletions
+4
View File
@@ -11,6 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PagingDbgExt", "PagingDbgEx
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReadIDTDbgExt", "ReadIDTDbgExt\ReadIDTDbgExt.vcxproj", "{32175898-45C7-4C47-990E-EBB9DA9D0992}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GetCurrentProcessorNumber", "GetCurrentProcessorNumber\GetCurrentProcessorNumber.vcxproj", "{4A00FFAF-5B55-4BAB-B681-4DB692B25001}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
@@ -24,6 +26,8 @@ Global
{4321EA53-183E-4104-887D-5CBFC14E4211}.Release|x64.Build.0 = Release|x64
{32175898-45C7-4C47-990E-EBB9DA9D0992}.Release|x64.ActiveCfg = Release|x64
{32175898-45C7-4C47-990E-EBB9DA9D0992}.Release|x64.Build.0 = Release|x64
{4A00FFAF-5B55-4BAB-B681-4DB692B25001}.Release|x64.ActiveCfg = Release|x64
{4A00FFAF-5B55-4BAB-B681-4DB692B25001}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+2 -2
View File
@@ -10,7 +10,7 @@
- `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.
- Sample code that demonstrates the usage of the `SMSW` instruction to fetch 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`
@@ -19,7 +19,7 @@
- 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 . . .
@@ -0,0 +1,85 @@
<?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>{4a00ffaf-5b55-4bab-b681-4db692b25001}</ProjectGuid>
<RootNamespace>GetCurrentProcessorNumber</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</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>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>Lib\\msvcrt_x64.lib;Kernel32.lib;User32.lib</AdditionalDependencies>
<AdditionalOptions>/EMITPOGOPHASEINFO /NOVCFEATURE /NOCOFFGRPINFO /FILEALIGN:0x200 /PDBALTPATH:$(ProjectName).pdb /Brepro /RELEASE /EMITTOOLVERSIONINFO:NO %(AdditionalOptions)</AdditionalOptions>
<ShowProgress>LinkVerbose</ShowProgress>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Src\ExeMain.cpp" />
<ClCompile Include="Src\GetCurrentProcessorNumber.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Inc\BaseDataTypes.h" />
<ClInclude Include="Inc\Common.h" />
<ClInclude Include="Inc\GetCurrentProcessorNumber.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
@@ -0,0 +1,32 @@
<?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>
<ClCompile Include="Src\ExeMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Src\GetCurrentProcessorNumber.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</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\GetCurrentProcessorNumber.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -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-07-05 Updated
// ========================================================================
// ========================================================================
// Pragmas
// ========================================================================
#pragma once
// Specify program entry point
#pragma comment(linker, "/ENTRY:ExeEntry")
// 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__ "GetCurrentProcessorNumber"
// 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
@@ -0,0 +1,71 @@
// ========================================================================
// File: GetCurrentProcessorNumber.h
//
// Author: winterknife
//
// Description: Header file for GetCurrentProcessorNumber.cpp source file
//
// Modifications:
// 2025-07-01 Created
// 2025-07-06 Updated
// ========================================================================
// ========================================================================
// Pragmas
// ========================================================================
#pragma once
// ========================================================================
// Includes
// ========================================================================
#include "Common.h"
// ========================================================================
// Macros
// ========================================================================
#pragma region MACROS
#if defined(_M_X64)
#define KGDT_R3_TEB 0x50
#elif defined(_M_IX86)
#define KGDT_R3_TEB 0x38
#endif
#define RPL_MASK 0x03
#pragma endregion
// ========================================================================
// Structures/Enumerations/Unions
// ========================================================================
#pragma region STRUCTS_ENUMS_UNIONS
// CPUID structure for using the return data of CPUID in the application
typedef struct _CPUID_REGISTERS {
DWORD dwEAX;
DWORD dwEBX;
DWORD dwECX;
DWORD dwEDX;
} CPUID_REGISTERS, *PCPUID_REGISTERS;
#pragma endregion
// ========================================================================
// C routine declarations
// ========================================================================
#pragma region DECLARATIONS
/// @brief Retrieve the number of the logical processor on which the calling thread is running
/// @param None
/// @return Returns the current processor number (only valid for systems with fewer than 64 logical processors - processor group 0)
_Success_(return != -1) _Must_inspect_result_ _IRQL_requires_max_(HIGH_LEVEL)
extern "C" __declspec(noinline) DWORD __stdcall get_current_processor_number(
VOID
);
#pragma endregion
Binary file not shown.
Binary file not shown.
+38
View File
@@ -0,0 +1,38 @@
# EVENSTAR - GetCurrentProcessorNumber
## Version
- `v1.0.0`
## Brief
- `ISA: x86`
- `Mode: Protected, Long`
- `Bitness: 32-bit, 64-bit`
- `CPL: 0, 3`
- `OS: Windows`
- `Language: C`
- Sample code that demonstrates the usage of the `RDPID`, `RDTSCP`, and the `LSL` instructions to fetch the current logical processor's ID
## Usage
```
C:\pub\bld>GetCurrentProcessorNumber.exe
[DBG]: [*] GetCurrentProcessorNumber Built Jul 6 2025 16:46:57
Press any key to continue . . .
[DBG]: [+] Logical processor count = 0n2
[DBG]: [+] Pinned all the threads of the current process to logical processor = 0n0
[DBG]: [+] Current logical processor's ID = 0n0
[DBG]: [+] Pinned all the threads of the current process to logical processor = 0n1
[DBG]: [+] Current logical processor's ID = 0n1
Press any key to continue . . .
```
## Tested OS Versions
- `Windows 11 21H2 Build 22000 Revision 675 64-bit`
## References
1. [Alex Ionescus Blog - Solution to Challenge](https://www.alex-ionescu.com/solution-to-challenge/)
2. [Processor Groups](https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups)
3. [GetCurrentProcessorNumber function (processthreadsapi.h)](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessornumber)
4. [Multiple Processors](https://learn.microsoft.com/en-us/windows/win32/procthread/multiple-processors)
5. [On pinning and isolating CPU cores](https://manuel.bernhardt.io/posts/2023-11-16-core-pinning/)
6. [C++11 threads, affinity and hyperthreading](https://eli.thegreenplace.net/2016/c11-threads-affinity-and-hyperthreading/)
7. [Intel® Intrinsics Guide](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=5089,5263)
+76
View File
@@ -0,0 +1,76 @@
// ========================================================================
// File: ExeMain.cpp
//
// Author: winterknife
//
// Description: Source file that contains the EXE entry point
//
// Modifications:
// 2025-07-01 Created
// 2025-07-06 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/Common.h"
#include "../Inc/GetCurrentProcessorNumber.h"
#include <process.h>
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
#pragma CODE_BEGIN
/// @brief EXE entry point
/// @param None
/// @return None
extern "C" __declspec(noreturn) VOID __stdcall ExeEntry(
VOID
) {
DEBUG_PRINT("[*] %s Built %s %s\n", __MODULE__, __DATE__, __TIME__);
system("PAUSE");
if (*(BYTE*)(0x7FFE0000ULL + 0x02D4))
__debugbreak();
__nop();
__nop();
__nop();
// Init local variables
DWORD dwActiveProcessorCount = 0;
DWORD dwIndex = 0;
DWORD_PTR dwptrProcessorAffinityMask = 0;
// Get the number of active logical processors in the system
dwActiveProcessorCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
DEBUG_PRINT("[+] Logical processor count = 0n%I32u\n", dwActiveProcessorCount);
// Loop through all processors
for (dwIndex = 0; dwIndex < dwActiveProcessorCount; dwIndex++) {
// Set a processor affinity mask (CPU pinning) for all the threads of the current process
dwptrProcessorAffinityMask = __ll_lshift(0x1, dwIndex);
if (!SetProcessAffinityMask(GetCurrentProcess(), dwptrProcessorAffinityMask)) {
DEBUG_PRINT("[-] SetProcessAffinityMask failed: 0n%I32u\n", GetLastError());
goto cleanup;
}
DEBUG_PRINT("[+] Pinned all the threads of the current process to logical processor = 0n%I32u\n", dwIndex);
// Get current processor number
DEBUG_PRINT("[+] Current logical processor's ID = 0n%I32u\n", get_current_processor_number());
}
// Cleanup
cleanup:
system("PAUSE");
ExitProcess(0);
}
#pragma CODE_END
#pragma endregion
@@ -0,0 +1,69 @@
// ========================================================================
// File: GetCurrentProcessorNumber.cpp
//
// Author: winterknife
//
// Description: Source file that contains the necessary routines to retrieve
// the current logical processor ID
//
// Modifications:
// 2025-07-01 Created
// 2025-07-07 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "../Inc/GetCurrentProcessorNumber.h"
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
_Use_decl_annotations_
DWORD __stdcall get_current_processor_number(
VOID
) {
// Init local variables
CPUID_REGISTERS cpuidRegisters; ZERO_MEMORY(&cpuidRegisters, sizeof(CPUID_REGISTERS));
DWORD dwIa32TscAux = 0;
DWORD dwSegmentLimit = 0;
QWORD qwRflags = 0;
// Check if processor supports the RDPID instruction for reading the IA32_TSC_AUX MSR value
// RDPID instruction support is only available since Sunny Cove Intel microarchitecture (2019)
__cpuidex((int*)&cpuidRegisters, 0x07, 0x00);
if (_bittest((const LONG*)&cpuidRegisters.dwECX, 22)) {
return _rdpid_u32(); // RDPID — Read Processor ID
}
else {
// Check if processor supports the RDTSCP instruction and the IA32_TSC_AUX MSR
// RDTSCP and IA32_TSC_AUX support are only available since Nehalem Intel microarchitecture (2008)
__cpuidex((int*)&cpuidRegisters, 0x80000001, 0x00);
if (_bittest((const LONG*)&cpuidRegisters.dwEDX, 27)) {
__rdtscp((unsigned int*)&dwIa32TscAux); // RDTSCP — Read Time-Stamp Counter and Processor ID
return dwIa32TscAux;
}
else {
// Get the segment limit of the 32-bit TEB segment
dwSegmentLimit = __segmentlimit(KGDT_R3_TEB | RPL_MASK); // LSL — Load Segment Limit
// Check if EFLAGS.ZF is set
// If the segment descriptor cannot be accessed or is an invalid type for the instruction, the EFLAGS.ZF flag is cleared
qwRflags = __readeflags(); // PUSHF/PUSHFD/PUSHFQ — Push EFLAGS Register Onto the Stack
if (_bittest64((const LONG64*)&qwRflags, 6)) {
// Read the processor ID from the segment limit
// In Windows, the segment limit of the segment descriptor selected by the TEB selector contains the current logical processor's ID in bits 14 to 19
return (dwSegmentLimit >> 0xE);
}
else {
return 0xFFFFFFFFUL;
}
}
}
}
#pragma endregion