Skip to content

Commit 43b0999

Browse files
author
Requiem
committed
perf: improved is_hardened() speed by using a new cache mechanism
2 parents 5a8ff02 + 9da062c commit 43b0999

File tree

4 files changed

+58
-46
lines changed

4 files changed

+58
-46
lines changed

TODO.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
1-
- [ ] add C++20 concepts for the VM::add_custom() function
2-
- [ ] add c++20 module support
31
- [ ] upload the lib to dnf
42
- [ ] upload the lib to apt
5-
- [ ] make a man file in markdown for the cli tool
63
- [ ] implement techniques from here https://stackoverflow.com/questions/43026032/detect-running-on-virtual-machine
74
- [ ] check if bios date in /sys/class/dmi/id/ could be useful under QEMU
8-
- [ ] add a .so, .dll, and .dylib shared object files in the release
95
- [ ] /sys/class/dmi/id/product_name check this in qemu
10-
- [ ] fix "dmidecode not found" error
116
- [ ] implement techniques from here https://www.cyberciti.biz/faq/linux-determine-virtualization-technology-command/
127
- [ ] implement techniques from virt-what
13-
- implement empty /sys/class dirs:
14-
- iommu
15-
- power_supply
16-
- check for presence of /dev/virtio-ports dir
17-
- replace all thread mismatch techniques to C style arrays
18-
8+
- [ ] implement empty /sys/class dirs:
9+
- [ ] iommu
10+
- [ ] power_supply
11+
- [ ] check for presence of /dev/virtio-ports dir
12+
- [ ] add the library to conan.io
13+
- [ ] add a reliable ci/cd for the debug binary
14+
- [ ] add an extra faq on ignoring false negatives and virtual devices on host
15+
- [ ] research 86box and pcem detection vectors
1916

2017
# Distant plans
21-
- add the library to conan.io when released
2218
- add a python version of the library (or any other lang for that matter)
2319
- add a GUI version of the lib
2420
- add a rust version of the lib

