Skip to content

Commit df5d47c

Browse files
authored
Merge pull request #315 from kernelwernel/dev
Dev
2 parents 71baaea + 0f919f9 commit df5d47c

File tree

3 files changed

+67
-36
lines changed

3 files changed

+67
-36
lines changed

src/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
| `vmaware.hpp` | Official and original library header in GPL-3.0, most likely what you're looking for. |
55
| `vmaware_MIT.hpp` | Same as above but in MIT. But this removes 7 techniques out of 118 |
66

7+
<br>
78

89
> [!IMPORTANT]
910
> The main branch is much more updated with features that haven't been added yet to the latest release. However, they are experimental.
10-
> If you want something far more stable, it's highly recommended to use the ones in the release section instead.
11+
> If you want something far more stable, it's highly recommended to use the ones in the release section instead.
12+
>
13+
> On the other hand, testing the main branch version is advised so that feedback can be given back to make the library better.

src/cli.cpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,18 @@
2929

3030
#if (defined(__GNUC__) || defined(__linux__))
3131
#include <unistd.h>
32-
#define LINUX 1
32+
#define CLI_LINUX 1
3333
#else
34-
#define LINUX 0
34+
#define CLI_LINUX 0
3535
#endif
3636

37+
3738
#if (defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__))
38-
#define WINDOWS 1
39+
#define CLI_WINDOWS 1
3940
#define WIN32_LEAN_AND_MEAN
4041
#include <windows.h>
4142
#else
42-
#define WINDOWS 0
43+
#define CLI_WINDOWS 0
4344
#endif
4445

4546
#if (_MSC_VER)
@@ -102,9 +103,9 @@ std::string not_detected = ("[" + red + "NOT DETECTED" + ansi_exit + "]");
102103
std::string no_support = ("[ " + grey + "NO SUPPORT" + ansi_exit + " ]");
103104
std::string no_perms = ("[" + grey + " NO PERMS " + ansi_exit + "]");
104105
std::string note = ("[ NOTE ]");
105-
std::string disabled = ("[" + red + " DISABLED " + ansi_exit + "]");
106+
std::string disabled = ("[" + grey + " DISABLED " + ansi_exit + "]");
106107

107-
#if (WINDOWS)
108+
#if (CLI_WINDOWS)
108109
class win_ansi_enabler_t
109110
{
110111
public:
@@ -281,7 +282,7 @@ nsjail
281282
}
282283

283284

