Skip to content

Commit

Permalink
added vbox disk technique
Browse files Browse the repository at this point in the history
  • Loading branch information
kernelwernel committed Sep 27, 2023
1 parent 6900c26 commit d4bc40c
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 29 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The library is:

- - -

**IMPORTANT:** The library is currently a beta, so more improvements and cross-compatibility fixes are planned (especially for Windows which I'm currently working on fixing). Although the project is improving on a daily basis, I don't recommend using this for any serious projects for now.
**IMPORTANT:** The library is currently a beta, so more improvements and cross-compatibility fixes are planned (especially for Windows which I'm currently working on fixing). I don't recommend using this for any serious projects for now.

- - -

Expand All @@ -46,7 +46,7 @@ int main() {


## CLI tool 🔧
This project also provides a tiny, but handy CLI tool utilising the full potential of what the library can do.
This project also provides a tiny, but handy CLI tool utilising the full potential of what the library can do. Also, running the CLI as root would give better results.

<img src="assets/image.png" width="500" title="cli">

Expand Down Expand Up @@ -75,7 +75,7 @@ You can view the full docs [here](docs/documentation.md). Trust me, it's not too
> It's designed for security researchers, VM engineers, and pretty much anybody who needs a practical and rock-solid VM detection mechanism in their project. For example, if you're making a VM and you're testing the effectiveness of concealing itself, or if you're a malware analyst and you want to check if your VM environment is good enough.
- Why another VM detection project?
> There's already loads of projects that have the same goal such as [InviZzzible](https://github.com/CheckPointSW/InviZzzible), [pafish](https://github.com/a0rtega/pafish) and [Al-Khaser](https://github.com/LordNoteworthy/al-khaser). But the difference between the aforementioned projects is that they have little to no support with non-Windows systems. On top of this, I wanted the core detection techniques to be accessible programmatically for everybody to get something useful out of it rather than providing just a CLI tool like the projects above.
> There's already loads of projects that have the same goal such as [InviZzzible](https://github.com/CheckPointSW/InviZzzible), [pafish](https://github.com/a0rtega/pafish) and [Al-Khaser](https://github.com/LordNoteworthy/al-khaser). But the difference between the aforementioned projects is that they don't provide a programmable interface to interact with the detection mechanisms, on top of having little to no support for non-Windows systems. I wanted the core detection techniques to be accessible programmatically for everybody to get something useful out of it rather than providing just a CLI tool like the projects above.
- Is it possible to spoof the result?
> Yes. There are some techniques that are trivially spoofable, and there's nothing the library can do about it whether it's a deliberate false negative or even a false positive. This is a problem that every VM detection project is facing, which is why the library is trying to test every technique possible to get the best result based on the environment it's running under.
Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- revise sidt check
- analyse the UUID check technique's efficiency
- fix c++11 debug function param error
- completely remove std::system() grep commands

- ~~update doc without technique column~~
- ~~make a flagcheck function~~
Expand Down
3 changes: 2 additions & 1 deletion docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ int main() {


# `VM::brand()`
This will essentially return the VM brand as a std::string_view (assuming you're using C++17 and above, else it will return a const char*). The possible brand string return values are: `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`, and `Virtual PC`. If none were detected, it will return `Unknown`.
This will essentially return the VM brand as a std::string_view (assuming you're using C++17 and above, else it will return a const char*). The possible brand string return values are: `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`, and `Virtual PC`. If none were detected, it will return `Unknown`. It's often not going to produce a satisfying result due to technical difficulties with accomplishing this, on top of being highly dependant on what mechanisms detected a VM.

```cpp
int main() {
Expand Down Expand Up @@ -114,6 +114,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::VM_FILES` | Find if any VM-specific files exists | Windows | 80% |
| `VM::HWMODEL` | Check if the sysctl for the hwmodel does not contain the "Mac" string | MacOS | 75% |
| `VM::DISK_SIZE` | Check if disk size is under or equal to 50GB | Linux | 60% |
| `VM::VBOX_DEFAULT` | Check for default RAM and DISK sizes set by VirtualBox | Linux and Windows | 55% |

# Non-technique flags
| Flag | Description |
Expand Down
1 change: 1 addition & 0 deletions src/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int main(int argc, char* argv[]) {
checker(VM::VM_FILES, "VM files");
checker(VM::HWMODEL, "hw.model");
checker(VM::DISK_SIZE, "disk size");
checker(VM::VBOX_DEFAULT, "VBox default specs");
std::printf("\n");

std::cout << "VM brand: " << (std::string(VM::brand()) == "Unknown" ? red : green) << VM::brand() << ansi_exit << "\n\n";
Expand Down
146 changes: 122 additions & 24 deletions src/vmaware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,9 @@ struct VM {
}

// for debug output
static inline void debug(auto ...message) noexcept {
#ifdef __VMAWARE_DEBUG__
#ifdef __VMAWARE_DEBUG__
template <typename... Args>
static inline void debug(Args... message) noexcept {
constexpr sv black_bg = "\x1B[48;2;0;0;0m",
bold = "\033[1m",
blue = "\x1B[38;2;00;59;193m",
Expand All @@ -316,8 +317,15 @@ struct VM {
std::cout << black_bg << bold << "[" << blue << "DEBUG" << ansiexit << bold << black_bg << "]" << ansiexit << " ";
((std::cout << message),...);
std::cout << "\n";
#endif
}
}

#else
// this is added so the compiler doesn't scream about "auto not allowed in function prototype" or some bullshit like that when compiling with C++17 or under.
template <typename... Args>
static inline void debug(Args... idk) noexcept {
return;
}
#endif

// directly return when adding a brand to the scoreboard for a more succint expression
[[nodiscard]] static inline bool add(const sv p_brand) noexcept {
Expand All @@ -327,7 +335,10 @@ struct VM {

// get disk size in GB
// TODO: finish the MSVC section
[[nodiscard]] static u16 get_disk_size() {
[[nodiscard]] static u32 get_disk_size() {
constexpr u64 GB = (1000 * 1000 * 1000);
u32 size;

#if (LINUX)
struct statvfs stat;

Expand All @@ -338,31 +349,28 @@ struct VM {
return false;
}

constexpr u64 GB = (1000 * 1000 * 1000);

// in gigabytes
const u32 size = static_cast<u32>((stat.f_blocks * stat.f_frsize) / GB);

if (size == 0) {
return false;
}
size = static_cast<u32>((stat.f_blocks * stat.f_frsize) / GB);

// round to the nearest factor of 10
const u16 result = static_cast<u16>(std::round((size / 10.0) * 10));
#elif (MSVC)

#if __VMAWARE_DEBUG__
debug("private get_disk_size function: ", "disk size = ", result, "GB");
#endif
#endif

if (size == 0) {
return false;
}

return result;
#elif (MSVC)
// round to the nearest factor of 10
const u32 result = static_cast<u32>(std::round((size / 10.0) * 10));

#if __VMAWARE_DEBUG__
debug("private get_disk_size function: ", "disk size = ", result, "GB");
#endif

return 0;
return result;
}
public:
// get RAM size in MB

// get RAM size in GB
// TODO: finish the MSVC section
[[nodiscard]] static u32 get_ram_size() {
#if (LINUX)
Expand Down Expand Up @@ -426,9 +434,11 @@ struct VM {
}

//https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getphysicallyinstalledsystemmemory?redirectedfrom=MSDN
/*
if (GetPhysicallyInstalledSystemMemory() == ERROR_INVALID_DATA) {
return 0;
}
*/

// TODO: finish this whenever I have time
#endif
Expand Down Expand Up @@ -500,6 +510,7 @@ struct VM {
VM_FILES = 1 << 28,
HWMODEL = 1 << 29,
DISK_SIZE = 1 << 30,
VBOX_DEFAULT = 1ULL << 31,

// settings
NO_MEMO = 1ULL << 63,
Expand Down Expand Up @@ -1843,7 +1854,7 @@ struct VM {

/**
* @brief Check for match with default RAM and disk size (VBOX-specific)
* @note RAM DISK
* @note RAM DISK
* WINDOWS 11: 4096MB, 80GB
* WINDOWS 10: 2048MB, 50GB
* ARCH, OPENSUSE, REDHAD, GENTOO, FEDORA, DEBIAN: 1024MB, 8GB
Expand All @@ -1854,6 +1865,92 @@ struct VM {
* @todo: check if it still applies to host systems with larger RAM and disk size than what I have
* @category Linux, Windows
*/
[[nodiscard]] static bool vbox_default_specs() try {
if (disabled(VBOX_DEFAULT)) {
return false;
}

const u32 disk = get_disk_size();
const u32 ram = get_ram_size();

if ((disk > 80) || (ram > 4)) {
return false;
}

#if (LINUX)
auto get_distro = []() -> std::string {
std::ifstream osReleaseFile("/etc/os-release");
std::string line;

while (std::getline(osReleaseFile, line)) {
if (line.find("ID=") != std::string::npos) {
const std::size_t start = line.find('"');
const std::size_t end = line.rfind('"');
if (start != std::string::npos && end != std::string::npos && start < end) {
return line.substr(start + 1, end - start - 1);
}
}
}

return "unknown";
};

const std::string distro = get_distro();

// yoda notation ftw
if ("unknown" == distro) {
return false;
}

if (
"arch" == distro ||
"opensuse" == distro ||
"redhat" == distro ||
"gentoo" == distro ||
"fedora" == distro ||
"debian" == distro
) {
return ((8 == disk) && (1 == ram));
}

if ("ubuntu" == distro) {
return ((10 == disk) && (1 == ram));
}

if ("ol" == distro) { // ol = oracle
return ((12 == disk) && (1 == ram));
}
#elif (MSVC)
double ret = 0.0;
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
OSVERSIONINFOEXW osInfo;

*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");

if (NULL != RtlGetVersion) {
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
RtlGetVersion(&osInfo);
ret = static_cast<double>(osInfo.dwMajorVersion);
}

// less than windows 10
if (ret < 10) {
return false;
}

// windows 10
if (10 == ret) {
return ((50 == disk) && (2 == ram));
}

// windows 11
if (11 == ret) {
return ((80 == disk) && (4 == ram));
}
#endif

return false;
} catch (...) { return false; }



Expand Down Expand Up @@ -1896,7 +1993,8 @@ struct VM {
{ VM::BOOT, { 5, boot_time }},
{ VM::VM_FILES, { 80, vm_files }},
{ VM::HWMODEL, { 75, hwmodel }},
{ VM::DISK_SIZE, { 60, disk_size }}
{ VM::DISK_SIZE, { 60, disk_size }},
{ VM::VBOX_DEFAULT, { 55, vbox_default_specs }}
};

public:
Expand Down
2 changes: 1 addition & 1 deletion src/vmtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
#include <iostream>

int main(void) {
std::cout << VM::get_ram_size() << "\n";
std::cout << VM::get_disk_size() << "\n";
return 0;
}

0 comments on commit d4bc40c

Please sign in to comment.