docs/documentation.md

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
- [`VM::conclusion()`](#vmconclusion)
1111
- [`VM::detected_count()`](#vmdetected_count)
1212
- [`VM::is_hardened()`](#vmis_hardened)
13-
- [`(advanced) VM::flag_to_string()`](#vmflag_to_string)
14-
- [`(advanced) VM::detected_enums()`](#vmdetected_enums)
13+
- [`(Advanced) VM::flag_to_string()`](#advanced-vmflag_to_string)
14+
- [`(Advanced) VM::detected_enums()`](#advanced-vmdetected_enums)
1515
- [vmaware struct](#vmaware-struct)
1616
- [Notes and overall things to avoid](#notes-and-overall-things-to-avoid)
1717
- [Flag table](#flag-table)
@@ -25,7 +25,7 @@
2525

2626
## `VM::detect()`
2727

28-
This is basically the main function you're looking for, which returns a bool. If no parameter is provided, all the recommended checks will be performed. But you can optionally set what techniques are used.
28+
This is basically the main function you're looking for, which returns a bool. If no parameter is provided, all the recommended checks will be performed. But you can optionally set which techniques are used.
2929

3030
```cpp
3131
#include "vmaware.hpp"
@@ -46,10 +46,9 @@ int main() {
4646

4747
/**
4848
* All checks are performed including techniques that are
49-
* disabled by default for a viariety of reasons. There are
50-
* around 5 technique that are disabled. If you want all
51-
* techniques for the sake of completeness, then you can use
52-
* this flag but remember that there may be potential
49+
* disabled by default for a viariety of reasons. If you
50+
* want all techniques for the sake of completeness, then
51+
* you can use this flag but remember that there may be potential
5352
* performance bottlenecks and an increase in false positives.
5453
*/
5554
bool is_vm3 = VM::detect(VM::ALL);
@@ -99,7 +98,7 @@ int main() {
9998
<br>
10099

101100
## `VM::percentage()`
102-
This will return a `std::uint8_t` between 0 and 100. It'll return the certainty of whether it has detected a VM based on all the techniques available as a percentage. The lower the value, the less chance it's a VM. The higher the value, the more likely it is.
101+
This will return a `std::uint8_t` between 0 and 100. It'll return the certainty of whether it has detected a VM based on all the techniques available as a percentage.
103102

104103
```cpp
105104
#include "vmaware.hpp"
@@ -118,8 +117,8 @@ int main() {
118117
std::cout << "Unsure if it's a VM\n";
119118
}
120119

121-
// converted to std::uint32_t for console character encoding reasons
122-
std::cout << "percentage: " << static_cast<std::uint32_t>(percent) << "%\n";
120+
// converted to int for console character encoding reasons
121+
std::cout << "percentage: " << static_cast<int>(percent) << "%\n";
123122

124123
return 0;
125124
}
@@ -322,22 +321,18 @@ This will detect whether the environment has any hardening indications as a `boo
322321

323322
Internally, this function works by analysing which combination of techniques are expected to be detected together. If a certain combination rule is mismatched, it indicates some kind of tampering of the system which assumes some sort of VM hardening.
324323

325-
326-
> [!WARNING]
327-
> This function should **NOT** be depended on for critical code. This is still a beta feature that hasn't been widely stress-tested as of 2.5.0. It works more as a heuristic assumption rather than a concrete guarantee.
324+
Similiary to `VM::brand()`, do not rely on this function for critical operations. This is meant to be a heuristic assumption rather than a concrete guarantee.
328325

329326

330327
```cpp
331328
#include "vmaware.hpp"
332329
#include <iostream>
333330

334331
int main() {
335-
if (VM::detect()) {
336-
if (VM::is_hardened()) {
337-
std::cout << "Potential hardening detected" << "\n";
338-
} else {
339-
std::cout << "Unsure if hardened" << "\n";
340-
}
332+
if (VM::is_hardened()) {
333+
std::cout << "Potential hardening detected" << "\n";
334+
} else {
335+
std::cout << "Unsure if hardened" << "\n";
341336
}
342337

343338
return 0;
@@ -346,8 +341,13 @@ int main() {
346341

347342
<br>
348343

349-
## `VM::flag_to_string()`
344+
## (Advanced) `VM::flag_to_string()`
345+
346+
<details>
347+
<summary>Show</summary>
348+
350349
This will take a technique flag enum as an argument and return the string version of it. For example:
350+
351351
```cpp
352352
#include "vmaware.hpp"
353353
#include <iostream>
@@ -362,7 +362,7 @@ int main() {
362362
}
363363
```
364364

365-
The reason why this exists is because it can be useful for debugging purposes. It should be noted that the "VM::" part is not included in the string output, so that's based on the programmer's choice if it should remain in the string or not. The example given above is obviously useless since the whole code can be manually handwritten, but the function is especially convenient if it's being used with [`VM::technique_vector`](#variables). For example:
365+
The reason why this exists is because it can be useful for debugging and infodumping purposes. It should be noted that the "VM::" part is not included in the string output, so that's based on the programmer's choice if it should remain in the string or not. The example given above is obviously useless since the whole code can be manually handwritten, but the function is especially convenient if it's being used with [`VM::technique_vector`](#variables). For example:
366366

367367
```cpp
368368
#include "vmaware.hpp"
@@ -382,9 +382,15 @@ int main() {
382382
}
383383
```
384384

385+
</details>
386+
385387
<br>
386388

387-
## `VM::detected_enums()`
389+
## (Advanced) `VM::detected_enums()`
390+
391+
<details>
392+
<summary>Show</summary>
393+
388394
This is a function that will return a vector of all the technique flags that were detected as running in a VM. The return type is `std::vector<VM::enum_flags>`, and it's designed to give a more programmatic overview of the result.
389395

390396
```cpp
@@ -402,6 +408,8 @@ int main() {
402408
}
403409
```
404410

411+
</details>
412+
405413
<br>
406414

407415
# vmaware struct
@@ -583,7 +591,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
583591
| `VM::DBVM` | Check if Dark Byte's VM is present | 🪟 | 150% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9518) |
584592
| `VM::BOOT_LOGO` | Check boot logo for known VM images | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9637) |
585593
| `VM::MAC_SYS` | Check for VM-strings in system profiler commands for MacOS | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7363) |
586-
| `VM::OBJECTS` | Check for any signs of VMs in Windows kernel object entities | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9740) |
594+
| `VM::KERNEL_OBJECTS` | Check for any signs of VMs in Windows kernel object entities | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9740) |
587595
| `VM::NVRAM` | Check for known NVRAM signatures that are present on virtual firmware | 🪟 | 100% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9926) |
588596
| `VM::SMBIOS_INTEGRITY` | Check if SMBIOS is malformed/corrupted in a way that is typical for VMs | 🪟 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L10357) |
589597
| `VM::EDID` | Check for non-standard EDID configurations | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L10368) |

src/cli.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ static void general(
805805
checker(VM::DBVM, "Dark Byte's hypervisor");
806806
checker(VM::BOOT_LOGO, "boot logo");
807807
checker(VM::MAC_SYS, "system profiler");
808-
checker(VM::OBJECTS, "kernel objects");
808+
checker(VM::KERNEL_OBJECTS, "kernel objects");
809809
checker(VM::NVRAM, "NVRAM");
810810
checker(VM::SMBIOS_INTEGRITY, "SMBIOS integrity");
811811
checker(VM::EDID, "EDID");

src/vmaware.hpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
* - struct for internal core components => line 11205
6161
* - start of VM detection technique list => line 4251
6262
* - start of public VM detection functions => line 11551
63-
* - start of externally defined variables => line 12534
63+
* - start of externally defined variables => line 12544
6464
*
6565
*
6666
* ============================== EXAMPLE ===================================
@@ -576,7 +576,7 @@ struct VM {
576576
UD,
577577
BLOCKSTEP,
578578
DBVM,
579-
OBJECTS,
579+
KERNEL_OBJECTS,
580580
NVRAM,
581581
SMBIOS_INTEGRITY,
582582
EDID,
@@ -9740,9 +9740,9 @@ struct VM {
97409740
/**
97419741
* @brief Check for any signs of VMs in Windows kernel object entities
97429742
* @category Windows
9743-
* @implements VM::OBJECTS
9743+
* @implements VM::KERNEL_OBJECTS
97449744
*/
9745-
[[nodiscard]] static bool objects() {
9745+
[[nodiscard]] static bool kernel_objects() {
97469746
struct OBJECT_DIRECTORY_INFORMATION {
97479747
UNICODE_STRING Name;
97489748
UNICODE_STRING TypeName;
@@ -9907,12 +9907,12 @@ struct VM {
99079907
// "VmGenerationCounter" and "VmGid" are created by the Hyper-V VM Bus provider
99089908
if (objectName == L"VmGenerationCounter") {
99099909
pNtClose(hDir);
9910-
debug("OBJECTS: Detected VmGenerationCounter");
9910+
debug("KERNEL_OBJECTS: Detected VmGenerationCounter");
99119911
return core::add(brands::HYPERV);
99129912
}
99139913
if (objectName == L"VmGid") {
99149914
pNtClose(hDir);
9915-
debug("OBJECTS: Detected VmGid");
9915+
debug("KERNEL_OBJECTS: Detected VmGid");
99169916
return core::add(brands::HYPERV);
99179917
}
99189918
}
@@ -11910,13 +11910,21 @@ struct VM {
1191011910

1191111911
u16 threshold = 150;
1191211912

11913-
// if high threshold is set, the points
11913+
// if high threshold is set, the bar
1191411914
// will be 300. If not, leave it as 150
1191511915
if (core::is_enabled(flags, HIGH_THRESHOLD)) {
1191611916
threshold = high_threshold_score;
1191711917
}
1191811918

11919-
return (points >= threshold);
11919+
if (points >= threshold) {
11920+
return true;
11921+
}
11922+
11923+
// this is added as a last ditch attempt to detect a VM,
11924+
// because if there are indications of hardening then logically
11925+
// it should in fact be a VM. It's doubtful if this can actually
11926+
// return true, but it's better than nothing
11927+
return (is_hardened());
1192011928
}
1192111929

1192211930

@@ -12114,7 +12122,7 @@ struct VM {
1211412122
case DBVM: return "DBVM";
1211512123
case BOOT_LOGO: return "BOOT_LOGO";
1211612124
case MAC_SYS: return "MAC_SYS";
12117-
case OBJECTS: return "OBJECTS";
12125+
case KERNEL_OBJECTS: return "KERNEL_OBJECTS";
1211812126
case NVRAM: return "NVRAM";
1211912127
case SMBIOS_INTEGRITY: return "SMBIOS_INTEGRITY";
1212012128
case EDID: return "EDID";
@@ -12726,7 +12734,7 @@ std::array<VM::core::technique, VM::enum_size + 1> VM::core::technique_table = [
1272612734
{VM::DRIVERS, {100, VM::drivers}},
1272712735
{VM::DEVICE_HANDLES, {100, VM::device_handles}},
1272812736
{VM::VIRTUAL_PROCESSORS, {100, VM::virtual_processors}},
12729-
{VM::OBJECTS, {100, VM::objects}},
12737+
{VM::KERNEL_OBJECTS, {100, VM::kernel_objects}},
1273012738
{VM::HYPERVISOR_QUERY, {100, VM::hypervisor_query}},
1273112739
{VM::AUDIO, {25, VM::audio}},
1273212740
{VM::DISPLAY, {25, VM::display}},

0 commit comments

Comments
 (0)