1919 * - Full credits: https://github.com/kernelwernel/VMAware#credits-and-contributors-%EF%B8%8F
2020 * - License: GPL-3.0
2121 *
22+ *
2223 * ================================ SECTIONS ==================================
23- * - enums for publicly accessible techniques => line 252
24- * - struct for internal cpu operations => line 447
25- * - struct for internal memoization => line 684
26- * - struct for internal utility functions => line 757
27- * - struct for internal core components => line 5713
28- * - start of internal VM detection techniques => line 1423
29- * - start of public VM detection functions => line 5786
30- * - start of externally defined variables => line 6053
24+ * - enums for publicly accessible techniques => line 282
25+ * - struct for internal cpu operations => line 480
26+ * - struct for internal memoization => line 772
27+ * - struct for internal utility functions => line 834
28+ * - struct for internal core components => line 7073
29+ * - start of internal VM detection techniques => line 1510
30+ * - start of public VM detection functions => line 7187
31+ * - start of externally defined variables => line 7487
32+ *
33+ *
34+ * ================================ EXAMPLE ==================================
35+ #include "vmaware.hpp"
36+ #include <iostream>
37+
38+ int main() {
39+ if (VM::detect()) {
40+ std::cout << "Virtual machine detected!" << std::endl;
41+ std::cout << "VM name: " << VM::brand() << std::endl;
42+ } else {
43+ std::cout << "Running in baremetal" << std::endl;
44+ }
45+
46+ std::cout << "VM certainty: " << (int)VM::percentage() << "%" << std::endl;
47+ }
48+
3149 */
3250
51+
3352#if (defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__))
3453#define MSVC 1
3554#define LINUX 0
@@ -348,7 +367,7 @@ struct VM {
348367 UPTIME,
349368 ODD_CPU_THREADS,
350369 INTEL_THREAD_MISMATCH,
351- INTEL_XEON_THREAD_MISMATCH ,
370+ XEON_THREAD_MISMATCH ,
352371 EXTREME,
353372 NO_MEMO,
354373 WIN_HYPERV_DEFAULT,
@@ -589,20 +608,22 @@ struct VM {
589608#endif
590609 }
591610
592- [[nodiscard]] static std::string get_model () {
611+ struct model_struct {
612+ bool found;
613+ bool is_xeon;
614+ bool is_i_series;
615+ std::string string;
616+ };
617+
618+ [[nodiscard]] static model_struct get_model () {
593619 const std::string brand = get_brand ();
594620
595621 constexpr const char * intel_i_series_regex = " i[0-9]-[A-Z0-9]{1,7}" ;
596622 constexpr const char * intel_xeon_series_regex = " [DEW]-[A-Z0-9]{1,7}" ;
597623
598- constexpr std::array<const char *, 2 > regex_templates {{
599- intel_i_series_regex,
600- intel_xeon_series_regex
601- }};
602-
603624 std::string match_str = " " ;
604625
605- for (const auto regex : regex_templates) {
626+ auto match = [&] (const char * regex) -> bool {
606627 std::regex pattern (regex);
607628
608629 auto words_begin = std::sregex_iterator (brand.begin (), brand.end (), pattern);
@@ -614,11 +635,32 @@ struct VM {
614635 }
615636
616637 if (!match_str.empty ()) {
617- return match_str;
638+ return true ;
639+ }
640+
641+ return false ;
642+ };
643+
644+ bool found = false ;
645+ bool is_xeon = false ;
646+ bool is_i_series = false ;
647+ std::string string = " " ;
648+
649+ if (cpu::is_intel ()) {
650+ if (match (intel_i_series_regex)) {
651+ found = true ;
652+ is_i_series = true ;
653+ string = match_str;
654+ } else if (match (intel_xeon_series_regex)) {
655+ found = true ;
656+ is_xeon = true ;
657+ string = match_str;
618658 }
619659 }
620660
621- return " " ;
661+ // no AMD (for now)
662+
663+ return model_struct{ found, is_xeon, is_i_series, string };
622664 };
623665
624666#if (CPP >= 17)
@@ -5877,7 +5919,7 @@ struct VM {
58775919 /* *
58785920 * @brief Check for CPUs that don't match their thread count
58795921 * @category All, x86
5880- * @links https://en.wikipedia.org/wiki/List_of_Intel_Core_processors
5922+ * @link https://en.wikipedia.org/wiki/List_of_Intel_Core_processors
58815923 */
58825924 [[nodiscard]] static bool intel_thread_mismatch () try {
58835925 if (core::disabled (INTEL_THREAD_MISMATCH)) {
@@ -5891,15 +5933,19 @@ struct VM {
58915933 return false ;
58925934 }
58935935
5894- const std::string model = cpu::get_model ();
5936+ const cpu::model_struct model = cpu::get_model ();
58955937
5896- debug (" INTEL_THREAD_MISMATCH: CPU model = " , model);
5938+ if (!model.found ) {
5939+ return false ;
5940+ }
58975941
5898- if (model.empty () ) {
5942+ if (! model.is_i_series ) {
58995943 return false ;
59005944 }
59015945
5902- std::unordered_map<std::string, u8 > thread_database = {
5946+ debug (" INTEL_THREAD_MISMATCH: CPU model = " , model.string );
5947+
5948+ const std::unordered_map<std::string, u8 > thread_database = {
59035949 // i3 series
59045950 { " i3-1000G1" , 4 },
59055951 { " i3-1000G4" , 4 },
@@ -6856,11 +6902,11 @@ struct VM {
68566902 };
68576903
68586904 // basically means "if there's 0 matches in the database, return false"
6859- if (thread_database.count (model) == 0 ) {
6905+ if (thread_database.count (model. string ) == 0 ) {
68606906 return false ;
68616907 }
68626908
6863- const u8 threads = thread_database.at (model);
6909+ const u8 threads = thread_database.at (model. string );
68646910
68656911 debug (" INTEL_THREAD_MISMATCH: thread in database = " , static_cast <u32 >(threads));
68666912
@@ -6873,6 +6919,158 @@ struct VM {
68736919 }
68746920
68756921
6922+ /* *
6923+ * @brief Check for Intel Xeon CPUs that don't match their thread count
6924+ * @category All, x86
6925+ * @link https://en.wikipedia.org/wiki/List_of_Intel_Core_processors
6926+ */
6927+ [[nodiscard]] static bool xeon_thread_mismatch () try {
6928+ if (core::disabled (XEON_THREAD_MISMATCH)) {
6929+ return false ;
6930+ }
6931+
6932+ #if (!x86)
6933+ return false ;
6934+ #else
6935+ if (!cpu::is_intel ()) {
6936+ return false ;
6937+ }
6938+
6939+ const cpu::model_struct model = cpu::get_model ();
6940+
6941+ if (!model.found ) {
6942+ return false ;
6943+ }
6944+
6945+ if (!model.is_i_series ) {
6946+ return false ;
6947+ }
6948+
6949+ debug (" XEON_THREAD_MISMATCH: CPU model = " , model.string );
6950+
6951+ const std::unordered_map<std::string, u8 > xeon_thread_database = {
6952+ // Xeon D
6953+ { " D-1518" , 8 },
6954+ { " D-1520" , 8 },
6955+ { " D-1521" , 8 },
6956+ { " D-1527" , 8 },
6957+ { " D-1528" , 12 },
6958+ { " D-1529" , 8 },
6959+ { " D-1531" , 12 },
6960+ { " D-1537" , 16 },
6961+ { " D-1539" , 16 },
6962+ { " D-1540" , 16 },
6963+ { " D-1541" , 16 },
6964+ { " D-1548" , 16 },
6965+ { " D-1557" , 24 },
6966+ { " D-1559" , 24 },
6967+ { " D-1567" , 24 },
6968+ { " D-1571" , 32 },
6969+ { " D-1577" , 32 },
6970+ { " D-1581" , 32 },
6971+ { " D-1587" , 32 },
6972+ { " D-1513N" , 8 },
6973+ { " D-1523N" , 8 },
6974+ { " D-1533N" , 12 },
6975+ { " D-1543N" , 16 },
6976+ { " D-1553N" , 16 },
6977+ { " D-1602" , 4 },
6978+ { " D-1612" , 8 },
6979+ { " D-1622" , 8 },
6980+ { " D-1627" , 8 },
6981+ { " D-1632" , 16 },
6982+ { " D-1637" , 12 },
6983+ { " D-1623N" , 8 },
6984+ { " D-1633N" , 12 },
6985+ { " D-1649N" , 16 },
6986+ { " D-1653N" , 16 },
6987+ { " D-2141I" , 16 },
6988+ { " D-2161I" , 24 },
6989+ { " D-2191" , 36 },
6990+ { " D-2123IT" , 8 },
6991+ { " D-2142IT" , 16 },
6992+ { " D-2143IT" , 16 },
6993+ { " D-2163IT" , 24 },
6994+ { " D-2173IT" , 28 },
6995+ { " D-2183IT" , 32 },
6996+ { " D-2145NT" , 16 },
6997+ { " D-2146NT" , 16 },
6998+ { " D-2166NT" , 24 },
6999+ { " D-2177NT" , 28 },
7000+ { " D-2187NT" , 32 },
7001+
7002+ // Xeon E
7003+ { " E-2104G" , 4 },
7004+ { " E-2124" , 4 },
7005+ { " E-2124G" , 4 },
7006+ { " E-2126G" , 6 },
7007+ { " E-2134" , 8 },
7008+ { " E-2136" , 12 },
7009+ { " E-2144G" , 8 },
7010+ { " E-2146G" , 12 },
7011+ { " E-2174G" , 8 },
7012+ { " E-2176G" , 12 },
7013+ { " E-2186G" , 12 },
7014+ { " E-2176M" , 12 },
7015+ { " E-2186M" , 12 },
7016+ { " E-2224" , 4 },
7017+ { " E-2224G" , 4 },
7018+ { " E-2226G" , 6 },
7019+ { " E-2234" , 8 },
7020+ { " E-2236" , 12 },
7021+ { " E-2244G" , 8 },
7022+ { " E-2246G" , 12 },
7023+ { " E-2274G" , 8 },
7024+ { " E-2276G" , 12 },
7025+ { " E-2278G" , 16 },
7026+ { " E-2286G" , 12 },
7027+ { " E-2288G" , 16 },
7028+ { " E-2276M" , 12 },
7029+ { " E-2286M" , 16 },
7030+
7031+ // Xeon W
7032+ { " W-2102" , 4 },
7033+ { " W-2104" , 4 },
7034+ { " W-2123" , 8 },
7035+ { " W-2125" , 8 },
7036+ { " W-2133" , 12 },
7037+ { " W-2135" , 12 },
7038+ { " W-2140B" , 16 },
7039+ { " W-2145" , 16 },
7040+ { " W-2150B" , 20 },
7041+ { " W-2155" , 20 },
7042+ { " W-2170B" , 28 },
7043+ { " W-2175" , 28 },
7044+ { " W-2191B" , 36 },
7045+ { " W-2195" , 36 },
7046+ { " W-3175X" , 56 },
7047+ { " W-3223" , 16 },
7048+ { " W-3225" , 16 },
7049+ { " W-3235" , 24 },
7050+ { " W-3245" , 32 },
7051+ { " W-3245M" , 32 },
7052+ { " W-3265" , 48 },
7053+ { " W-3265M" , 48 },
7054+ { " W-3275" , 56 },
7055+ { " W-3275M" , 56 }
7056+ };
7057+
7058+ if (xeon_thread_database.count (model.string ) == 0 ) {
7059+ return false ;
7060+ }
7061+
7062+ const u8 threads = xeon_thread_database.at (model.string );
7063+
7064+ debug (" XEON_THREAD_MISMATCH: thread in database = " , static_cast <u32 >(threads));
7065+
7066+ return (std::thread::hardware_concurrency () != threads);
7067+ #endif
7068+ }
7069+ catch (...) {
7070+ debug (" INTEL_THREAD_MISMATCH: catched error, returned false" );
7071+ return false ;
7072+ }
7073+
68767074 struct core {
68777075 MSVC_DISABLE_WARNING (PADDING)
68787076 struct technique {
@@ -7462,7 +7660,8 @@ const std::map<VM::u8, VM::core::technique> VM::core::table = {
74627660 { VM::MUTEX, { 85 , VM::mutex }},
74637661 { VM::UPTIME, { 10 , VM::uptime }},
74647662 { VM::ODD_CPU_THREADS, { 80 , VM::odd_cpu_threads }},
7465- { VM::INTEL_THREAD_MISMATCH, { 70 , VM::intel_thread_mismatch }}
7663+ { VM::INTEL_THREAD_MISMATCH, { 85 , VM::intel_thread_mismatch }},
7664+ { VM::XEON_THREAD_MISMATCH, { 85 , VM::xeon_thread_mismatch }}
74667665
74677666 // __TABLE_LABEL, add your technique above
74687667 // { VM::FUNCTION, { POINTS, FUNCTION_POINTER }}
0 commit comments