From 177707c0b66b383df689df589e057c6b9d0c5928 Mon Sep 17 00:00:00 2001 From: dmfrpro Date: Sat, 12 Apr 2025 22:13:29 +0300 Subject: [PATCH 1/2] Add Looking-Glass & VDD processes check Signed-off-by: dmfrpro --- README.md | 2 ++ al-khaser/Al-khaser.cpp | 1 + al-khaser/AntiVM/Generic.cpp | 33 ++++++++++++++++++++++++++++++++- al-khaser/AntiVM/Generic.h | 3 ++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5f805a0..da52d53 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,8 @@ Please, if you encounter any of the anti-analysis tricks which you have seen in - prl_tools.exe(Parallels) - xenservice.exe(Citrix Xen) - qemu-ga.exe (QEMU) + - looking-glass-host.exe (GENERIC) + - VDDSysTray.exe (GENERIC) - **WMI** - SELECT * FROM Win32_Bios (SerialNumber) (GENERIC) - SELECT * FROM Win32_PnPEntity (DeviceId) (VBOX) diff --git a/al-khaser/Al-khaser.cpp b/al-khaser/Al-khaser.cpp index 2c1abc3..404841a 100644 --- a/al-khaser/Al-khaser.cpp +++ b/al-khaser/Al-khaser.cpp @@ -170,6 +170,7 @@ int main(int argc, char* argv[]) known_usernames(); known_hostnames(); other_known_sandbox_environment_checks(); + looking_glass_vdd_processes(); exec_check(&NumberOfProcessors, TEXT("Checking Number of processors in machine ")); exec_check(&idt_trick, TEXT("Checking Interupt Descriptor Table location ")); exec_check(&ldt_trick, TEXT("Checking Local Descriptor Table location ")); diff --git a/al-khaser/AntiVM/Generic.cpp b/al-khaser/AntiVM/Generic.cpp index 97321db..1c8f715 100644 --- a/al-khaser/AntiVM/Generic.cpp +++ b/al-khaser/AntiVM/Generic.cpp @@ -2174,4 +2174,35 @@ BOOL hosting_check() if (sock != INVALID_SOCKET) closesocket(sock); WSACleanup(); return retVal; -} \ No newline at end of file +} + +/* +Check for looking-glass-host & VDD processes list.exe +https://looking-glass.io (Used in Hypervisor Phantom) +https://github.com/Scrut1ny/Hypervisor-Phantom + +Looking-glass requires at least one of them: +1. Physical monitor (undetectable) +2. HDMI emulator stub (undetectable?) +3. VirtualDisplayDriver (https://github.com/VirtualDrivers/Virtual-Display-Driver) +*/ +VOID looking_glass_vdd_processes() +{ + const TCHAR *szProcesses[] = { + _T("looking-glass-host.exe"), // Looking-Glass.io + _T("VDDSysTray.exe"), // VirtualDisplayDriver, used in conjunction + }; + + WORD iLength = sizeof(szProcesses) / sizeof(szProcesses[0]); + + for (int i = 0; i < iLength; i++) + { + TCHAR msg[256] = _T(""); + _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking processes %s "), szProcesses[i]); + + if (GetProcessIdFromName(szProcesses[i])) + print_results(TRUE, msg); + else + print_results(FALSE, msg); + } +} diff --git a/al-khaser/AntiVM/Generic.h b/al-khaser/AntiVM/Generic.h index d2e96da..7c78438 100644 --- a/al-khaser/AntiVM/Generic.h +++ b/al-khaser/AntiVM/Generic.h @@ -51,4 +51,5 @@ BOOL registry_services_disk_enum(); BOOL registry_disk_enum(); BOOL number_SMBIOS_tables(); BOOL firmware_ACPI_WAET(); -BOOL hosting_check(); \ No newline at end of file +BOOL hosting_check(); +VOID looking_glass_vdd_processes(); From f0e1652cc7a0b943a5eb15562ff12f2594c42036 Mon Sep 17 00:00:00 2001 From: dmfrpro Date: Sat, 12 Apr 2025 22:21:26 +0300 Subject: [PATCH 2/2] Add PCI Vendor ID registry scan Signed-off-by: dmfrpro --- al-khaser/Al-khaser.cpp | 9 ++-- al-khaser/AntiVM/KVM.cpp | 1 + al-khaser/AntiVM/Parallels.cpp | 25 +++++++++++ al-khaser/AntiVM/Parallels.h | 1 + al-khaser/AntiVM/Qemu.cpp | 24 ++++++++++ al-khaser/AntiVM/Qemu.h | 1 + al-khaser/AntiVM/VMWare.cpp | 1 + al-khaser/AntiVM/VirtualBox.cpp | 3 +- al-khaser/AntiVM/VirtualPC.cpp | 1 + al-khaser/AntiVM/Xen.cpp | 24 ++++++++++ al-khaser/AntiVM/Xen.h | 1 + al-khaser/Shared/Utils.cpp | 80 ++++++++++++++++++++++++++++----- 12 files changed, 156 insertions(+), 15 deletions(-) diff --git a/al-khaser/Al-khaser.cpp b/al-khaser/Al-khaser.cpp index 404841a..171c45d 100644 --- a/al-khaser/Al-khaser.cpp +++ b/al-khaser/Al-khaser.cpp @@ -268,6 +268,7 @@ int main(int argc, char* argv[]) if (ENABLE_QEMU_CHECKS) { print_category(TEXT("QEMU Detection")); qemu_reg_key_value(); + qemu_reg_keys(); qemu_processes(); qemu_dir(); exec_check(&qemu_firmware_SMBIOS, TEXT("Checking SMBIOS firmware ")); @@ -278,13 +279,14 @@ int main(int argc, char* argv[]) /* Xen Detection */ if (ENABLE_XEN_CHECKS) { print_category(TEXT("Xen Detection")); + xen_reg_keys(); xen_process(); exec_check(&xen_check_mac, TEXT("Checking Mac Address start with 08:16:3E ")); } /* KVM Detection */ if (ENABLE_KVM_CHECKS) { - print_category(TEXT("Xen Detection")); + print_category(TEXT("KVM Detection")); kvm_files(); kvm_reg_keys(); exec_check(&kvm_dir, TEXT("Checking KVM virio directory ")); @@ -297,9 +299,10 @@ int main(int argc, char* argv[]) wine_reg_keys(); } - /* Paralles Detection */ + /* Parallels Detection */ if (ENABLE_PARALLELS_CHECKS) { - print_category(TEXT("Paralles Detection")); + print_category(TEXT("Parallels Detection")); + parallels_reg_keys(); parallels_process(); exec_check(¶llels_check_mac, TEXT("Checking Mac Address start with 00:1C:42 ")); } diff --git a/al-khaser/AntiVM/KVM.cpp b/al-khaser/AntiVM/KVM.cpp index 4ecae99..0500675 100644 --- a/al-khaser/AntiVM/KVM.cpp +++ b/al-khaser/AntiVM/KVM.cpp @@ -15,6 +15,7 @@ VOID kvm_reg_keys() _T("SYSTEM\\ControlSet001\\Services\\BALLOON"), _T("SYSTEM\\ControlSet001\\Services\\BalloonService"), _T("SYSTEM\\ControlSet001\\Services\\netkvm"), + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_1AF4*"), }; WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); diff --git a/al-khaser/AntiVM/Parallels.cpp b/al-khaser/AntiVM/Parallels.cpp index 9b14b55..d91d3b6 100644 --- a/al-khaser/AntiVM/Parallels.cpp +++ b/al-khaser/AntiVM/Parallels.cpp @@ -2,6 +2,31 @@ #include "Parallels.h" +/* +Check against Parallels registry keys +*/ +VOID parallels_reg_keys() +{ + /* Array of strings of blacklisted registry keys */ + const TCHAR* szKeys[] = { + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_1AB8*"), + }; + + WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); + + /* Check one by one */ + for (int i = 0; i < dwlength; i++) + { + TCHAR msg[256] = _T(""); + _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking reg key %s "), szKeys[i]); + + if (Is_RegKeyExists(HKEY_LOCAL_MACHINE, szKeys[i])) + print_results(TRUE, msg); + else + print_results(FALSE, msg); + } +} + /* Check for process list */ diff --git a/al-khaser/AntiVM/Parallels.h b/al-khaser/AntiVM/Parallels.h index 34036c1..66a5bf5 100644 --- a/al-khaser/AntiVM/Parallels.h +++ b/al-khaser/AntiVM/Parallels.h @@ -1,4 +1,5 @@ #pragma once +VOID parallels_reg_keys(); VOID parallels_process(); BOOL parallels_check_mac(); \ No newline at end of file diff --git a/al-khaser/AntiVM/Qemu.cpp b/al-khaser/AntiVM/Qemu.cpp index 143d392..64f26c7 100644 --- a/al-khaser/AntiVM/Qemu.cpp +++ b/al-khaser/AntiVM/Qemu.cpp @@ -28,6 +28,30 @@ VOID qemu_reg_key_value() } +/* +Check against QEMU registry keys +*/ +VOID qemu_reg_keys() +{ + /* Array of strings of blacklisted registry keys */ + const TCHAR* szKeys[] = { + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_1B36*"), + }; + + WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); + + /* Check one by one */ + for (int i = 0; i < dwlength; i++) + { + TCHAR msg[256] = _T(""); + _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking reg key %s "), szKeys[i]); + + if (Is_RegKeyExists(HKEY_LOCAL_MACHINE, szKeys[i])) + print_results(TRUE, msg); + else + print_results(FALSE, msg); + } +} /* Check for process list diff --git a/al-khaser/AntiVM/Qemu.h b/al-khaser/AntiVM/Qemu.h index 6a632dd..8b70e91 100644 --- a/al-khaser/AntiVM/Qemu.h +++ b/al-khaser/AntiVM/Qemu.h @@ -1,6 +1,7 @@ #pragma once VOID qemu_reg_key_value(); +VOID qemu_reg_keys(); VOID qemu_processes(); VOID qemu_dir(); BOOL qemu_firmware_ACPI(); diff --git a/al-khaser/AntiVM/VMWare.cpp b/al-khaser/AntiVM/VMWare.cpp index e7c3e2b..90e487d 100644 --- a/al-khaser/AntiVM/VMWare.cpp +++ b/al-khaser/AntiVM/VMWare.cpp @@ -39,6 +39,7 @@ VOID vmware_reg_keys() /* Array of strings of blacklisted registry keys */ const TCHAR* szKeys[] = { _T("SOFTWARE\\VMware, Inc.\\VMware Tools"), + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_15AD*"), }; WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); diff --git a/al-khaser/AntiVM/VirtualBox.cpp b/al-khaser/AntiVM/VirtualBox.cpp index c71fdba..d31ede5 100644 --- a/al-khaser/AntiVM/VirtualBox.cpp +++ b/al-khaser/AntiVM/VirtualBox.cpp @@ -44,7 +44,8 @@ VOID vbox_reg_keys() _T("SYSTEM\\ControlSet001\\Services\\VBoxMouse"), _T("SYSTEM\\ControlSet001\\Services\\VBoxService"), _T("SYSTEM\\ControlSet001\\Services\\VBoxSF"), - _T("SYSTEM\\ControlSet001\\Services\\VBoxVideo") + _T("SYSTEM\\ControlSet001\\Services\\VBoxVideo"), + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_5333*"), }; WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); diff --git a/al-khaser/AntiVM/VirtualPC.cpp b/al-khaser/AntiVM/VirtualPC.cpp index d77d9dd..bf28b79 100644 --- a/al-khaser/AntiVM/VirtualPC.cpp +++ b/al-khaser/AntiVM/VirtualPC.cpp @@ -32,6 +32,7 @@ VOID virtual_pc_reg_keys() /* Array of strings of blacklisted registry keys */ const TCHAR* szKeys[] = { _T("SOFTWARE\\Microsoft\\Virtual Machine\\Guest\\Parameters"), + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_5333*"), }; WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); diff --git a/al-khaser/AntiVM/Xen.cpp b/al-khaser/AntiVM/Xen.cpp index baadb43..f8eaa6d 100644 --- a/al-khaser/AntiVM/Xen.cpp +++ b/al-khaser/AntiVM/Xen.cpp @@ -2,6 +2,30 @@ #include "Xen.h" +/* +Check against Xen registry keys +*/ +VOID xen_reg_keys() +{ + /* Array of strings of blacklisted registry keys */ + const TCHAR* szKeys[] = { + _T("SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_5853*"), + }; + + WORD dwlength = sizeof(szKeys) / sizeof(szKeys[0]); + + /* Check one by one */ + for (int i = 0; i < dwlength; i++) + { + TCHAR msg[256] = _T(""); + _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking reg key %s "), szKeys[i]); + if (Is_RegKeyExists(HKEY_LOCAL_MACHINE, szKeys[i])) + print_results(TRUE, msg); + else + print_results(FALSE, msg); + } +} + /* Check for process list */ diff --git a/al-khaser/AntiVM/Xen.h b/al-khaser/AntiVM/Xen.h index 9f1b8d8..b028820 100644 --- a/al-khaser/AntiVM/Xen.h +++ b/al-khaser/AntiVM/Xen.h @@ -1,4 +1,5 @@ #pragma once +VOID xen_reg_keys(); VOID xen_process(); BOOL xen_check_mac(); \ No newline at end of file diff --git a/al-khaser/Shared/Utils.cpp b/al-khaser/Shared/Utils.cpp index 78ad268..fd527bb 100644 --- a/al-khaser/Shared/Utils.cpp +++ b/al-khaser/Shared/Utils.cpp @@ -58,17 +58,75 @@ BOOL Is_RegKeyValueExists(HKEY hKey, const TCHAR* lpSubKey, const TCHAR* lpValue BOOL Is_RegKeyExists(HKEY hKey, const TCHAR* lpSubKey) { - HKEY hkResult = NULL; - TCHAR lpData[1024] = { 0 }; - DWORD cbData = MAX_PATH; - - if (RegOpenKeyEx(hKey, lpSubKey, NULL, KEY_READ, &hkResult) == ERROR_SUCCESS) - { - RegCloseKey(hkResult); - return TRUE; - } - - return FALSE; + if (_tcschr(lpSubKey, _T('*')) == NULL && _tcschr(lpSubKey, _T('?')) == NULL) + { + HKEY hkResult = NULL; + if (RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &hkResult) == ERROR_SUCCESS) + { + RegCloseKey(hkResult); + return TRUE; + } + return FALSE; + } + else + { + const TCHAR* lastBackslash = _tcsrchr(lpSubKey, _T('\\')); + TCHAR parentPath[MAX_PATH] = {0}; + TCHAR childPattern[MAX_PATH] = {0}; + + if (lastBackslash != NULL) + { + size_t parentLen = lastBackslash - lpSubKey; + _tcsncpy_s(parentPath, _countof(parentPath), lpSubKey, parentLen); + _tcscpy_s(childPattern, _countof(childPattern), lastBackslash + 1); + } + else + { + _tcscpy_s(childPattern, _countof(childPattern), lpSubKey); + } + + HKEY hKeyParent = NULL; + LONG lResult = RegOpenKeyEx(hKey, parentPath, 0, KEY_READ, &hKeyParent); + if (lResult != ERROR_SUCCESS) + { + return FALSE; + } + + TCHAR childPatternUpper[MAX_PATH]; + _tcscpy_s(childPatternUpper, _countof(childPatternUpper), childPattern); + _tcsupr_s(childPatternUpper, _countof(childPatternUpper)); + + DWORD dwIndex = 0; + TCHAR subkeyName[MAX_PATH]; + DWORD cchName = MAX_PATH; + BOOL bFound = FALSE; + + while (1) + { + cchName = MAX_PATH; + lResult = RegEnumKeyEx(hKeyParent, dwIndex, subkeyName, &cchName, NULL, NULL, NULL, NULL); + if (lResult == ERROR_NO_MORE_ITEMS) + break; + if (lResult != ERROR_SUCCESS) + break; + + TCHAR subkeyUpper[MAX_PATH]; + _tcscpy_s(subkeyUpper, _countof(subkeyUpper), subkeyName); + _tcsupr_s(subkeyUpper, _countof(subkeyUpper)); + + // Check if the subkey matches the pattern + if (PathMatchSpec(subkeyUpper, childPatternUpper)) + { + bFound = TRUE; + break; + } + + dwIndex++; + } + + RegCloseKey(hKeyParent); + return bFound; + } } BOOL is_FileExists(TCHAR* szPath)