284-
#if (LINUX)
285+
#if (CLI_LINUX)
285286
bool is_admin() {
286287
const uid_t uid = getuid();
287288
const uid_t euid = geteuid();
@@ -297,7 +298,7 @@ bool is_admin() {
297298

298299

299300
bool are_perms_required(const VM::enum_flags flag) {
300-
#if (LINUX)
301+
#if (CLI_LINUX)
301302
if (is_admin()) {
302303
return false;
303304
}
@@ -508,10 +509,10 @@ bool is_unsupported(VM::enum_flags flag) {
508509

509510

510511
#if __cplusplus >= 201703L
511-
if constexpr (LINUX) {
512+
if constexpr (CLI_LINUX) {
512513
return linux_techniques(flag);
513514
}
514-
else if constexpr (WINDOWS) {
515+
else if constexpr (CLI_WINDOWS) {
515516
return windows_techniques(flag);
516517
}
517518
else if constexpr (APPLE) {
@@ -521,11 +522,11 @@ bool is_unsupported(VM::enum_flags flag) {
521522
return true;
522523
}
523524
#else
524-
#if LINUX
525+
#if (CLI_LINUX)
525526
return linux_techniques(flag);
526-
#elif WINDOWS
527+
#elif (CLI_WINDOWS)
527528
return windows_techniques(flag);
528-
#elif APPLE
529+
#elif (APPLE)
529530
return macos_techniques(flag);
530531
#else
531532
return true;
@@ -634,7 +635,7 @@ std::string vm_description(const std::string& vm_brand) {
634635
{ brands::AZURE_HYPERV, "Azure Hyper-V is Microsoft's cloud-optimized hypervisor variant powering Azure VMs. Implements Azure-specific virtual devices like NVMe Accelerated Networking and vTPMs. Supports nested virtualization for running Hyper-V/containers within Azure VMs, enabling cloud-based CI/CD pipelines and dev/test environments." },
635636
{ brands::NANOVISOR, "NanoVisor is a Hyper-V modification serving as the host OS of Xbox's devices: the Xbox System Software. It contains 2 partitions: the \"Exclusive\" partition is a custom VM for games, while the other partition, called the \"Shared\" partition is a custom VM for running multiple apps including the OS itself. The OS was based on Windows 8 Core at the Xbox One launch in 2013." },
636637
{ brands::SIMPLEVISOR, "SimpleVisor is a minimalist Intel VT-x hypervisor by Alex Ionescu for Windows/Linux research. Demonstrates EPT-based memory isolation and hypercall handling. Used to study VM escapes and hypervisor rootkits, with hooks for intercepting CR3 changes and MSR accesses." },
637-
{ brands::HYPERV_ARTIFACT, "The CLI detected Hyper-V operating as a Type 1 hypervisor, not as a guest virtual machine. Althought your hardware/firmware signatures match Microsoft's Hyper-V architecture, we determined that you're running on baremetal, with the help of our \"Hyper-X\" mechanism that differentiates between the root partition (host OS) and guest VM environments. This prevents false positives, as Windows sometimes runs under Hyper-V (type 1) hypervisor." },
638+
{ brands::HYPERV_ARTIFACT, "The CLI detected Hyper-V operating as a Type 1 hypervisor, not as a guest virtual machine. Although your hardware/firmware signatures match Microsoft's Hyper-V architecture, we determined that you're running on baremetal, with the help of our \"Hyper-X\" mechanism that differentiates between the root partition (host OS) and guest VM environments. This prevents false positives, as Windows sometimes runs under Hyper-V (type 1) hypervisor." },
638639
{ brands::UML, "User-Mode Linux (UML) allows running Linux kernels as user-space processes using ptrace-based virtualization. Primarily used for kernel debugging and network namespace testing. Offers lightweight isolation without hardware acceleration, but requires host/guest kernel version matching for stable operation." },
639640
{ brands::POWERVM, "IBM PowerVM is a type 1 hypervisor for POWER9/10 systems, supporting Live Partition Mobility and Shared Processor Pools. Implements VIOS (Virtual I/O Server) for storage/networking virtualization, enabling concurrent AIX, IBM i, and Linux workloads with RAS features like predictive failure analysis." },
640641
{ brands::GCE, "Google Compute Engine (GCE) utilizes KVM-based virtualization with custom Titanium security chips for hardware root of trust. Features live migration during host maintenance and shielded VMs with UEFI secure boot. Underpins Google Cloud's Confidential Computing offering using AMD SEV-SNP memory encryption." },
@@ -676,7 +677,7 @@ std::string vm_description(const std::string& vm_brand) {
676677
* @copyright MIT
677678
*/
678679
[[nodiscard]] static bool anyrun_driver() {
679-
#if (!WINDOWS)
680+
#if (!CLI_WINDOWS)
680681
return false;
681682
#else
682683
HANDLE hFile;
@@ -710,7 +711,7 @@ std::string vm_description(const std::string& vm_brand) {
710711
* @copyright MIT
711712
*/
712713
[[nodiscard]] static bool anyrun_directory() {
713-
#if (!WINDOWS)
714+
#if (!CLI_WINDOWS)
714715
return false;
715716
#else
716717
NTSTATUS status;
@@ -771,7 +772,7 @@ void checker(const VM::enum_flags flag, const char* message) {
771772
enum_name = grey + " [VM::" + VM::flag_to_string(flag) + "]" + ansi_exit;
772773
}
773774

774-
#if (LINUX)
775+
#if (CLI_LINUX)
775776
if (are_perms_required(flag)) {
776777
if (arg_bitset.test(COMPACT)) {
777778
return;
@@ -810,7 +811,7 @@ void checker(const VM::enum_flags flag, const char* message) {
810811
// that are embedded in the CLI because it was removed in the lib as of 2.0
811812
void checker(const std::function<bool()>& func, const char* message) {
812813
#if __cplusplus >= 201703L
813-
if constexpr (!WINDOWS) {
814+
if constexpr (!CLI_WINDOWS) {
814815
if (arg_bitset.test(VERBOSE)) {
815816
unsupported_count++;
816817
}
@@ -822,7 +823,7 @@ void checker(const std::function<bool()>& func, const char* message) {
822823
supported_count++;
823824
}
824825
#else
825-
#if !WINDOWS
826+
#if !CLI_WINDOWS
826827
if (arg_bitset.test(VERBOSE)) {
827828
unsupported_count++;
828829
}
@@ -875,7 +876,7 @@ void general() {
875876
notes_enabled = true;
876877
}
877878

878-
#if (LINUX)
879+
#if (CLI_LINUX)
879880
if (notes_enabled && !is_admin()) {
880881
std::cout << note << " Running under root might give better results\n";
881882
}
@@ -1011,13 +1012,13 @@ void general() {
10111012
{
10121013
std::string brand = vm.brand;
10131014

1014-
if (is_anyrun && (brand == "Unknown")) {
1015+
if (is_anyrun && (brand == brands::NULL_BRAND)) {
10151016
brand = "ANY.RUN";
10161017
}
10171018

10181019
const bool is_red = (
1019-
(brand == "Unknown") ||
1020-
(brand == "Hyper-V artifact (not an actual VM)")
1020+
(brand == brands::NULL_BRAND) ||
1021+
(brand == brands::HYPERV_ARTIFACT)
10211022
);
10221023

10231024
std::cout << bold << "VM brand: " << ansi_exit << (is_red ? red : green) << brand << ansi_exit << "\n";
@@ -1030,11 +1031,11 @@ void general() {
10301031
std::string color = "";
10311032
std::string &type = vm.type;
10321033

1033-
if (is_anyrun && (type == "Unknown")) {
1034+
if (is_anyrun && (type == brands::NULL_BRAND)) {
10341035
type = "Sandbox";
10351036
}
10361037

1037-
if (type == "Unknown") {
1038+
if (type == brands::NULL_BRAND) {
10381039
color = red;
10391040
} else {
10401041
color = green;
@@ -1184,7 +1185,7 @@ void general() {
11841185

11851186

11861187
int main(int argc, char* argv[]) {
1187-
#if (WINDOWS)
1188+
#if (CLI_WINDOWS)
11881189
win_ansi_enabler_t ansi_enabler;
11891190
#endif
11901191

@@ -1311,7 +1312,7 @@ int main(int argc, char* argv[]) {
13111312
if (arg_bitset.test(BRAND)) {
13121313
std::string brand = VM::brand(VM::NO_MEMO, VM::MULTIPLE, settings());
13131314

1314-
if (is_anyrun && (brand == "Unknown")) {
1315+
if (is_anyrun && (brand == brands::NULL_BRAND)) {
13151316
brand = "ANY.RUN";
13161317
}
13171318

@@ -1323,7 +1324,7 @@ int main(int argc, char* argv[]) {
13231324
if (arg_bitset.test(TYPE)) {
13241325
std::string type = VM::type(VM::NO_MEMO, VM::MULTIPLE, settings());
13251326

1326-
if (is_anyrun && (type == "Unknown")) {
1327+
if (is_anyrun && (type == brands::NULL_BRAND)) {
13271328
type = "Sandbox";
13281329
}
13291330

@@ -1336,7 +1337,7 @@ int main(int argc, char* argv[]) {
13361337
std::string conclusion = VM::conclusion(VM::NO_MEMO, VM::MULTIPLE, settings());
13371338

13381339
if (is_anyrun) {
1339-
const std::string original = "Unknown";
1340+
const std::string original = brands::NULL_BRAND;
13401341
const std::string new_brand = "ANY.RUN";
13411342

13421343
replace(conclusion, original, new_brand);

src/vmaware.hpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ MSVC_DISABLE_WARNING(ASSIGNMENT_OPERATOR NO_INLINE_FUNC SPECTRE)
468468
* TL;DR I have wonky fingers :(
469469
*/
470470
namespace brands {
471+
static constexpr const char* NULL_BRAND = "Unknown";
471472
static constexpr const char* VBOX = "VirtualBox";
472473
static constexpr const char* VMWARE = "VMware";
473474
static constexpr const char* VMWARE_EXPRESS = "VMware Express";
@@ -534,7 +535,6 @@ namespace brands {
534535
static constexpr const char* NOIRVISOR = "NoirVisor";
535536
static constexpr const char* QIHOO = "Qihoo 360 Sandbox";
536537
static constexpr const char* NSJAIL = "nsjail";
537-
static constexpr const char* NULL_BRAND = "Unknown";
538538
}
539539

540540

@@ -1200,12 +1200,11 @@ struct VM {
12001200
// memoization
12011201
struct memo {
12021202
private:
1203-
using result_t = bool;
12041203
using points_t = u8;
12051204

12061205
public:
12071206
struct data_t {
1208-
result_t result;
1207+
bool result;
12091208
points_t points;
12101209
};
12111210

@@ -1214,7 +1213,7 @@ struct VM {
12141213
static flagset cache_keys;
12151214

12161215
public:
1217-
static void cache_store(const u16 technique_macro, const result_t result, const points_t points) {
1216+
static void cache_store(const u16 technique_macro, const bool result, const points_t points) {
12181217
cache_table[technique_macro] = { result, points };
12191218
cache_keys.set(technique_macro);
12201219
}
@@ -10269,7 +10268,7 @@ struct VM {
1026910268
return false;
1027010269
}
1027110270

10272-
[[nodiscard]] static bool is_setting_flag_set(const flagset& flags) {
10271+
[[nodiscard]] static bool is_setting_flag_set(const flagset& flags) {
1027310272
for (std::size_t i = settings_begin; i < settings_end; i++) {
1027410273
if (flags.test(i)) {
1027510274
return true;
@@ -10963,10 +10962,13 @@ struct VM {
1096310962
// brand strings will be outputted if there's a conflict)
1096410963
const bool is_multiple = core::is_enabled(flags, MULTIPLE);
1096510964

10965+
// used for later
10966+
u16 score = 0;
10967+
1096610968
// are all the techiques already run? if not, run them
1096710969
// to fetch the necessary info to determine the brand
1096810970
if (!memo::all_present() || core::is_enabled(flags, NO_MEMO)) {
10969-
core::run_all(flags);
10971+
score = core::run_all(flags);
1097010972
}
1097110973

1097210974
// check if the result is already cached and return that instead
@@ -11148,6 +11150,25 @@ struct VM {
1114811150
merge(TMP_VMWARE_HARD, TMP_WORKSTATION, TMP_VMWARE_HARD);
1114911151

1115011152

11153+
// this is added in case the lib detects a non-Hyper-X technique.
11154+
// A Hyper-X affiliated technique should make the overall score
11155+
// as 0, but this isn't the case if non-Hyper-X techniques were
11156+
// found. There may be a conflict between an Unknown and Hyper-V
11157+
// brand, which is exactly what this section is meant to handle.
11158+
// It will remove the Hyper-V artifact brand string from the
11159+
// std::map to pave the way for other brands to take precendence.
11160+
// One of the main reasons to do this is because it would look
11161+
// incredibly awkward if the brand was "Hyper-V artifacts (not an
11162+
// actual VM)", clearly stating that it's NOT a VM while the VM
11163+
// confirmation is true and percentage is 100%, as if that makes
11164+
// any sense whatsoever. That's what this part fixes.
11165+
if (brands.count(TMP_HYPERV_ARTIFACT) > 0) {
11166+
if (score > 0) {
11167+
brands.erase(TMP_HYPERV_ARTIFACT);
11168+
}
11169+
}
11170+
11171+
1115111172
// the brand element, which stores the NAME (const char*) and the SCORE (u8)
1115211173
using brand_element_t = std::pair<const char*, brand_score_t>;
1115311174

@@ -11165,6 +11186,9 @@ struct VM {
1116511186

1116611187
std::string ret_str = brands::NULL_BRAND;
1116711188

11189+
11190+
11191+
1116811192
// if the multiple setting flag is NOT set, return the
1116911193
// brand with the highest score. Else, return a std::string
1117011194
// of the brand message (i.e. "VirtualBox or VMware").
@@ -11183,6 +11207,8 @@ struct VM {
1118311207
ret_str = ss.str();
1118411208
}
1118511209

11210+
11211+
1118611212
// cache the result if memoization is enabled
1118711213
if (core::is_disabled(flags, NO_MEMO)) {
1118811214
if (is_multiple) {
@@ -11193,6 +11219,7 @@ struct VM {
1119311219
memo::brand::store(ret_str);
1119411220
}
1119511221
}
11222+
1119611223

1119711224
// debug stuff to see the brand scoreboard, ignore this
1119811225
#ifdef __VMAWARE_DEBUG__

0 commit comments

Comments
 (0)