Skip to content

Commit 4393778

Browse files
committed
added VM::MULTIPLE option
1 parent f3c2e5e commit 4393778

3 files changed

Lines changed: 88 additions & 94 deletions

File tree

TODO.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
- [ ] upload the lib to apt
2626
- [X] add ARM support
2727
- [ ] look into what `fv-az663-325` is
28+
- [ ] implement techniques from [here](https://labs.nettitude.com/blog/vm-detection-tricks-part-3-hyper-v-raw-network-protocol/)
29+
- [ ] add multiple choice for VM::brand()
2830

2931
# Distant plans
3032
- add the library to conan.io when released

src/cli.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ int main(int argc, char* argv[]) {
255255

256256
std::printf("\n");
257257

258-
const std::string brand = VM::brand();
258+
const std::string brand = VM::brand(VM::MULTIPLE);
259259

260260
std::cout << "VM brand: " << (brand == "Unknown" ? red : green) << brand << ansi_exit << "\n";
261261

@@ -309,7 +309,7 @@ int main(int argc, char* argv[]) {
309309
version();
310310
return 0;
311311
} else if (cmp(arg, "-b") || cmp(arg, "--brand")) {
312-
std::cout << VM::brand() << "\n";
312+
std::cout << VM::brand(VM::MULTIPLE) << "\n";
313313
return 0;
314314
} else if (cmp(arg, "-p") || cmp(arg, "--percent")) {
315315
std::cout << static_cast<std::uint32_t>(VM::percentage()) << "\n";

src/vmaware.hpp

Lines changed: 84 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,8 @@ struct VM {
325325
MUTEX,
326326
EXTREME,
327327
NO_MEMO,
328-
WIN_HYPERV_DEFAULT
328+
WIN_HYPERV_DEFAULT,
329+
MULTIPLE
329330
};
330331
private:
331332
static constexpr u8 enum_size = __LINE__ - enum_line_start - 4; // get enum size
@@ -576,18 +577,6 @@ struct VM {
576577
qnx = " QNXQVMBSQG ",
577578
virtapple = "VirtualApple";
578579

579-
#if (CPP >= 17)
580-
constexpr std::array<std::string_view, 13> IDs{
581-
#else
582-
std::array<std::string, 13> IDs {
583-
#endif
584-
bhyve, kvm, qemu,
585-
hyperv, parallels, parallels,
586-
parallels2, vmware, vbox,
587-
xen, acrn, qnx,
588-
virtapple
589-
};
590-
591580
auto cpuid_thingy = [](const u32 p_leaf, u32* regs, std::size_t start = 0, std::size_t end = 4) -> bool {
592581
u32 x[4]{};
593582
cpu::cpuid(x[0], x[1], x[2], x[3], p_leaf);
@@ -611,36 +600,44 @@ struct VM {
611600
return str;
612601
};
613602

614-
std::stringstream ss;
615-
ss << strconvert(sig_reg[0]);
616-
ss << strconvert(sig_reg[1]);
617-
ss << strconvert(sig_reg[2]);
603+
std::stringstream ss1;
604+
std::stringstream ss2;
605+
606+
ss1 << strconvert(sig_reg[0]);
607+
ss1 << strconvert(sig_reg[1]);
608+
ss1 << strconvert(sig_reg[2]);
618609

619-
brand = ss.str();
610+
ss2 << strconvert(sig_reg[0]);
611+
ss2 << strconvert(sig_reg[2]);
612+
ss2 << strconvert(sig_reg[1]);
620613

621-
debug(technique_name, brand);
614+
std::string brand1 = ss1.str();
615+
std::string brand2 = ss2.str();
616+
617+
debug(technique_name, brand1);
618+
debug(technique_name, brand2);
622619

623620
#if (CPP < 17)
624621
// bypass compiler warning about unused parameter, ignore this
625622
UNUSED(technique_name);
626623
#endif
627624

628-
const bool found = (std::find(std::begin(IDs), std::end(IDs), brand) != std::end(IDs));
629-
630-
if (found) {
631-
if (brand == qemu) { return core::add(QEMU); }
632-
if (brand == vmware) { return core::add(VMWARE); }
633-
if (brand == vbox) { return core::add(VBOX); }
634-
if (brand == bhyve) { return core::add(BHYVE); }
635-
if (brand == kvm) { return core::add(KVM); }
636-
if (brand == xta) { return core::add(MSXTA); }
637-
if (brand == parallels) { return core::add(PARALLELS); }
638-
if (brand == parallels2) { return core::add(PARALLELS); }
639-
if (brand == xen) { return core::add(XEN); }
640-
if (brand == acrn) { return core::add(ACRN); }
641-
if (brand == qnx) { return core::add(QNX); }
642-
if (brand == virtapple) { return core::add(VAPPLE); }
643-
if (brand == hyperv) {
625+
const std::vector<std::string> brand_streams = { brand1, brand2 };
626+
627+
for (const auto &tmp_brand : brand_streams) {
628+
if (tmp_brand == qemu) { return core::add(QEMU); }
629+
if (tmp_brand == vmware) { return core::add(VMWARE); }
630+
if (tmp_brand == vbox) { return core::add(VBOX); }
631+
if (tmp_brand == bhyve) { return core::add(BHYVE); }
632+
if (tmp_brand == kvm) { return core::add(KVM); }
633+
if (tmp_brand == xta) { return core::add(MSXTA); }
634+
if (tmp_brand == parallels) { return core::add(PARALLELS); }
635+
if (tmp_brand == parallels2) { return core::add(PARALLELS); }
636+
if (tmp_brand == xen) { return core::add(XEN); }
637+
if (tmp_brand == acrn) { return core::add(ACRN); }
638+
if (tmp_brand == qnx) { return core::add(QNX); }
639+
if (tmp_brand == virtapple) { return core::add(VAPPLE); }
640+
if (tmp_brand == hyperv) {
644641
bool tmp = core::add(VPC);
645642
UNUSED(tmp);
646643
return core::add(HYPERV);
@@ -654,7 +651,7 @@ struct VM {
654651
* but the Wikipedia article on CPUID says it's
655652
* "KVMKVMKVM\0\0\0", like wtf????
656653
*/
657-
if (util::find(brand, "KVM")) {
654+
if (util::find(brand1, "KVM") || util::find(brand2, "KVM")) {
658655
return core::add(KVM);
659656
}
660657

@@ -5695,7 +5692,7 @@ struct VM {
56955692
#endif
56965693
ss << ". Consult the documentation's flag handler for VM::check()";
56975694
throw std::invalid_argument(std::string(text) + ss.str());
5698-
};
5695+
};
56995696

57005697
if (p_flag > enum_size) {
57015698
throw_error("Flag argument must be a valid");
@@ -5708,7 +5705,7 @@ struct VM {
57085705
if (
57095706
(p_flag == NO_MEMO) || \
57105707
(p_flag == EXTREME)
5711-
) {
5708+
) {
57125709
throw_error("Flag argument must be a technique flag and not a settings flag");
57135710
}
57145711

@@ -5723,7 +5720,7 @@ struct VM {
57235720

57245721
auto it = core::table.find(p_flag);
57255722

5726-
if (/*VMAWARE_UNLIKELY*/(it == core::table.end())) {
5723+
if ((it == core::table.end())) {
57275724
throw_error("Flag is not known");
57285725
}
57295726

@@ -5738,72 +5735,55 @@ struct VM {
57385735

57395736
/**
57405737
* @brief Fetch the VM brand
5741-
* @param any combination of flags, can be optional
5738+
* @param either nothing or VM::MULTIPLE
57425739
* @return std::string
57435740
* @returns VMware, VirtualBox, KVM, bhyve, QEMU, Microsoft Hyper-V, Microsoft x86-to-ARM, Parallels, Xen HVM, ACRN, QNX hypervisor, Hybrid Analysis, Sandboxie, Docker, Wine, Virtual Apple, Virtual PC, Unknown
57445741
* @link https://github.com/kernelwernel/VMAware/blob/main/docs/documentation.md#vmbrand
57455742
*/
5746-
[[nodiscard]] static std::string brand(const flagset p_flags = DEFAULT) {
5743+
[[nodiscard]] static std::string brand(u8 is_multiple = false) {
57475744
{
57485745
// this is added to set the brand scoreboard table
5749-
u16 tmp = core::run_all(p_flags);
5746+
u16 tmp = core::run_all(DEFAULT);
57505747
UNUSED(tmp);
57515748
}
57525749

5753-
const char* current_brand = "";
5754-
5755-
// fetch the brand with the most points in the scoreboard
5756-
#if (CPP >= 20)
5757-
auto it = std::ranges::max_element(core::brand_scoreboard, {},
5758-
[](const auto& pair) {
5759-
return pair.second;
5760-
}
5761-
);
5750+
#define brands core::brand_scoreboard
57625751

5763-
if (it != core::brand_scoreboard.end()) {
5764-
if (
5765-
std::none_of(core::brand_scoreboard.cbegin(), core::brand_scoreboard.cend(),
5766-
[](const auto& pair) {
5767-
return pair.second;
5768-
}
5769-
)
5770-
) {
5771-
current_brand = "Unknown";
5772-
}
5773-
else {
5774-
current_brand = it->first;
5775-
}
5752+
#ifdef __VMAWARE_DEBUG__
5753+
for (const auto p : brands) {
5754+
debug("scoreboard: ", (int)p.second, " : ", p.first);
57765755
}
5777-
else {
5778-
current_brand = "Unknown";
5756+
#endif
5757+
5758+
if (is_multiple == VM::MULTIPLE) {
5759+
is_multiple = true;
5760+
} else if (is_multiple != 0) {
5761+
throw std::invalid_argument("Flag for VM::brand() must either be empty or VM::MULTIPLE. Consult the documentation's flag handler for VM::check()");
57795762
}
5780-
#else
5781-
#if (MSVC)
5782-
int max = 0;
5783-
#else
5784-
u8 max = 0;
5785-
#endif
57865763

5787-
#if (CPP >= 17)
5788-
for (const auto& [brand, points] : core::brand_scoreboard) {
5764+
const char* current_brand = "";
5765+
i32 max = 0;
5766+
5767+
// both do the same thing
5768+
#if (CPP >= 17)
5769+
for (const auto& [brand, points] : brands) {
57895770
if (points > max) {
57905771
current_brand = brand;
57915772
max = points;
57925773
}
57935774
}
5794-
#else
5795-
for (auto it = core::brand_scoreboard.cbegin(); it != core::brand_scoreboard.cend(); ++it) {
5775+
#else
5776+
for (auto it = brands.cbegin(); it != brands.cend(); ++it) {
57965777
if (it->second > max) {
57975778
current_brand = it->first;
57985779
max = it->second;
57995780
}
58005781
}
5801-
#endif
5782+
#endif
58025783

58035784
if (max == 0) {
5804-
current_brand = "Unknown";
5785+
return "Unknown";
58055786
}
5806-
#endif
58075787

58085788
// goofy ass C++11 and C++14 linker error workaround
58095789
#if (CPP <= 14)
@@ -5832,23 +5812,17 @@ struct VM {
58325812
constexpr const char* TMP_HYPERV = VM::HYPERV;
58335813
#endif
58345814

5835-
#define brands core::brand_scoreboard
5836-
58375815
if (
58385816
brands.at(TMP_QEMU) > 0 &&
58395817
brands.at(TMP_KVM) > 0
58405818
) {
58415819
current_brand = "QEMU+KVM";
5842-
}
5843-
5844-
if (
5820+
} else if (
58455821
brands.at(TMP_VPC) > 0 &&
58465822
brands.at(TMP_HYPERV) > 0
58475823
) {
58485824
current_brand = "Microsoft Virtual PC/Hyper-V";
5849-
}
5850-
5851-
if (brands.at(TMP_VMWARE) > 0) {
5825+
} else if (brands.at(TMP_VMWARE) > 0) {
58525826
if (brands.at(TMP_EXPRESS) > 0) {
58535827
current_brand = TMP_EXPRESS;
58545828
} else if (brands.at(TMP_ESX) > 0) {
@@ -5858,13 +5832,30 @@ struct VM {
58585832
} else if (brands.at(TMP_WORKSTATION) > 0) {
58595833
current_brand = TMP_WORKSTATION;
58605834
}
5861-
}
5835+
} else if (is_multiple) {
5836+
std::vector<std::string> potential_brands;
58625837

5863-
#ifdef __VMAWARE_DEBUG__
5864-
for (const auto p : brands) {
5865-
debug("scoreboard: ", (int)p.second, " : ", p.first);
5838+
for (auto it = brands.cbegin(); it != brands.cend(); ++it) {
5839+
const u8 points = it->second;
5840+
const std::string brand = it->first;
5841+
5842+
if (points > 0) {
5843+
potential_brands.push_back(brand);
5844+
}
5845+
}
5846+
5847+
std::stringstream ss;
5848+
u8 i = 1;
5849+
5850+
ss << potential_brands.front();
5851+
5852+
for (; i < potential_brands.size(); i++) {
5853+
ss << " or ";
5854+
ss << potential_brands.at(i);
5855+
}
5856+
5857+
return ss.str();
58665858
}
5867-
#endif
58685859

58695860
return current_brand;
58705861
}
@@ -6003,6 +5994,7 @@ VM::flagset VM::DEFAULT = []() -> flagset {
60035994
tmp.flip(NO_MEMO);
60045995
tmp.flip(CURSOR);
60055996
tmp.flip(WIN_HYPERV_DEFAULT);
5997+
tmp.flip(MULTIPLE);
60065998
return tmp;
60075999
}();
60086000

0 commit comments

Comments
 (0)