Skip to content

Commit 5a8ff02

Browse files
author
Requiem
committed
perf: made cache mechanism for every vm brand found
1 parent 7f0acab commit 5a8ff02

File tree

1 file changed

+46
-25
lines changed

1 file changed

+46
-25
lines changed

src/vmaware.hpp

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,18 +3025,20 @@ struct VM {
30253025
bool result;
30263026
u8 points;
30273027
bool cached;
3028+
const char* brand_name;
30283029
};
30293030
struct cache_entry {
30303031
bool result;
30313032
u8 points;
30323033
bool has_value;
3034+
const char* brand_name;
30333035
};
30343036

30353037
static std::array<cache_entry, enum_size + 1> cache_table;
30363038

3037-
static void cache_store(u16 flag, bool result, u8 points) {
3039+
static void cache_store(u16 flag, bool result, u8 points, const char* brand = nullptr) {
30383040
if (flag <= enum_size) {
3039-
cache_table[flag] = { result, points, true };
3041+
cache_table[flag] = { result, points, true, brand };
30403042
}
30413043
}
30423044

@@ -3049,14 +3051,15 @@ struct VM {
30493051

30503052
static data_t cache_fetch(u16 flag) {
30513053
if (flag <= enum_size && cache_table[flag].has_value) {
3052-
return { cache_table[flag].result, cache_table[flag].points, true };
3054+
return { cache_table[flag].result, cache_table[flag].points, true, cache_table[flag].brand_name };
30533055
}
3054-
return { false, 0, false };
3056+
return { false, 0, false, nullptr };
30553057
}
30563058

30573059
static void uncache(u16 flag) {
30583060
if (flag <= enum_size) {
30593061
cache_table[flag].has_value = false;
3062+
cache_table[flag].brand_name = nullptr;
30603063
}
30613064
}
30623065

@@ -9197,7 +9200,7 @@ struct VM {
91979200
*/
91989201
[[nodiscard]] static bool trap() {
91999202
bool hypervisorCaught = false;
9200-
#if (x86_64)
9203+
#if (x86_64)
92019204
// when a single - step(TF) and hardware breakpoint(DR0) collide, Intel CPUs set both DR6.BS and DR6.B0 to report both events, which help make this detection trick
92029205
// AMD CPUs prioritize the breakpoint, setting only its corresponding bit in DR6 and clearing the single-step bit, which is why this technique is not compatible with AMD
92039206
if (!cpu::is_intel()) {
@@ -9389,7 +9392,7 @@ struct VM {
93899392
PVOID freeBase = execMem;
93909393
SIZE_T freeSize = trampSize;
93919394
pNtFreeVirtualMemory(hCurrentProcess, &freeBase, &freeSize, MEM_RELEASE);
9392-
#endif
9395+
#endif
93939396
return hypervisorCaught;
93949397
}
93959398

@@ -11157,7 +11160,10 @@ struct VM {
1115711160
&propertyType, nullptr, 0, &required);
1115811161
if (required > bufBytes) {
1115911162
BYTE* newBuf = static_cast<BYTE*>(realloc(buffer, required));
11160-
if (!newBuf) { found = false; break; }
11163+
if (!newBuf) {
11164+
found = false;
11165+
break;
11166+
}
1116111167
buffer = newBuf;
1116211168
bufBytes = required;
1116311169
}
@@ -11187,10 +11193,6 @@ struct VM {
1118711193
free(buffer);
1118811194
SetupDiDestroyDeviceInfoList(devs);
1118911195

11190-
if (!found) {
11191-
debug("CLOCK: PIT/AT (PNP0100) timer not found");
11192-
}
11193-
1119411196
return !found;
1119511197
}
1119611198
// ADD NEW TECHNIQUE FUNCTION HERE
@@ -11244,8 +11246,14 @@ struct VM {
1124411246
static std::array<brand_entry, MAX_BRANDS> brand_scoreboard;
1124511247
static size_t brand_count;
1124611248

11249+
// Temporary storage to capture which brand was detected by the currently running technique
11250+
static const char* last_detected_brand;
11251+
1124711252
// directly return when adding a brand to the scoreboard for a more succint expression
1124811253
static inline bool add(const char* p_brand, const char* extra_brand = "") noexcept {
11254+
// capture the brand being added so we can cache it later
11255+
last_detected_brand = p_brand;
11256+
1124911257
for (size_t i = 0; i < brand_count; ++i) {
1125011258
// pointer comparison is sufficient as we use the static constants from brands:: namespace
1125111259
if (brand_scoreboard[i].name == p_brand) {
@@ -11331,9 +11339,15 @@ struct VM {
1133111339
continue;
1133211340
}
1133311341

11342+
// reset the last detected brand before running
11343+
last_detected_brand = nullptr;
11344+
1133411345
// run the technique
1133511346
const bool result = technique_data.run();
1133611347

11348+
// retrieve the brand that was set during execution (if any)
11349+
const char* detected_brand = (result && last_detected_brand) ? last_detected_brand : brands::NULL_BRAND;
11350+
1133711351
if (result) {
1133811352
points += technique_data.points;
1133911353

@@ -11343,7 +11357,7 @@ struct VM {
1134311357
}
1134411358

1134511359
// store the current technique result to the cache
11346-
memo::cache_store(technique_macro, result, technique_data.points);
11360+
memo::cache_store(technique_macro, result, technique_data.points, detected_brand);
1134711361

1134811362
// for things like VM::detect() and VM::percentage(),
1134911363
// a score of 150+ is guaranteed to be a VM, so
@@ -11564,7 +11578,7 @@ struct VM {
1156411578
#endif
1156511579
) {
1156611580
if (util::is_unsupported(flag_bit)) {
11567-
memo::cache_store(flag_bit, false, 0);
11581+
memo::cache_store(flag_bit, false, 0, brands::NULL_BRAND);
1156811582
return false;
1156911583
}
1157011584

@@ -11603,13 +11617,18 @@ struct VM {
1160311617
if (flag_bit < technique_end) {
1160411618
const core::technique& pair = core::technique_table[flag_bit];
1160511619

11606-
if (auto run_fn = pair.run) {
11620+
if (auto run_fn = pair.run) {
11621+
core::last_detected_brand = nullptr;
11622+
1160711623
bool result = run_fn();
1160811624
if (result) detected_count_num++;
1160911625
#ifdef __VMAWARE_DEBUG__
1161011626
total_points += pair.points;
1161111627
#endif
11612-
memo::cache_store(flag_bit, result, pair.points);
11628+
// determine the brand string associated with this result
11629+
const char* detected_brand = (result && core::last_detected_brand) ? core::last_detected_brand : brands::NULL_BRAND;
11630+
11631+
memo::cache_store(flag_bit, result, pair.points, detected_brand);
1161311632
return result;
1161411633
}
1161511634
else {
@@ -12426,19 +12445,20 @@ struct VM {
1242612445
* @return bool
1242712446
*/
1242812447
static bool is_hardened() {
12448+
// Helper to get the specific brand associated with a technique using the cache
12449+
// If not cached, VM::check() will run it and cache the specific brand via core::last_detected_brand
1242912450
auto detected_brand = [](const enum_flags flag) -> const char* {
12430-
memo::uncache(flag);
12431-
12432-
std::array<core::brand_entry, core::MAX_BRANDS> old_scoreboard_snapshot{};
12433-
std::copy(core::brand_scoreboard.begin(), core::brand_scoreboard.end(), old_scoreboard_snapshot.begin());
12434-
12435-
check(flag);
12451+
// ensure the technique has been run and cached
12452+
if (!check(flag)) {
12453+
return brands::NULL_BRAND;
12454+
}
1243612455

12437-
for (size_t i = 0; i < core::brand_count; ++i) {
12438-
if (old_scoreboard_snapshot[i].score < core::brand_scoreboard[i].score) {
12439-
return core::brand_scoreboard[i].name;
12440-
}
12456+
// access the private cache directly to get the brand string
12457+
if (memo::cache_table[flag].has_value) {
12458+
const char* b = memo::cache_table[flag].brand_name;
12459+
return (b != nullptr) ? b : brands::NULL_BRAND;
1244112460
}
12461+
1244212462
return brands::NULL_BRAND;
1244312463
};
1244412464

@@ -12649,6 +12669,7 @@ VM::hyperx_state VM::memo::hyperx::state = VM::HYPERV_UNKNOWN;
1264912669
std::array<VM::memo::leaf_entry, VM::memo::leaf_cache::CAPACITY> VM::memo::leaf_cache::table{};
1265012670
std::size_t VM::memo::leaf_cache::count = 0;
1265112671
std::size_t VM::memo::leaf_cache::next_index = 0;
12672+
const char* VM::core::last_detected_brand = nullptr;
1265212673

1265312674
#ifdef __VMAWARE_DEBUG__
1265412675
VM::u16 VM::total_points = 0;

0 commit comments

Comments
 (0)