Skip to content

Commit e9a52bb

Browse files
committed
Initial commit
0 parents  commit e9a52bb

16 files changed

+1227
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Compiled Object files
5+
*.slo
6+
*.lo
7+
*.o
8+
*.obj
9+
10+
# Precompiled Headers
11+
*.gch
12+
*.pch
13+
14+
# Compiled Dynamic libraries
15+
*.so
16+
*.dylib
17+
*.dll
18+
19+
# Fortran module files
20+
*.mod
21+
*.smod
22+
23+
# Compiled Static libraries
24+
*.lai
25+
*.la
26+
*.a
27+
*.lib
28+
29+
# Executables
30+
*.exe
31+
*.out
32+
*.app

Hypervisor-Detection.sln

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hypervisor-Detection", "Hypervisor-Detection\Hypervisor-Detection.vcxproj", "{E2884040-CC52-48CA-A662-77038124191B}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|x64 = Debug|x64
11+
Debug|x86 = Debug|x86
12+
Release|x64 = Release|x64
13+
Release|x86 = Release|x86
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{E2884040-CC52-48CA-A662-77038124191B}.Debug|x64.ActiveCfg = Debug|x64
17+
{E2884040-CC52-48CA-A662-77038124191B}.Debug|x64.Build.0 = Debug|x64
18+
{E2884040-CC52-48CA-A662-77038124191B}.Debug|x86.ActiveCfg = Debug|Win32
19+
{E2884040-CC52-48CA-A662-77038124191B}.Debug|x86.Build.0 = Debug|Win32
20+
{E2884040-CC52-48CA-A662-77038124191B}.Release|x64.ActiveCfg = Release|x64
21+
{E2884040-CC52-48CA-A662-77038124191B}.Release|x64.Build.0 = Release|x64
22+
{E2884040-CC52-48CA-A662-77038124191B}.Release|x86.ActiveCfg = Release|Win32
23+
{E2884040-CC52-48CA-A662-77038124191B}.Release|x86.Build.0 = Release|Win32
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {68B39579-0F16-4F2A-9989-A4D9686E1C71}
30+
EndGlobalSection
31+
EndGlobal
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Abnormals/@EntryIndexedValue">True</s:Boolean>
3+
<s:Boolean x:Key="/Default/UserDictionary/Words/=CPUID/@EntryIndexedValue">True</s:Boolean>
4+
<s:Boolean x:Key="/Default/UserDictionary/Words/=hypervisor/@EntryIndexedValue">True</s:Boolean>
5+
<s:Boolean x:Key="/Default/UserDictionary/Words/=osvi/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/UserDictionary/Words/=regs/@EntryIndexedValue">True</s:Boolean>
7+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Virtualized/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
#include <intrin.h>
2+
#include <iostream>
3+
#include <Windows.h>
4+
#include <format>
5+
#include <functional>
6+
#include <future>
7+
#include <map>
8+
9+
const std::string ascii = R"(
10+
_ _ _
11+
| | | | (_)
12+
| |__| |_ _ _ __ ___ _ ____ ___ ___ ___ _ __
13+
| __ | | | | '_ \ / _ \ '__\ \ / / / __|/ _ \| '__|
14+
| | | | |_| | |_) | __/ | \ V /| \__ \ (_) | |
15+
|_| |_|\__, | .__/ \___|_| \_/ |_|___/\___/|_|
16+
__/ | |
17+
_____ |___/|_| _ _
18+
| __ \ | | | | (_)
19+
| | | | ___| |_ ___ ___| |_ _ ___ _ __
20+
| | | |/ _ \ __/ _ \/ __| __| |/ _ \| '_ \
21+
| |__| | __/ || __/ (__| |_| | (_) | | | |
22+
|_____/ \___|\__\___|\___|\__|_|\___/|_| |_|
23+
24+
https://github.com/void-stack
25+
26+
)";
27+
28+
#ifdef _WIN64
29+
extern "C" void __fastcall _asm_fyl2xp1(void);
30+
#endif
31+
32+
struct _cpuid_buffer_t
33+
{
34+
uint32_t EAX;
35+
uint32_t EBX;
36+
uint32_t ECX;
37+
uint32_t EDX;
38+
};
39+
40+
// resources [check #Improvement Part https://secret.club/2020/01/12/battleye-hypervisor-detection.html]
41+
bool take_time()
42+
{
43+
// If the CPUID instruction execution time is longer than the arithmetic
44+
// instruction it’s a reliable indication that the system is virtualized
45+
// because under no circumstances should the arithmetic instruction take
46+
// longer than the CPUID execution to grab vendor, or version information.
47+
// This detection will also catch those using TSC offsetting/scaling.
48+
49+
constexpr auto measure_time = 5;
50+
51+
long long __cpuid_time = 0;
52+
long long __fyl2xp1_time = 0;
53+
54+
LARGE_INTEGER frequency = {};
55+
LARGE_INTEGER start = {};
56+
LARGE_INTEGER end = {};
57+
58+
QueryPerformanceFrequency(&frequency);
59+
60+
// count the average time it takes to execute a CPUID instruction
61+
for (std::size_t i = 0; i < measure_time; ++i)
62+
{
63+
QueryPerformanceCounter(&start);
64+
_cpuid_buffer_t cpuid_data;
65+
__cpuid(reinterpret_cast<int*>(&cpuid_data), 1);
66+
QueryPerformanceCounter(&end);
67+
68+
auto delta = end.QuadPart - start.QuadPart;
69+
70+
delta *= 1000000000;
71+
delta /= frequency.QuadPart;
72+
73+
__cpuid_time += delta;
74+
}
75+
76+
// count the average time it takes to execute a FYL2XP1 instruction
77+
for (std::size_t i = 0; i < measure_time; ++i)
78+
{
79+
QueryPerformanceCounter(&start);
80+
#ifdef _WIN64
81+
_asm_fyl2xp1();
82+
#else
83+
_asm FYL2XP1
84+
#endif
85+
QueryPerformanceCounter(&end);
86+
87+
auto delta = end.QuadPart - start.QuadPart;
88+
89+
delta *= 1000000000;
90+
delta /= frequency.QuadPart;
91+
92+
__fyl2xp1_time += delta;
93+
}
94+
95+
return __fyl2xp1_time <= __cpuid_time;
96+
}
97+
98+
// resources [check https://secret.club/2020/01/12/battleye-hypervisor-detection.html] #Improvement Part
99+
bool take_time_cpuid_against_fyl2xp1()
100+
{
101+
constexpr auto measure_times = 5;
102+
auto positives = 0;
103+
auto negatives = 0;
104+
105+
// run the internal VM check multiple times to get an average result
106+
for (auto i = measure_times; i != 0; --i)
107+
take_time() ? ++positives : ++negatives;
108+
109+
// if there are more positive results than negative results, the
110+
// process is likely running inside a VM
111+
const bool decision = (positives >= negatives);
112+
113+
return decision;
114+
}
115+
116+
// resources https://secret.club/2020/04/13/how-anti-cheats-detect-system-emulation.html
117+
bool check_invalid_leaf()
118+
{
119+
constexpr unsigned int invalid_leaf = 0x04201337;
120+
constexpr unsigned int valid_leaf = 0x40000000;
121+
122+
_cpuid_buffer_t InvalidLeafResponse = {};
123+
_cpuid_buffer_t ValidLeafResponse = {};
124+
125+
__cpuid(reinterpret_cast<int32_t*>(&InvalidLeafResponse), invalid_leaf);
126+
__cpuid(reinterpret_cast<int32_t*>(&ValidLeafResponse), valid_leaf);
127+
128+
if ((InvalidLeafResponse.EAX != ValidLeafResponse.EAX) ||
129+
(InvalidLeafResponse.EBX != ValidLeafResponse.EBX) ||
130+
(InvalidLeafResponse.ECX != ValidLeafResponse.ECX) ||
131+
(InvalidLeafResponse.EDX != ValidLeafResponse.EDX))
132+
return true;
133+
134+
return false;
135+
}
136+
137+
// resources https://secret.club/2020/04/13/how-anti-cheats-detect-system-emulation.html
138+
bool check_highest_low_function_leaf()
139+
{
140+
constexpr auto queryVendorIdMagic = 0x40000000;
141+
142+
_cpuid_buffer_t regs = {};
143+
__cpuid(reinterpret_cast<int32_t*>(&regs), queryVendorIdMagic);
144+
145+
_cpuid_buffer_t reserved_regs = {};
146+
__cpuid(reinterpret_cast<int32_t*>(&reserved_regs), 1);
147+
148+
__cpuid(reinterpret_cast<int32_t*>(&reserved_regs), reserved_regs.EAX);
149+
150+
if (reserved_regs.EAX != regs.EAX ||
151+
reserved_regs.EBX != regs.EBX ||
152+
reserved_regs.ECX != regs.ECX ||
153+
reserved_regs.EDX != regs.EDX)
154+
return true;
155+
156+
return false;
157+
}
158+
159+
// resouces https://kb.vmware.com/s/article/1009458
160+
bool check_for_known_hypervisor()
161+
{
162+
_cpuid_buffer_t cpuInfo = {};
163+
__cpuid(reinterpret_cast<int32_t*>(&cpuInfo), 1);
164+
165+
if (!(cpuInfo.ECX & (1 << 31))) // check bit 31 of register ECX, which is “hypervisor present bit”
166+
return false; // if not present return
167+
168+
// we know hypervisor is present we can query the vendor id.
169+
constexpr auto queryVendorIdMagic = 0x40000000;
170+
__cpuid(reinterpret_cast<int32_t*>(&cpuInfo), queryVendorIdMagic);
171+
172+
// construct string for our vendor name
173+
constexpr auto size = 13;
174+
const auto presentVendor = new char[size];
175+
memcpy(presentVendor + 0, &cpuInfo.EBX, 4);
176+
memcpy(presentVendor + 4, &cpuInfo.ECX, 4);
177+
memcpy(presentVendor + 8, &cpuInfo.EDX, 4);
178+
presentVendor[12] = '\0';
179+
180+
// check against known vendor names
181+
const char* vendors[]{
182+
"KVMKVMKVM\0\0\0", // KVM
183+
"Microsoft Hv", // Microsoft Hyper-V or Windows Virtual PC */
184+
"VMwareVMware", // VMware
185+
"XenVMMXenVMM", // Xen
186+
"prl hyperv ", // Parallels
187+
"VBoxVBoxVBox" // VirtualBox
188+
};
189+
190+
for (const auto& vendor : vendors)
191+
{
192+
if (!memcmp(vendor, presentVendor, size))
193+
{
194+
std::cout << "\tFound known hypervisor: " << presentVendor << std::endl;
195+
return true;
196+
}
197+
}
198+
199+
std::cout << "\tFound unknown hypervisor: " << presentVendor << std::endl;
200+
return false;
201+
}
202+
203+
void arch()
204+
{
205+
if constexpr (const int* pInt = nullptr; sizeof(pInt) == 8)
206+
std::cout << "Version: x64" << std::endl;
207+
else if constexpr (sizeof(pInt) == 4)
208+
std::cout << "Version: x86" << std::endl;
209+
}
210+
211+
int main()
212+
{
213+
// test all functions
214+
const std::map<std::string_view, std::function<bool()>> callbacks = {
215+
{"Profiling CPUID against FYL2XP1", &take_time_cpuid_against_fyl2xp1},
216+
{"Checking highest low function leaf", &check_highest_low_function_leaf},
217+
{"Checking invalid leaf", &check_invalid_leaf},
218+
{"Checking for known hypervisor vendors", &check_for_known_hypervisor}
219+
};
220+
221+
std::cout << ascii << std::endl;
222+
223+
arch();
224+
225+
const auto log = [&](const std::function<bool()> callback,
226+
const std::string_view label)
227+
{
228+
const std::uint32_t condition = callback();
229+
230+
(condition
231+
? std::cout
232+
<< "* [" << label << "] ~ " << "Detected [!]"
233+
: std::cout
234+
<< "* " << label << " ~ " << "Passed [+]") << std::endl;
235+
};
236+
237+
for (const auto& [callback, value] : callbacks)
238+
log(value, callback);
239+
240+
std::cin.get();
241+
}

0 commit comments

Comments
 (0)