Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // COMPILATION: cl /EHsc /W4 /std:c++17 poc.cpp /Fe:poc.exe user32.lib advapi32.lib
- #include <windows.h>
- #include <tlhelp32.h>
- #include <lmcons.h>
- #include <intrin.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <cstdio>
- #include <cstring>
- #include <cwchar>
- #include <cctype>
- #include <cwctype>
- #include <string>
- #include <algorithm>
- #include <utility>
- using uint = unsigned int;
- typedef struct cpuid_result_t {
- uint32_t eax;
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- } cpuid_result_t;
- static cpuid_result_t cpuid(uint32_t leaf) {
- int regs[4] = {0};
- __cpuid(regs, (int)leaf);
- cpuid_result_t result;
- result.eax = (uint32_t)regs[0];
- result.ebx = (uint32_t)regs[1];
- result.ecx = (uint32_t)regs[2];
- result.edx = (uint32_t)regs[3];
- return result;
- }
- static inline uint32_t ROTL(uint32_t v, unsigned int r) {
- r &= 31; // limita la rotazione a 0..31
- return (v << r) | (v >> ((32 - r) & 31));
- }
- static inline wchar_t toupper_w(wchar_t c) {
- return (wchar_t)towupper((wint_t)c);
- }
- static wchar_t* wcslower(const wchar_t* src, wchar_t* dst, size_t dst_count) {
- if (src == nullptr || dst == nullptr || dst_count == 0) {
- return nullptr;
- }
- size_t i = 0;
- for (; i + 1 < dst_count && src[i] != L'\0'; ++i) {
- wchar_t ch = src[i];
- if (ch >= L'A' && ch <= L'Z') {
- ch = (wchar_t)(ch + 0x20);
- }
- dst[i] = ch;
- }
- dst[i] = L'\0';
- return dst;
- }
- uint32_t g_score = 0;
- uint32_t g_integrity = 0;
- const uint32_t XOR_MASK = 0x5961b6f7;
- const uint32_t HASH_SEED = 0xffaadf05; // initial integrity mask only
- const uint32_t INTEGRITY_XOR = 0xd3de4abd; // per-round integrity XOR constant
- // per-round integrity step data
- uint32_t DAT_140044520[11] = {
- 0,0,0,0,0,0,0,0,0,0,0
- };
- uint Check0_ProcessNameBlocklist(void);
- uint Check1_CoreAndThreadCount(void);
- uint Check2_PhysicalMemory(void);
- uint Check3_DisplayAdapterAllowlist(void);
- uint32_t Check4_UsernameHostnameBlocklist(void);
- uint Check5_SystemUptime(void);
- uint Check6_SleepAcceleration(void);
- uint Check7_RemoteSession(void);
- uint Check8_RdtscHypervisorJitter(void);
- uint Check9_CpuidBrandMismatch(void);
- uint Check10_GpuVendorBlocklist(void);
- // ══════════════════════════════════════════════════════════
- // FUN_140006d08 — Anti-Sandbox Orchestrator
- //
- // Runs 11 anti-sandbox checks, IDs 0–10.
- // The global suspicion score is stored XOR-masked in g_score.
- // The integrity value is stored in g_integrity and updated every round.
- //
- // All API calls are dynamically resolved at first use:
- // → GetProcAddress-equivalent via PEB walk: FUN_1400270c4
- // → API name strings are obfuscated, decoded once, then cached.
- //
- // Important scoring caveat:
- // The decompiled code does NOT implement one uniform:
- //
- // RunCheck(check_id) → delta
- //
- // model for all checks.
- //
- // Instead, several checks use distinct control-flow paths:
- // - Check 0 can directly inject +99 into g_score.
- // - Checks 3 and 4 force current_score + 7 on hit.
- // - Checks 6, 8, 9, and 10 explicitly carry the current score,
- // then add the check result.
- // - Check 7 does not carry the existing score on its path.
- // ══════════════════════════════════════════════════════════
- void AntiSandboxSuite() {
- // ── Scoring globals initialized to XOR-masked zero ────
- g_score = 0 ^ XOR_MASK; // DAT_140055f18 = 0x5961b6f7
- g_integrity = 0 ^ HASH_SEED; // DAT_140055f1c = 0xffaadf05
- // True value of both globals is 0 at start.
- // ── 11-iteration check loop ───────────────────────────
- int check_ids[] = {
- 2, // RAM
- 7, // Remote session
- 3, // Display adapter name
- 4, // Username / computer name
- 8, // CPUID/RDTSC timing
- 5, // System uptime
- 9, // CPUID vendor/brand mismatch
- 1, // CPU topology
- 10, // GPU PCI vendor
- 0, // Process enumeration
- 6 // Sleep acceleration
- };
- int pre_delays[] = {
- 168, // before Check 2
- 256, // before Check 7
- 371, // before Check 3
- 358, // before Check 4
- 468, // before Check 8
- 221, // before Check 5
- 252, // before Check 9
- 266, // before Check 1
- 109, // before Check 10
- 424, // before Check 0
- 309 // before Check 6
- };
- uint check_round = 11;
- do {
- uint round = 11 - check_round;
- // Optional pre-check delay, if delay > 0.
- if (pre_delays[round] > 0) {
- Sleep(pre_delays[round]); // FUN_14002cf10 = Sleep()
- }
- int check_id = check_ids[round];
- // ── Mixed score-update model from the decompiled CFG ──
- //
- // This is intentionally NOT represented as:
- //
- // g_score = (g_score ^ XOR_MASK) + RunCheck(check_id);
- // g_score = g_score ^ XOR_MASK;
- //
- // because the actual decompiled control flow has several
- // non-uniform accumulation paths.
- uint score_register = 0;
- switch (check_id) {
- case 0: {
- // Check 0:
- // Running process name blocklist.
- uint delta = Check0_ProcessNameBlocklist();
- score_register = (g_score ^ XOR_MASK) + delta;
- break;
- }
- case 1: {
- // Check 1:
- // CPU logical core count and thread/affinity topology.
- uint delta = Check1_CoreAndThreadCount();
- score_register = (g_score ^ XOR_MASK) + delta;
- break;
- }
- case 2: {
- // Check 2:
- // Physical RAM size.
- uint delta = Check2_PhysicalMemory();
- score_register = (g_score ^ XOR_MASK) + delta;
- break;
- }
- case 3: {
- // Check 3:
- // Display-adapter name allowlist using EnumDisplayDevicesW.
- //
- // FUN_140022398-style return semantics from the pseudocode:
- // 1 -> expected / whitelisted GPU adapter substring found -> no score update
- // 0 -> no whitelisted GPU adapter substring found -> score += 7
- //
- // This is an allowlist-style check:
- // match -> environment looks acceptable for this check
- // no match -> suspicious / sandbox score increased
- //
- // The scoring is inverted compared with normal
- // "detection == suspicious" checks: on the referenced CFG,
- // absence of a known/expected GPU substring causes the +7 crash-path score.
- uint whitelisted_gpu_detected = Check3_DisplayAdapterAllowlist();
- if (whitelisted_gpu_detected == 0) {
- score_register = (g_score ^ XOR_MASK) + 7;
- } else {
- score_register = g_score ^ XOR_MASK;
- }
- break;
- }
- case 4: {
- // Check 4:
- // Username / hostname blocklist.
- //
- // Forced current_score + 7 path on username/hostname hit.
- if (Check4_UsernameHostnameBlocklist()) {
- score_register = (g_score ^ XOR_MASK) + 7;
- } else {
- score_register = g_score ^ XOR_MASK;
- }
- break;
- }
- case 5: {
- // Check 5:
- // System uptime.
- uint delta = Check5_SystemUptime();
- score_register = (g_score ^ XOR_MASK) + delta;
- break;
- }
- case 6: {
- // Check 6:
- // Sleep acceleration detection.
- //
- // Carries the existing unmasked score forward first,
- // then adds the check result:
- //
- // local_res8 = DAT_140055f18 ^ 0x5961b6f7;
- // local_res8 = local_res8 + delta;
- uint delta = Check6_SleepAcceleration();
- score_register = g_score ^ XOR_MASK;
- score_register = score_register + delta;
- break;
- }
- case 7: {
- // Check 7:
- // Remote / VM desktop session.
- uint delta = Check7_RemoteSession();
- score_register = g_score ^ XOR_MASK;
- score_register = score_register + delta;
- break;
- }
- case 8: {
- // Check 8:
- // __rdtsc / __cpuid hypervisor jitter timing.
- //
- // Carries the existing score forward, then adds delta.
- uint delta = Check8_RdtscHypervisorJitter();
- score_register = g_score ^ XOR_MASK;
- score_register = score_register + delta;
- break;
- }
- case 9: {
- // Check 9:
- // __cpuid vendor vs brand mismatch.
- //
- // Carries the existing score forward, then adds delta.
- uint delta = Check9_CpuidBrandMismatch();
- score_register = g_score ^ XOR_MASK;
- score_register = score_register + delta;
- break;
- }
- case 10: {
- // Check 10:
- // GPU PCI vendor ID blocklist.
- //
- // Carries the existing score forward, then adds delta.
- uint delta = Check10_GpuVendorBlocklist();
- score_register = g_score ^ XOR_MASK;
- score_register = score_register + delta;
- break;
- }
- }
- // LAB_140007060-style score store:
- // re-mask and persist the updated score register.
- g_score = score_register ^ XOR_MASK;
- // ── MurmurHash-style integrity hash ───────────────
- //
- // Important:
- // The integrity hash does NOT use HASH_SEED here.
- //
- // HASH_SEED = 0xffaadf05 is only the initial mask value used
- // for g_integrity initialization:
- //
- // DAT_140055f1c = 0xffaadf05
- //
- // The actual per-round integrity XOR constant is:
- //
- // 0xd3de4abd
- //
- // Actual decompiled logic:
- //
- // uVar4 = DAT_140055f1c
- // ^ 0xd3de4abd
- // ^ *(uint*)(&DAT_140044520 + lVar11);
- //
- // uVar4 = (uVar4 << 0xd | uVar4 >> 0x13) * 0x5bd1e995;
- //
- // DAT_140055f1c = uVar4 >> 0xf ^ uVar4 ^ 0xd3de4abd;
- //
- // The per-round step values are loaded from DAT_140044520,
- // a third static array, not from the score table itself.
- uint v = g_integrity ^ INTEGRITY_XOR ^ DAT_140044520[round];
- v = ROTL(v, 13) * 0x5BD1E995;
- g_integrity = (v >> 15) ^ v ^ INTEGRITY_XOR;
- check_round--;
- } while (check_round != 0);
- // ── Final kill gate ───────────────────────────────────
- // ┌──────┬──────────────────────────────────┬──────────────────────────────────────┬─────────────────────────┬────────────────────────────────────────────┐
- // │ ID │ Function │ Technique │ API / Instruction │ Score behavior │
- // ├──────┼──────────────────────────────────┼──────────────────────────────────────┼─────────────────────────┼────────────────────────────────────────────┤
- // │ 0 │ Check0_ProcessNameBlocklist │ Running process name blocklist │ CreateToolhelp32 │ 5/2/1/0 + optional direct +99 injection │
- // │ 1 │ Check1_CoreAndThreadCount │ CPU logical core count + affinity │ GetLogicalProcessorInfo│ 7 / 2 / 1 / 0, additive path │
- // │ 2 │ Check2_PhysicalMemory │ Physical RAM size │ GlobalMemoryStatusEx │ 7 / 2 / 1 / 0, additive path │
- // │ 3 │ Check3_DisplayAdapterAllowlist │ Display adapter name hash allowlist │ EnumDisplayDevicesW │ VM GPU found: no score; otherwise +7 │
- // │ 4 │ Check4_UsernameHostnameBlocklist │ Username / hostname blocklist │ GetComputerNameW │ Forces current_score + 7 on hit │
- // │ │ │ │ GetUserNameW │ │
- // │ 5 │ Check5_SystemUptime │ System uptime │ GetTickCount64 │ 3 / 1 / 0, additive path │
- // │ 6 │ Check6_SleepAcceleration │ Sleep acceleration detection │ Sleep + GetTickCount64 │ Carries score, then adds 7 / 0 │
- // │ 7 │ Check7_RemoteSession │ Remote / VM desktop session │ GetSystemMetrics │ 7 / 0, does not carry score on this path │
- // │ 8 │ Check8_RdtscHypervisorJitter │ __rdtsc / __cpuid hypervisor timing │ __rdtsc + __cpuid │ Carries score, then adds 5 / 2 / 0 │
- // │ 9 │ Check9_CpuidBrandMismatch │ __cpuid vendor vs brand mismatch │ __cpuid leaf 0 + 0x8000 │ Carries score, then adds 5 / 0 │
- // │ 10 │ Check10_GpuVendorBlocklist │ GPU PCI vendor ID blocklist │ EnumDisplayDevicesW │ Carries score, then adds 5 / 0 │
- // ├──────┴──────────────────────────────────┴──────────────────────────────────────┴─────────────────────────┴────────────────────────────────────────────┤
- // │ KILL GATE: accumulated_score >= 7 → PoisonScores() + MessageBoxA spam loop + swi(3) / __debugbreak() crash │
- // │ CLEAN GATE: accumulated_score < 7 → silent return → hidden window → C2 beacon → check.mentor-square80.click │
- // └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
- int true_score = g_score ^ XOR_MASK;
- wprintf(L"[FINAL] true_score=%d threshold=7\n", true_score);
- if (true_score < 7) {
- wprintf(L"All checks passed, resume execution...\n");
- return; // Clean path — resume execution.
- } else {
- wprintf(L"Checks failed, the sample evaded successfully...\n");
- }
- }
- // CHECK 0 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ════════════════════════════════════════════════════════════════
- // HashLookup — FNV-1a variant on UTF-16LE strings
- // Used by: Check 0 (process names), Check 3 (window titles),
- // Check 4 (username/hostname)
- //
- // Signature:
- // bool HashLookup(
- // const wchar_t *str, // lowercased wide string
- // int char_count,
- // const uint32_t *table, // hash table pointer
- // int table_count
- // )
- // ════════════════════════════════════════════════════════════════
- bool HashLookup(const wchar_t *str,
- int char_count,
- const uint32_t *table,
- int table_count) {
- const uint32_t FNV_SEED = 0xEB1AF681;
- const uint32_t FNV_PRIME = 0x01000193;
- uint32_t hash = FNV_SEED;
- // FNV-1a hash over UTF-16LE bytes.
- //
- // For each wide character:
- // lo_byte = str[i] & 0xFF
- // hi_byte = (str[i] >> 8) & 0xFF
- //
- // Equivalent byte order:
- // low byte first, then high byte.
- for (int i = 0; i < char_count; i++) {
- uint8_t lo = (uint8_t)(str[i] & 0xFF);
- uint8_t hi = (uint8_t)((str[i] >> 8) & 0xFF);
- hash = ((lo ^ hash) * FNV_PRIME) ^ hi;
- hash = hash * FNV_PRIME;
- }
- // Linear search through the precomputed hash table.
- for (int j = 0; j < table_count; j++) {
- if (hash == table[j]) {
- return true;
- }
- }
- return false;
- }
- // ──────────────────────────────────────────────────────────
- // CHECK 0 | Process Name Blocklist
- // Technique: Snapshot all running processes, lowercase each
- // name, compute an FNV-like hash, and compare it
- // against a table of 77 pre-hashed sandbox process
- // names.
- // ──────────────────────────────────────────────────────────
- uint Check0_ProcessNameBlocklist(void) {
- #define PROC_BLOCKLIST_COUNT 77
- // Backing process-name blocklist hash table.
- // These are FNV-1a UTF-16LE variant hashes using seed 0xEB1AF681.
- static const uint32_t proc_blocklist[PROC_BLOCKLIST_COUNT] = {
- 0xBA2A05BF, // x32dbg.exe
- 0xB9454E34, // x64dbg.exe
- 0xFD407966, // windbg.exe
- 0x854E2A78, // ollydbg.exe
- 0xD7A05A03, // ida.exe
- 0xC4AA0F91, // ida64.exe
- 0x14143F12, // idaq.exe
- 0x47FB2AB0, // idaq64.exe
- 0xC1BBDF5F, // h74xsp.exe
- 0x0745234D, // idat64.exe
- 0xF797E6CC, // radare2.exe
- 0x90ADBB1E, // ghidra.exe
- 0xE72659B7, // ghidrarun.exe
- 0x40C4C43F, // dnspy.exe
- 0xE9618405, // de4dot.exe
- 0x5C27A3CB, // dotpeek.exe
- 0x40C0D839, // dotpeek64.exe
- 0x2DC251BC, // cheatengine-x86_64.exe
- 0x80D108DA, // cheatengine.exe
- 0xE76ACA8F, // unknown
- 0xDC30D8CF, // scylla.exe
- 0x41CEC4CA, // scylla_x64.exe
- 0x30032056, // scylla_x86.exe
- 0xDB68AC3F, // die.exe
- 0xC81E3552, // pestudio.exe
- 0x51A2E803, // pe-bear.exe
- 0xCF43F3B4, // hiew.exe
- 0xE49EAD55, // hiew32.exe
- 0x64D4223C, // apimonitor-x64.exe
- 0x4CD9A220, // apimonitor-x86.exe
- 0x3F20CF87, // regshot.exe
- 0x851C9BF2, // iamn0f.exe
- 0x45A901D5, // wireshark.exe
- 0x0279E8DB, // fiddler.exe
- 0x5ABF9252, // j-obdk.exe
- 0x91D75626, // httpdebugger.exe
- 0xD48B4CF5, // unknown
- 0x1278F6CC, // burpsuite.exe
- 0x59CE92B9, // pyw.exe
- 0x023F59E6, // mitmproxy.exe
- 0xC9590D6E, // 1-7oyt.exe
- 0x97510723, // proxifier.exe
- 0x415AFE92, // smartsniff.exe
- 0xA4EF56F1, // rawcap.exe
- 0x60203BFC, // networkminer.exe
- 0xDA59FCD1, // dumpcap.exe
- 0x068FDF61, // fakenet.exe
- 0x6A7F9AC9, // xenservice.exe
- 0xA3C3EA38, // unknown
- 0xE5A5D8A3, // unknown
- 0xCB69584F, // procmon64.exe
- 0x7A16F9CC, // procexp.exe
- 0x3F72412E, // procexp64.exe
- 0x2324C535, // tcpview.exe
- 0x30773BF2, // autoruns.exe
- 0x4E0861CD, // filemon.exe
- 0x7E11166B, // regmon.exe
- 0x0AA6028A, // processhacker.exe
- 0x0535AC50, // sysanalyzer.exe
- 0x0536BF1F, // 52n1oo.exe
- 0x343B0086, // ozu0jc.exe
- 0x0E6EA0C8, // immunitydebugger.exe
- 0x33ECDC2A, // unknown
- 0x1E071347, // lordpe.exe
- 0x8D8648DE, // protection_id.exe
- 0x8C963DD7, // peid.exe
- 0x1E08DE85, // joeboxcontrol.exe
- 0x3B9C56E7, // joeboxserver.exe
- 0x2A00D3A1, // vboxservice.exe
- 0x292AEC72, // vboxtray.exe
- 0x96B59713, // vmtoolsd.exe
- 0xDB40F9D3, // vmwaretray.exe
- 0xD890E6CC, // vmwareuser.exe
- 0x93760CA8, // vmsrvc.exe
- 0xBA27E6E5, // vmusrvc.exe
- 0x5F7A2BB5, // prl_tools.exe
- 0xEAA39666 // prl_cc.exe
- };
- bool found_badproc = false;
- int total_procs = 0;
- // Open a process snapshot (Type=2 = TH32CS_SNAPPROCESS)
- HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (snap != INVALID_HANDLE_VALUE) {
- PROCESSENTRY32W entry = {0};
- entry.dwSize = sizeof(PROCESSENTRY32W);
- if (Process32FirstW(snap, &entry)) {
- do {
- total_procs++;
- // Lowercase the process name as a wide-character string
- wchar_t name_lower[MAX_PATH] = {0};
- wcsncpy_s(name_lower, MAX_PATH, entry.szExeFile, _TRUNCATE);
- _wcslwr_s(name_lower, MAX_PATH);
- // Perform an FNV-style hash lookup against the 77-entry table.
- if (HashLookup(name_lower, (int)wcslen(name_lower), proc_blocklist, PROC_BLOCKLIST_COUNT)) {
- wprintf(L"[CHECK-0] blocked process found: %ls\n", name_lower);
- found_badproc = true;
- }
- entry.dwSize = sizeof(PROCESSENTRY32W);
- } while (Process32NextW(snap, &entry));
- }
- CloseHandle(snap);
- }
- (void)found_badproc;
- int ret_score;
- std::string meaning;
- // Return a score based on the total number of running processes
- if (total_procs < 0x33) {
- ret_score = 5; // < 51 processes → very suspicious
- meaning = "very suspicious: fewer than 51 running processes";
- } else if (total_procs <= 0x4b) {
- ret_score = 2; // 51–75 processes → mildly suspicious
- meaning = "mildly suspicious: 51 to 75 running processes";
- } else if (total_procs <= 100) {
- ret_score = 1; // 76–100 processes → slightly suspicious
- meaning = "slightly suspicious: 76 to 100 running processes";
- } else {
- ret_score = 0; // > 100 processes → normal
- meaning = "normal: more than 100 running processes";
- }
- if (found_badproc) {
- ret_score += 99;
- }
- printf("[CHECK0] total_processes=%d return=%u meaning=%s\n",
- total_procs,
- ret_score,
- meaning.c_str());
- return ret_score;
- }
- // CHECK 1 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 1 | CPU Core Count via Processor Information
- // Technique: Calls GetLogicalProcessorInformation to count
- // physical CPU packages and logical core bits.
- // Sandboxes often expose only 1–2 vCPUs.
- // ──────────────────────────────────────────────────────────
- uint Check1_CoreAndThreadCount() {
- SYSTEM_LOGICAL_PROCESSOR_INFORMATION buf[48];
- DWORD bytes_written = 0x600;
- BOOL ok = GetLogicalProcessorInformation(buf, &bytes_written);
- if (!ok) {
- wprintf(L"[CHECK-1] GetLogicalProcessorInformation failed. GetLastError() = %lu\n", GetLastError());
- wprintf(L"[CHECK-1] Returning score = 7\n");
- return 0;
- }
- uint core_count = 0;
- uint logical_count = 0;
- int entry_count = bytes_written >> 5;
- for (int i = 0; i < entry_count; i++) {
- ULONG_PTR mask = buf[i].ProcessorMask;
- LOGICAL_PROCESSOR_RELATIONSHIP rel = buf[i].Relationship;
- // Only RelationProcessorCore entries are used.
- // Each RelationProcessorCore entry represents one physical CPU core.
- if (rel != RelationProcessorCore)
- continue;
- core_count++;
- // Count set bits in ProcessorMask.
- // Each set bit represents one logical processor / hardware thread
- // belonging to this physical core.
- for (ULONG_PTR m = mask; m != 0; m >>= 1)
- logical_count += static_cast<uint>(m & 1);
- }
- uint score;
- if (core_count <= 1) {
- score = 7;
- }
- else if (core_count == 2) {
- if (logical_count < 3)
- score = 2;
- else if (logical_count > 4)
- score = 0;
- else
- score = 1;
- }
- else {
- score = 0;
- }
- wprintf(L"[CHECK-1] physical core count = %u\n", core_count);
- wprintf(L"[CHECK-1] logical thread count = %u\n", logical_count);
- wprintf(L"[CHECK-1] returning score = %u\n", score);
- return score;
- }
- // CHECK 2 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 2 | Physical Memory Size
- // Technique: Reads total installed RAM. Sandbox VMs are
- // commonly configured with 512MB–2GB.
- // Real machines typically have 8GB+.
- // ──────────────────────────────────────────────────────────
- uint Check2_PhysicalMemory(void) {
- MEMORYSTATUSEX mem = {0};
- // Set the structure size before calling GlobalMemoryStatusEx.
- // This field is required by the Windows API.
- mem.dwLength = sizeof(mem);
- // Query the total amount of physical memory installed on the system.
- // If the API call fails, return 0 because the check could not be evaluated.
- if (!GlobalMemoryStatusEx(&mem)) {
- wprintf(L"[CHECK-2] GlobalMemoryStatusEx failed. Returning score: 0\n");
- return 0;
- }
- // Convert total physical memory from bytes to megabytes.
- // Shifting right by 20 is equivalent to dividing by 1024 * 1024.
- uint64_t ram_mb = mem.ullTotalPhys >> 20;
- uint score = 0;
- // Low-memory systems are often associated with sandbox or VM environments.
- // Higher scores indicate stronger suspicion.
- if (ram_mb <= 0x600) {
- score = 7; // <= 1536 MB: likely sandbox
- } else if (ram_mb <= 0xE00) {
- score = 2; // <= 3584 MB: suspicious
- } else if (ram_mb <= 0x1600) {
- score = 1; // <= 5632 MB: borderline
- } else {
- score = 0; // > 5632 MB: likely real machine
- }
- // Print debug information about the calculated RAM value and final score.
- wprintf(L"[CHECK-2] Total physical memory: %llu MB\n",
- (unsigned long long)ram_mb);
- wprintf(L"[CHECK-2] Physical memory check score: %u\n",
- score);
- return score;
- }
- // CHECK 3 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 3 | Display Adapter Name Whitelist / Expected GPU Detection
- // API: EnumDisplayDevicesW from user32.dll
- // Technique: Enumerate display adapters. For each active adapter,
- // lowercase DeviceString and test all substrings of
- // length 5..14 against a 5-entry FNV UTF-16LE hash table.
- //
- // Important semantic note:
- // Despite looking like VM GPU detection, the scoring logic shows that
- // the hash table acts as an allowlist / whitelist.
- //
- // Return semantics, matching the pseudocode:
- // 1 -> expected / whitelisted adapter substring found
- // 0 -> no whitelisted adapter substring found
- //
- // Scoring is handled by AntiSandboxSuite():
- // return 1 -> score unchanged
- // return 0 -> score += 7
- //
- // Therefore:
- // match -> environment looks acceptable for this check
- // no match -> suspicious / sandbox score increased
- // ──────────────────────────────────────────────────────────
- static bool Check3_ScanAdapterName(
- const wchar_t* adapter_name_lower,
- const uint32_t* allowlist,
- int allowlist_count,
- DWORD adapter_index
- ) {
- if (adapter_name_lower == nullptr || adapter_name_lower[0] == L'\0') {
- return false;
- }
- int name_len = (int)wcslen(adapter_name_lower);
- for (int sub_len = 5; sub_len <= 14 && sub_len <= name_len; sub_len++) {
- for (int start = 0; start + sub_len <= name_len; start++) {
- wprintf(
- L"[CHECK-3] Checking substring len=%d start=%d substring=\"%.*ls\"\n",
- sub_len,
- start,
- sub_len,
- &adapter_name_lower[start]
- );
- if (HashLookup(
- &adapter_name_lower[start],
- sub_len,
- allowlist,
- allowlist_count))
- {
- wprintf(L"[CHECK-3] Whitelisted GPU adapter substring hash matched\n");
- wprintf(
- L"[CHECK-3] adapter_index=%lu substring=\"%.*ls\" full_device_string=\"%ls\"\n",
- adapter_index,
- sub_len,
- &adapter_name_lower[start],
- adapter_name_lower
- );
- return true;
- }
- }
- }
- return false;
- }
- uint Check3_DisplayAdapterAllowlist(void) {
- wprintf(L"[CHECK-3] Enumerating display adapters with EnumDisplayDevicesW()...\n");
- static const uint32_t gpu_name_allowlist[5] = {
- 0x5D9F8AA4u,
- 0xB46022F2u,
- 0xA77EEF5Bu,
- 0xD31A9699u,
- 0x7346A4CCu
- };
- int whitelisted_gpu_detected = 0;
- for (DWORD dev_idx = 0; ; dev_idx++) {
- DISPLAY_DEVICEW dd;
- ZeroMemory(&dd, sizeof(dd));
- // In the binary this value is 0x348, which matches sizeof(DISPLAY_DEVICEW).
- dd.cb = sizeof(dd);
- if (!EnumDisplayDevicesW(NULL, dev_idx, &dd, 0)) {
- break;
- }
- wprintf(L"[CHECK-3] Adapter index %lu found.\n", dev_idx);
- wprintf(L"[CHECK-3] DeviceString: %ls\n", dd.DeviceString);
- wprintf(L"[CHECK-3] StateFlags : 0x%08X\n", dd.StateFlags);
- // DISPLAY_DEVICE_ACTIVE / ATTACHED_TO_DESKTOP is bit 0 in the
- // pseudocode. Only active display adapters are processed.
- if ((dd.StateFlags & 0x1) == 0) {
- wprintf(L"[CHECK-3] Skipping adapter: not active.\n");
- continue;
- }
- wchar_t lower[128] = {0};
- wcslower(dd.DeviceString, lower, _countof(lower));
- if (Check3_ScanAdapterName(
- lower,
- gpu_name_allowlist,
- _countof(gpu_name_allowlist),
- dev_idx))
- {
- whitelisted_gpu_detected = 1;
- break;
- }
- }
- if (whitelisted_gpu_detected) {
- wprintf(L"[CHECK-3] Returning 1: whitelisted GPU adapter name detected; score unchanged.\n");
- return 1;
- }
- wprintf(L"[CHECK-3] Returning 0: no whitelisted GPU adapter name detected; caller will add +7.\n");
- return 0;
- }
- // CHECK 4 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 4 | Username & Hostname String Blocklist
- // Technique: Reads computer name and username, lowercases,
- // computes FNV-style hash of each, compares
- // against blocklist of 20 known sandbox values.
- // Confirmed hits: vmware, sandbox, cuckoo,
- // malware, sample, analysis, john doe
- // ──────────────────────────────────────────────────────────
- uint32_t Check4_UsernameHostnameBlocklist(void) {
- static const uint32_t name_blocklist[20] = {
- 0x7ba43f80, // ?
- 0x966ea0aa, // ?
- 0x6d2ab6d0, // malware
- 0x6ba382ef, // maltest
- 0x854d8bec, // johndoe
- 0xf8a8714c, // sandbox
- 0x0ef62eba, // virus
- 0x767a179c, // john doe
- 0xb9184372, // ?
- 0x5a7eb0b4, // ?
- 0x7f1c2975, // ?
- 0x4490d09d, // ?
- 0x1c9436cc, // george
- 0x69c2d508, // ?
- 0xf6c2b2af, // test
- 0x20ab9bf7, // sample
- 0xa7e472e3, // analysis
- 0x2410b3a7, // cuckoo
- 0xac7d9203, // vmware
- 0x17518351 // ?
- };
- wchar_t computername[MAX_COMPUTERNAME_LENGTH + 1] = {0};
- DWORD cn_size = MAX_COMPUTERNAME_LENGTH + 1;
- wchar_t username[UNLEN + 1] = {0};
- DWORD un_size = UNLEN + 1;
- uint32_t result = 0;
- BOOL got_computername = GetComputerNameW(computername, &cn_size);
- BOOL got_username = GetUserNameW(username, &un_size);
- wprintf(L"[CHECK-4] ComputerName: %ls (%ls)\n",
- got_computername ? computername : L"<failed>",
- got_computername ? L"OK" : L"FAILED");
- wprintf(L"[CHECK-4] Username: %ls (%ls)\n",
- got_username ? username : L"<failed>",
- got_username ? L"OK" : L"FAILED");
- if (got_computername) {
- wchar_t computername_lower[MAX_COMPUTERNAME_LENGTH + 1] = {0};
- wcslower(computername, computername_lower, _countof(computername_lower));
- if (HashLookup(computername_lower, (int)wcslen(computername_lower), name_blocklist, 20)) {
- wprintf(L"[CHECK-4] Match on ComputerName: %ls\n", computername);
- result = 7;
- }
- }
- if (got_username) {
- wchar_t username_lower[UNLEN + 1] = {0};
- wcslower(username, username_lower, _countof(username_lower));
- if (HashLookup(username_lower, (int)wcslen(username_lower), name_blocklist, 20)){
- wprintf(L"[CHECK-4] Match on Username: %ls\n", username);
- result = 7;
- }
- }
- wprintf(L"[CHECK-4] Result: %u\n", result);
- return result;
- }
- // CHECK 5 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 5 | System Uptime Check
- // Technique: A freshly-booted sandbox VM typically has very
- // low uptime. Real machines are usually up for
- // hours or days.
- // ──────────────────────────────────────────────────────────
- uint Check5_SystemUptime() {
- // Get system uptime in milliseconds since boot.
- uint64_t uptime_ms = GetTickCount64();
- uint result;
- const wchar_t* meaning;
- if (uptime_ms < 0x1D4C1) {
- result = 3; // < ~2 min -> freshly booted VM
- meaning = L"freshly booted VM";
- }
- else if (uptime_ms <= 600000) {
- result = 1; // < ~10 min -> suspicious
- meaning = L"suspicious low uptime";
- }
- else {
- result = 0; // > 10 min -> plausible real machine
- meaning = L"plausible real machine";
- }
- wprintf(L"[CHECK-5] Uptime: %llu ms | Result: %u | Meaning: %ls\n",
- uptime_ms, result, meaning);
- return result;
- }
- // CHECK 6 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 6 | Sleep Skew / Time Acceleration Detection
- // Technique: Many sandboxes patch Sleep() to return
- // immediately (or after a few ms) to speed up
- // analysis. This measures real elapsed time
- // across a known Sleep(1000) call.
- // ──────────────────────────────────────────────────────────
- uint Check6_SleepAcceleration(void) {
- wprintf(L"[CHECK-6] Sleep requested: 1000 ms\n");
- uint64_t t_before = GetTickCount64();
- Sleep(1000);
- uint64_t t_after = GetTickCount64();
- uint64_t elapsed = t_after - t_before;
- uint result = elapsed < 400 ? 7 : 0;
- wprintf(L"[CHECK-6] Elapsed: %llu ms\n",
- (unsigned long long)elapsed);
- wprintf(L"[CHECK-6] Result: %u (%ls)\n",
- result,
- result == 7
- ? L"sandbox suspected: Sleep was accelerated or skipped"
- : L"normal timing: Sleep duration looks realistic");
- return result;
- }
- // CHECK 7 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK 7 | Remote Desktop / VM Session Detection
- // Technique: SM_REMOTESESSION (index 0x1000) returns non-zero
- // if the calling process is running under a
- // Terminal Services / Remote Desktop session.
- // VMs accessed via RDP, most sandbox hypervisors
- // and remote analysis environments always set this.
- // ──────────────────────────────────────────────────────────
- uint Check7_RemoteSession() {
- // user32!GetSystemMetrics(SM_REMOTESESSION = 0x1000)
- int result = GetSystemMetrics(SM_REMOTESESSION);
- if (result != 0) {
- wprintf(L"[CHECK-7] GetSystemMetrics(SM_REMOTESESSION) = %d (remote session)\n", result);
- return 7;
- } else {
- wprintf(L"[CHECK-7] GetSystemMetrics(SM_REMOTESESSION) = %d (local session)\n", result);
- return 0;
- }
- }
- // CHECK 8 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK-8 | __rdtsc / __cpuid Timing Side-Channel
- // Technique: __cpuid is a serialising instruction — it flushes
- // the CPU pipeline. On bare metal, executing
- // __cpuid takes ~100–400 cycles. Under a hypervisor
- // it causes a VM-exit which costs 1000–5000+ cycles.
- // The malware measures this 7 times, sorts the
- // samples (bubble sort), and inspects the MEDIAN
- // to filter outlier noise.
- // ──────────────────────────────────────────────────────────
- uint Check8_RdtscHypervisorJitter() {
- unsigned long long samples[7];
- // Warmup: execute __cpuid twice before measuring to reduce first-run noise.
- cpuid(0);
- cpuid(0);
- // Take 7 timing samples.
- for (int i = 0; i < 7; i++) {
- unsigned long long t1 = __rdtsc(); // Timestamp before __cpuid.
- cpuid(0); // Serializing instruction; may trigger VM-exit.
- unsigned long long t2 = __rdtsc(); // Timestamp after __cpuid.
- samples[i] = t2 - t1; // __cpuid latency in CPU cycles.
- }
- wprintf(
- L"[CHECK-8] Samples: %llu, %llu, %llu, %llu, %llu, %llu, %llu cycles\n",
- samples[0], samples[1], samples[2], samples[3], samples[4], samples[5], samples[6]
- );
- // Sort samples in ascending order.
- // The median is used to reduce the impact of outliers caused by interrupts,
- // scheduling, or temporary CPU noise.
- for (int i = 1; i < 7; i++)
- for (int j = i; j < 7; j++)
- if (samples[j] < samples[i-1])
- std::swap(samples[i-1], samples[j]);
- // With 7 samples, the median is the value at index 3 after sorting.
- unsigned long long median_cycles = samples[3];
- wprintf(
- L"[CHECK-8] Median __cpuid latency: %llu cycles\n", median_cycles
- );
- if (median_cycles <= 0x5DC) {
- wprintf(L"[CHECK-8] Result: 0 - likely bare metal (<=1500 cycles)\n");
- return 0;
- }
- else if (median_cycles <= 0xBB8) {
- wprintf(L"[CHECK-8] Result: 2 - suspicious timing overhead (1501-3000 cycles)\n");
- return 2;
- }
- else {
- wprintf(L"[CHECK-8] Result: 5 - strong hypervisor/VM-exit indication (>=3001 cycles)\n");
- return 5;
- }
- }
- // CHECK 9 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // ──────────────────────────────────────────────────────────
- // CHECK-9 | __cpuid Vendor / Brand String Mismatch
- // Technique: Hypervisors sometimes misconfigure the CPU
- // vendor leaf (leaf 0) and the brand string
- // leaves (0x80000002-4). This check catches the
- // specific case where the two sources contradict
- // each other — a configuration only possible in
- // a virtual machine.
- //
- // Leaf 0 EBX values:
- // 0x68747541 = "Auth" → full vendor = "AuthenticAMD"
- // 0x756e6547 = "Genu" → full vendor = "GenuineIntel"
- //
- // Brand string leaves 0x80000002-4:
- // 48-byte ASCII string like:
- // "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz"
- // ──────────────────────────────────────────────────────────
- uint Check9_CpuidBrandMismatch() {
- wprintf(L"[CHECK-9] Reading CPU vendor information from __cpuid leaf 0...\n");
- // Step 1: Read CPU vendor from leaf 0.
- // This leaf exposes the CPU vendor identifier. We only check EBX here,
- // because the original logic uses the first 4 bytes to distinguish
- // between "Auth" for AMD and "Genu" for Intel.
- cpuid_result_t r = cpuid(0);
- uint32_t vendor_ebx = r.ebx; // "Auth" or "Genu"
- wprintf(L"[CHECK-9] Leaf 0 EBX value: 0x%08X\n", vendor_ebx);
- // Only analyse AMD and Intel — skip unknown vendors.
- bool is_amd = (vendor_ebx == 0x68747541); // "Auth" -> AuthenticAMD
- bool is_intel = (vendor_ebx == 0x756e6547); // "Genu" -> GenuineIntel
- if (is_amd) {
- wprintf(L"[CHECK-9] Vendor leaf indicates AMD-compatible CPU vendor.\n");
- } else if (is_intel) {
- wprintf(L"[CHECK-9] Vendor leaf indicates Intel-compatible CPU vendor.\n");
- } else {
- wprintf(L"[CHECK-9] Unknown or unsupported CPU vendor. Skipping mismatch check.\n");
- wprintf(L"[CHECK-9] Result: 0 - no judgment.\n");
- return 0; // unknown vendor -> no judgment
- }
- wprintf(L"[CHECK-9] Reading CPU brand string from extended __cpuid leaves 0x80000002-0x80000004...\n");
- // Step 2: Read 48-byte CPU brand string from leaves 0x80000002-0x80000004.
- // The brand string is a human-readable CPU model string, for example:
- // "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz".
- char brand[49] = {0};
- cpuid_result_t r2 = cpuid(0x80000002);
- cpuid_result_t r3 = cpuid(0x80000003);
- cpuid_result_t r4 = cpuid(0x80000004);
- static_assert(sizeof(cpuid_result_t) == 16, "cpuid_result_t must be 16 bytes");
- memcpy(brand + 0x00, &r2, sizeof r2);
- memcpy(brand + 0x10, &r3, sizeof r3);
- memcpy(brand + 0x20, &r4, sizeof r4);
- brand[48] = '\0';
- wprintf(L"[CHECK-9] CPU brand string: %S\n", brand);
- // Step 3: Scan brand string for manufacturer keywords.
- // The goal is to detect whether the brand string explicitly mentions
- // "Intel" or "AMD", independently from what __cpuid leaf 0 reports.
- bool brand_says_intel = false;
- bool brand_says_amd = false;
- wprintf(L"[CHECK-9] Scanning brand string for manufacturer keywords: Intel / AMD...\n");
- size_t brand_len = strlen(brand);
- for (size_t i = 0; i < brand_len; i++) {
- char c = (char)tolower((unsigned char)brand[i]);
- if (i + 4 < brand_len &&
- c == 'i' &&
- tolower((unsigned char)brand[i + 1]) == 'n' &&
- tolower((unsigned char)brand[i + 2]) == 't' &&
- tolower((unsigned char)brand[i + 3]) == 'e' &&
- tolower((unsigned char)brand[i + 4]) == 'l')
- {
- brand_says_intel = true;
- wprintf(L"[CHECK-9] Brand string contains keyword: Intel\n");
- }
- if (i + 2 < brand_len &&
- c == 'a' &&
- tolower((unsigned char)brand[i + 1]) == 'm' &&
- tolower((unsigned char)brand[i + 2]) == 'd')
- {
- brand_says_amd = true;
- wprintf(L"[CHECK-9] Brand string contains keyword: AMD\n");
- }
- }
- wprintf(
- L"[CHECK-9] Summary: vendor_leaf=%ls, brand_mentions_intel=%ls, brand_mentions_amd=%ls\n",
- is_amd ? L"AMD" : L"Intel",
- brand_says_intel ? L"true" : L"false",
- brand_says_amd ? L"true" : L"false"
- );
- // Step 4: Cross-check — vendor leaf must agree with brand string.
- //
- // Contradiction cases:
- // - AMD vendor leaf + Intel brand string
- // - Intel vendor leaf + AMD brand string
- //
- // This can indicate a virtualized or misconfigured environment where
- // the __cpuid vendor and the CPU brand string were not configured consistently.
- if (is_amd && brand_says_intel && !brand_says_amd) {
- wprintf(L"[CHECK-9] Mismatch detected: __cpuid vendor says AMD, but brand string says Intel.\n");
- wprintf(L"[CHECK-9] Result: 5 - suspicious __cpuid vendor/brand mismatch.\n");
- return 5;
- }
- if (is_intel && brand_says_amd && !brand_says_intel) {
- wprintf(L"[CHECK-9] Mismatch detected: __cpuid vendor says Intel, but brand string says AMD.\n");
- wprintf(L"[CHECK-9] Result: 5 - suspicious __cpuid vendor/brand mismatch.\n");
- return 5;
- }
- wprintf(L"[CHECK-9] No __cpuid vendor/brand mismatch detected.\n");
- wprintf(L"[CHECK-9] Result: 0 - vendor and brand appear consistent.\n");
- return 0; // vendor and brand agree -> real hardware / no mismatch detected
- }
- // ══════════════════════════════════════════════════════════════
- // CHECK 10 | GPU PCI Vendor ID Enumeration + Blocklist
- // API: EnumDisplayDevicesW (user32.dll)
- // Weight: 309
- //
- // Technique: Enumerate every display adapter registered in
- // Windows. For each adapter that is attached to
- // the active desktop, extract the PCI Vendor ID
- // from the Windows Device Instance Path string:
- //
- // "PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD&REV_00"
- // ^^^^
- // 4 hex digits = PCI Vendor ID
- //
- // Compare the parsed vendor ID against a table of
- // 6 known VM/hypervisor GPU vendors (stored XOR-
- // obfuscated in the binary with mask 0x884CBE0A).
- //
- // Blocklisted GPU vendors:
- // 0x1234 QEMU / BOCHS Standard VGA Controller
- // 0x15AD VMware SVGA II Adapter
- // 0x80EE VirtualBox Graphics Adapter
- // 0x1B36 QEMU VirtIO GPU (Red Hat)
- // 0x1AF4 Red Hat VirtIO Device
- // 0x1AE0 Google Compute Engine Virtual GPU
- // ══════════════════════════════════════════════════════════════
- uint Check10_GpuVendorBlocklist() {
- // Blocklist stored XOR-obfuscated in the binary.
- // Each entry is decoded at runtime with:
- //
- // decoded_vendor_id = stored_value ^ 0x884CBE0A
- //
- // The decoded values correspond to known GPU vendors commonly
- // associated with virtual machines or hypervisors.
- uint32_t blocklist_raw[6] = {
- 0x884CAC3E, // -> 0x1234 QEMU / BOCHS
- 0x884CABA7, // -> 0x15AD VMware
- 0x884C3EE4, // -> 0x80EE VirtualBox
- 0x884CA53C, // -> 0x1B36 QEMU VirtIO GPU
- 0x884CA4FE, // -> 0x1AF4 Red Hat VirtIO
- 0x884CA4EA, // -> 0x1AE0 Google Compute Engine
- };
- wprintf(L"[CHECK-10] Starting GPU PCI Vendor ID enumeration check.\n");
- wprintf(L"[CHECK-10] Enumerating display adapters using EnumDisplayDevicesW().\n");
- DISPLAY_DEVICEW dd = {0};
- dd.cb = sizeof(dd); // DISPLAY_DEVICEW structure size
- // Enumerate all display adapters registered by Windows.
- //
- // EnumDisplayDevicesW(NULL, iDevNum, &dd, 0) returns FALSE
- // when there are no more display adapters to enumerate.
- for (DWORD iDevNum = 0; EnumDisplayDevicesW(NULL, iDevNum, &dd, 0); iDevNum++) {
- wprintf(L"[CHECK-10] Adapter index %lu found.\n", iDevNum);
- wprintf(L"[CHECK-10] DeviceName : %ls\n", dd.DeviceName);
- wprintf(L"[CHECK-10] DeviceID : %ls\n", dd.DeviceID);
- wprintf(L"[CHECK-10] StateFlags : 0x%08X\n", dd.StateFlags);
- // Only process adapters attached to the active desktop.
- //
- // DISPLAY_DEVICE_ATTACHED_TO_DESKTOP is bit 0.
- // Also require DeviceName to be non-empty.
- if (!(dd.StateFlags & 0x1) || dd.DeviceName[0] == L'\0') {
- wprintf(L"[CHECK-10] Skipping adapter: not attached to desktop or empty DeviceName.\n");
- goto checktennextadapter;
- }
- wprintf(L"[CHECK-10] Adapter is attached to the desktop. Processing DeviceID.\n");
- {
- // DeviceID normally contains a PnP instance path such as:
- //
- // PCI\\VEN_15AD&DEV_0405&SUBSYS_040515AD&REV_00\\...
- //
- // The code scans this string looking for the marker "VEN_".
- // The hexadecimal digits following "VEN_" are parsed as the
- // PCI Vendor ID.
- wchar_t* dev_id = dd.DeviceID;
- size_t id_len = wcslen(dev_id);
- wprintf(L"[CHECK-10] DeviceID length: %zd characters.\n", id_len);
- wprintf(L"[CHECK-10] Scanning DeviceID for VEN_ marker.\n");
- // Scan for the substring "VEN_" in a case-insensitive way.
- // Each candidate character is converted to uppercase before
- // comparison.
- for (int pos = 0; pos < id_len - 3; pos++) {
- wchar_t c0 = toupper_w(dev_id[pos]);
- wchar_t c1 = toupper_w(dev_id[pos+1]);
- wchar_t c2 = toupper_w(dev_id[pos+2]);
- wchar_t c3 = toupper_w(dev_id[pos+3]);
- if (c0 == L'V' && c1 == L'E' && c2 == L'N' && c3 == L'_') {
- wprintf(L"[CHECK-10] VEN_ marker found at position %d.\n", pos);
- // Parse hexadecimal digits immediately after "VEN_".
- //
- // Parsing stops when one of the following is reached:
- // - end of string
- // - '&'
- // - a non-hexadecimal character
- //
- // The resulting value is the parsed PCI Vendor ID.
- uint32_t vendor_id = 0;
- int hex_pos = pos + 4;
- while (true) {
- wchar_t ch = dev_id[hex_pos];
- if (ch == L'\0' || ch == L'&') {
- wprintf(L"[CHECK-10] End of VEN field reached.\n");
- break;
- }
- uint32_t digit;
- if (ch >= L'0' && ch <= L'9')
- digit = ch - L'0';
- else if (ch >= L'A' && ch <= L'F')
- digit = ch - L'A' + 10;
- else if (ch >= L'a' && ch <= L'f')
- digit = ch - L'a' + 10;
- else {
- wprintf(L"[CHECK-10] Non-hex character encountered while parsing VEN field: '%lc'.\n", ch);
- break;
- }
- vendor_id = (vendor_id << 4) | digit;
- hex_pos++;
- }
- wprintf(L"[CHECK-10] Parsed PCI Vendor ID: 0x%04X.\n", vendor_id);
- wprintf(L"[CHECK-10] Comparing parsed Vendor ID against VM GPU vendor blocklist.\n");
- // Decode each obfuscated blocklist entry and compare it
- // with the parsed Vendor ID.
- for (int j = 0; j < 6; j++) {
- uint32_t expected = blocklist_raw[j] ^ 0x884CBE0A;
- wprintf(
- L"[CHECK-10] Blocklist entry %d: raw=0x%08X decoded=0x%04X.\n",
- j,
- blocklist_raw[j],
- expected
- );
- if (vendor_id == expected) {
- // A known VM/hypervisor GPU Vendor ID was found.
- //
- // Return value 5 means:
- // this check positively identified a blocklisted
- // GPU vendor associated with a virtualized
- // environment.
- wprintf(L"[CHECK-10] MATCH FOUND: Vendor ID 0x%04X is blocklisted.\n", vendor_id);
- wprintf(L"[CHECK-10] Returning 5: VM/hypervisor GPU vendor detected.\n");
- return 5;
- }
- }
- // A VEN_ marker was found and parsed, but the resulting
- // Vendor ID did not match any blocklisted VM GPU vendor.
- //
- // The scan continues in case the DeviceID contains another
- // VEN_ token later in the string.
- wprintf(L"[CHECK-10] No blocklist match for Vendor ID 0x%04X.\n", vendor_id);
- wprintf(L"[CHECK-10] Continuing scan for possible additional VEN_ markers.\n");
- }
- }
- }
- checktennextadapter:
- // Reset selected DISPLAY_DEVICEW fields before the next iteration.
- //
- // This preserves the original logic while making sure stale values
- // from the current adapter are not reused on the next call.
- wprintf(L"[CHECK-10] Moving to next display adapter.\n");
- ZeroMemory(&dd, sizeof(dd));
- dd.cb = sizeof(dd);
- }
- // No display adapter exposed a blocklisted VM/hypervisor GPU Vendor ID.
- //
- // Return value 0 means:
- // this check did not find evidence of a known virtual GPU vendor.
- wprintf(L"[CHECK-10] Enumeration completed.\n");
- wprintf(L"[CHECK-10] No blocklisted GPU PCI Vendor ID was found.\n");
- wprintf(L"[CHECK-10] Returning 0: no VM/hypervisor GPU vendor detected by this check.\n");
- return 0;
- }
- int main() {
- AntiSandboxSuite();
- std::wprintf(L"Press ENTER to continue...");
- std::getwchar();
- std::wprintf(L"Continuing...\n");
- return 0;
- }
Add Comment
Please, Sign In to add comment