Skip to content

Commit

Permalink
Merge pull request #61 from kernelwernel/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
kernelwernel authored Mar 22, 2024
2 parents 5f156e6 + 77e57ef commit ca99857
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 84 deletions.
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- [ ] fix memoization
- [X] add a python script to automatically set the lines of the seperate sections in the header
- [ ] add C++20 concepts for the VM::add_custom() function
- [ ] check for valid monitor technique


# Distant plans
Expand Down
5 changes: 2 additions & 3 deletions docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::DMIDECODE` | Get output from dmidecode tool and grep for common VM keywords | Linux | 55% | Admin | |
| `VM::DMESG` | Get output from dmesg tool and grep for common VM keywords | Linux | 55% | | |
| `VM::HWMON` | Check if HWMON is present (if not, likely a VM) | Linux | 75% | | |
| `VM::CURSOR` | Check if cursor isn't active (sign of automated VM environment) | Windows | 10% | | |
| `VM::CURSOR` | Check if cursor isn't active (sign of automated VM environment) | Windows | 5% | | |
| `VM::VMWARE_REG` | Look for any VMware-specific registry data | Windows | 65% | | |
| `VM::VBOX_REG` | Look for any VirtualBox-specific registry data | Windows | 65% | | |
| `VM::USER` | Match the username for any defaulted ones | Windows | 35% | | |
Expand Down Expand Up @@ -276,7 +276,6 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::BIOS_SERIAL` | Check if BIOS serial number is null | Windows | 60% | | |
| `VM::VBOX_FOLDERS` | Check for VirtualBox-specific string for shared folder ID | Windows | 45% | | |
| `VM::VBOX_MSSMBIOS` | Check VirtualBox MSSMBIOS registry for VM-specific strings | Windows | 75% | | |
| `VM::MAC_HYPERTHREAD` | Check if hyperthreading core count matches with physical expectations | MacOS | 10% | | |
| `VM::MAC_MEMSIZE` | Check if memory is too low for MacOS system | MacOS | 30% | | |
| `VM::MAC_IOKIT` | Check MacOS' IO kit registry for VM-specific strings | MacOS | 80% | | |
| `VM::IOREG_GREP` | Check for VM-strings in ioreg commands for MacOS | MacOS | 75% | | |
Expand Down Expand Up @@ -309,4 +308,4 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::NO_MEMO` | This will disable memoization, meaning the result will not be fetched through a previous computation of the `VM::detect()` function. Use this if you're only using a single function from the `VM` struct for a performance boost.
| `VM::EXTREME` | This will disregard the weights/biases and its scoring system. It will essentially treat any technique that found a hit as a VM detection no matter how low that technique's certainty is, so if a single technique is positive then it will return true. |
| `VM::DEFAULT` | This represents a range of flags which are enabled if no default argument is provided. The reason why this exists is to easily disable any bits manually (shown in the is_vm6 example in the `VM::detect()` section)
| `VM::WIN11_HYPERV` | This will take into account that Windows 11 sometimes may have Hyper-V as a default virtualisation software for any program even if the OS is running as host. Essentially, it will diregard any techniques prone to this issue, and NOT detect it as running in a VM, while having a higher threshold bar to detect it as a VM. |
| `VM::WIN_HYPERV_DEFAULT` | This will take into account that Windows 11 (and sometimes 10) may have Hyper-V as a default virtualisation software for any program even if the OS is running as host. Essentially, this flag will count any techniques prone to this issue as running in a VM, while having a higher threshold bar to detect it as one. |
1 change: 0 additions & 1 deletion src/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ int main(int argc, char* argv[]) {
checker(VM::HYPERV_WMI, "Hyper-V WMI output");
checker(VM::VBOX_FOLDERS, "VirtualBox shared folders");
checker(VM::VBOX_MSSMBIOS, "VirtualBox MSSMBIOS");
checker(VM::MAC_HYPERTHREAD, "MacOS hyperthreading");
checker(VM::MAC_MEMSIZE, "MacOS hw.memsize");
checker(VM::MAC_IOKIT, "MacOS registry IO-kit");
checker(VM::IOREG_GREP, "IO registry grep");
Expand Down
116 changes: 50 additions & 66 deletions src/vmaware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,6 @@ struct VM {
BIOS_SERIAL,
VBOX_FOLDERS,
VBOX_MSSMBIOS,
MAC_HYPERTHREAD,
MAC_MEMSIZE,
MAC_IOKIT,
IOREG_GREP,
Expand All @@ -301,7 +300,7 @@ struct VM {
HYPERV_BOARD,
EXTREME,
NO_MEMO,
WIN11_HYPERV
WIN_HYPERV_DEFAULT
};
private:
static constexpr u8 enum_size = __LINE__ - enum_line_start - 4; // get enum size
Expand Down Expand Up @@ -1489,13 +1488,13 @@ struct VM {
return false;
}

if (core::disabled(WIN_HYPERV_DEFAULT) && MSVC) {
return false;
}

#if (!x86)
return false;
#else
if (core::enabled(WIN11_HYPERV)) {
return false;
}

u32 unused, ecx = 0;

cpu::cpuid(unused, unused, ecx, unused, 1);
Expand All @@ -1520,12 +1519,16 @@ struct VM {
return false;
}

#if (!x86 || MSVC)
if (core::disabled(WIN_HYPERV_DEFAULT) && MSVC) {
return false;
}

#if (!x86)
return false;
#else
u32 a, b, c, d = 0;

if (core::enabled(WIN11_HYPERV)) {
if (core::enabled(WIN_HYPERV_DEFAULT)) {
cpu::cpuid(a, b, c, d, (cpu::leaf::hypervisor));
if (
b == 0x7263694D && // "Micr"
Expand Down Expand Up @@ -1565,7 +1568,7 @@ struct VM {
#if (!x86)
return false;
#else
if (core::enabled(WIN11_HYPERV)) {
if (core::disabled(WIN_HYPERV_DEFAULT) && MSVC) {
return false;
}

Expand Down Expand Up @@ -1772,20 +1775,16 @@ struct VM {
PIP_ADAPTER_INFO AdapterInfo;
DWORD dwBufLen = sizeof(IP_ADAPTER_INFO);

char* mac_addr = static_cast<char*>(std::malloc(18));

AdapterInfo = (IP_ADAPTER_INFO*)std::malloc(sizeof(IP_ADAPTER_INFO));

if (AdapterInfo == NULL) {
free(mac_addr);
return false;
}

if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_BUFFER_OVERFLOW) {
std::free(AdapterInfo);
AdapterInfo = (IP_ADAPTER_INFO*)std::malloc(dwBufLen);
if (AdapterInfo == NULL) {
std::free(mac_addr);
return false;
}
}
Expand Down Expand Up @@ -2144,7 +2143,7 @@ struct VM {

if (std::string(p_brand) != "") {
debug("REGISTRY: ", "detected = ", p_brand);
core::scoreboard[p_brand]++;
core::brand_scoreboard[p_brand]++;
}
}
};
Expand Down Expand Up @@ -2602,34 +2601,6 @@ struct VM {
}


/**
* @brief check if hyperthreading core count matches with physical expectations
* @category MacOS
* @author from MacRansom ransomware
* @link https://evasions.checkpoint.com/techniques/macos.html
*/
[[nodiscard]] static bool mac_hyperthread() try {
if (core::disabled(MAC_HYPERTHREAD)) {
return false;
}

#if (!APPLE || !x86)
return false;
#else
// not valid for all cases
// my mac return 1
std::unique_ptr<std::string> result = util::sys_result("echo $((`sysctl -n hw.logicalcpu`/`sysctl -n hw.physicalcpu`))");

return (*result != ("2"));
return false;
#endif
}
catch (...) {
debug("MAC_HYPERTHREAD: catched error, returned false");
return false;
}


/**
* @brief Check if disk size is too low
* @category Linux (for now)
Expand Down Expand Up @@ -2775,7 +2746,9 @@ struct VM {
u32 retv = WNetGetProviderName(WNNC_NET_RDR2SAMPLE, provider, reinterpret_cast<LPDWORD>(&pnsize));

if (retv == NO_ERROR) {
return (lstrcmpi(provider, _T("VirtualBox Shared Folders")) == 0);
bool result = (lstrcmpi(provider, _T("VirtualBox Shared Folders")) == 0);
delete provider;
return result;
}

return false;
Expand Down Expand Up @@ -4010,17 +3983,23 @@ struct VM {
return false;
#else
// board_ptr and manufacturer_ptr empty
/* std::unique_ptr<std::string> platform_ptr = util::sys_result("ioreg -rd1 -c IOPlatformExpertDevice");
std::unique_ptr<std::string> platform_ptr = util::sys_result("ioreg -rd1 -c IOPlatformExpertDevice");
std::unique_ptr<std::string> board_ptr = util::sys_result("ioreg -rd1 -c board-id");
std::unique_ptr<std::string> manufacturer_ptr = util::sys_result("ioreg -rd1 -c manufacturer");

const std::string platform = *platform_ptr;
const std::string board = *board_ptr;
const std::string manufacturer = *manufacturer_ptr;

if (platform.empty())

auto check_platform = [&]() -> bool {
debug("IO_KIT: ", "platform = ", platform);

if (platform.empty()) {
return false;
}

for (const char c : platform) {
if (!std::isdigit(c)) {
return false;
Expand All @@ -4032,7 +4011,8 @@ struct VM {

auto check_board = [&]() -> bool {
debug("IO_KIT: ", "board = ", board);
if (board == "") {

if (board.empty()) {
return false;
}

Expand All @@ -4048,12 +4028,16 @@ struct VM {
return core::add(VMWARE);
}

return true;
return false;
};

auto check_manufacturer = [&]() -> bool {
debug("IO_KIT: ", "manufacturer = ", manufacturer);

if (manufacturer.empty()) {
return false;
}

if (util::find(manufacturer, "Apple")) {
return false;
}
Expand All @@ -4062,14 +4046,14 @@ struct VM {
return core::add(VBOX);
}

return true;
return false;
};

return (
check_platform() ||
check_board() ||
check_manufacturer()
);*/
);

return false;
#endif
Expand Down Expand Up @@ -5110,9 +5094,9 @@ struct VM {

// VM scoreboard table specifically for VM::brand()
#if (MSVC)
static std::map<const char*, int> scoreboard;
static std::map<const char*, int> brand_scoreboard;
#else
static std::map<const char*, u8> scoreboard;
static std::map<const char*, u8> brand_scoreboard;
#endif

// directly return when adding a brand to the scoreboard for a more succint expression
Expand All @@ -5122,7 +5106,7 @@ struct VM {
[[gnu::const]]
#endif
static inline bool add(const char* p_brand) noexcept {
core::scoreboard.at(p_brand)++;
core::brand_scoreboard.at(p_brand)++;
return true;
}

Expand Down Expand Up @@ -5151,7 +5135,7 @@ struct VM {

auto adjust = [=](const u8 value) -> u8 {
#if (MSVC)
if (ver == 11 && core::enabled(WIN11_HYPERV)) {
if (ver == 11 && core::enabled(WIN_HYPERV_DEFAULT)) {
return (value / 2);
}
#endif
Expand Down Expand Up @@ -5259,15 +5243,15 @@ struct VM {

// fetch the brand with the most points in the scoreboard
#if (CPP >= 20)
auto it = std::ranges::max_element(core::scoreboard, {},
auto it = std::ranges::max_element(core::brand_scoreboard, {},
[](const auto& pair) {
return pair.second;
}
);

if (it != core::scoreboard.end()) {
if (it != core::brand_scoreboard.end()) {
if (
std::none_of(core::scoreboard.cbegin(), core::scoreboard.cend(),
std::none_of(core::brand_scoreboard.cbegin(), core::brand_scoreboard.cend(),
[](const auto& pair) {
return pair.second;
}
Expand All @@ -5290,14 +5274,14 @@ struct VM {
#endif

#if (CPP >= 17)
for (const auto& [brand, points] : core::scoreboard) {
for (const auto& [brand, points] : core::brand_scoreboard) {
if (points > max) {
current_brand = brand;
max = points;
}
}
#else
for (auto it = core::scoreboard.cbegin(); it != core::scoreboard.cend(); ++it) {
for (auto it = core::brand_scoreboard.cbegin(); it != core::brand_scoreboard.cend(); ++it) {
if (it->second > max) {
current_brand = it->first;
max = it->second;
Expand All @@ -5319,14 +5303,15 @@ struct VM {
constexpr const char* TMP_KVM = VM::KVM;
#endif

if (core::scoreboard.at(TMP_QEMU) > 0 &&
core::scoreboard.at(TMP_KVM) > 0
) {
if (
core::brand_scoreboard.at(TMP_QEMU) > 0 &&
core::brand_scoreboard.at(TMP_KVM) > 0
) {
current_brand = "QEMU+KVM";
}

#ifdef __VMAWARE_DEBUG__
for (const auto p : core::scoreboard) {
for (const auto p : core::brand_scoreboard) {
debug("scoreboard: ", (int)p.second, " : ", p.first);
}
#endif
Expand Down Expand Up @@ -5420,9 +5405,9 @@ MSVC_ENABLE_WARNING(4626 4514)
// It's easier to just group them together rather than having C++17<= preprocessors with inline stuff

#if (MSVC)
std::map<const char*, int> VM::core::scoreboard{
std::map<const char*, int> VM::core::brand_scoreboard {
#else
std::map<const char*, VM::u8> VM::core::scoreboard {
std::map<const char*, VM::u8> VM::core::brand_scoreboard {
#endif
{ VM::VMWARE, 0 },
{ VM::VBOX, 0 },
Expand Down Expand Up @@ -5465,7 +5450,7 @@ VM::flagset VM::DEFAULT = []() -> flagset {
tmp.flip(EXTREME);
tmp.flip(NO_MEMO);
tmp.flip(CURSOR);
tmp.flip(WIN11_HYPERV);
tmp.flip(WIN_HYPERV_DEFAULT);
return tmp;
}();

Expand Down Expand Up @@ -5517,7 +5502,7 @@ const std::map<VM::u8, VM::core::technique> VM::core::table = {
{ VM::DMESG, { 55, VM::dmesg }},
{ VM::HWMON, { 75, VM::hwmon }},
{ VM::SIDT5, { 45, VM::sidt5 }},
{ VM::CURSOR, { 10, VM::cursor_check }},
{ VM::CURSOR, { 5, VM::cursor_check }},
{ VM::VMWARE_REG, { 65, VM::vmware_registry }},
{ VM::VBOX_REG, { 65, VM::vbox_registry }},
{ VM::USER, { 35, VM::user_check }},
Expand Down Expand Up @@ -5550,7 +5535,6 @@ const std::map<VM::u8, VM::core::technique> VM::core::table = {
{ VM::BIOS_SERIAL, { 60, VM::bios_serial }},
{ VM::VBOX_FOLDERS, { 45, VM::vbox_shared_folders }},
{ VM::VBOX_MSSMBIOS, { 75, VM::vbox_mssmbios }},
{ VM::MAC_HYPERTHREAD, { 10, VM::mac_hyperthread }},
{ VM::MAC_MEMSIZE, { 30, VM::hw_memsize }},
{ VM::MAC_IOKIT, { 80, VM::io_kit }},
{ VM::IOREG_GREP, { 75, VM::ioreg_grep }},
Expand Down
Loading

0 comments on commit ca99857

Please sign in to comment.