@@ -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;
1264912669std::array<VM::memo::leaf_entry, VM::memo::leaf_cache::CAPACITY> VM::memo::leaf_cache::table{};
1265012670std::size_t VM::memo::leaf_cache::count = 0 ;
1265112671std::size_t VM::memo::leaf_cache::next_index = 0 ;
12672+ const char * VM::core::last_detected_brand = nullptr ;
1265212673
1265312674#ifdef __VMAWARE_DEBUG__
1265412675VM::u16 VM::total_points = 0 ;
0 commit comments