So how do malware authors know if an environment is safe for them to attack or not?
There are plenty of indicators about a system that they check to determine if there’s a security system like a sandbox which automatically tests malware or a virtual machine (VM) used in some sandbox environments and by security researchers to analyze and debug malware.
So how many processor cores do you have?
Well, most computers and even smartphones nowadays have at least 2 if not more, so if a malware sees only 1, it’s a strong indicator that the machine is used in a VM or sandbox to test the malware.
Let’s see some code examples for Windows OS…
Example #1: The “Straightforward” way
SYSTEM_INFO si; GetNativeSystemInfo(&si); //or GetSystemInfo(&si); if (si.dwNumberOfProcessors == 1) ExitProcess(0);
Example #2: The “Cross-platform” way
The C++ standard has a call that informs about the number of processors (internally in Windows, it calls GetSystemInfo function)
if (std::thread::hardware_concurrency() == 1) exit(0);
Example #3: The “Native” way
WinAPI calls like GetSystemInfo above usually invoke a lower level call (or calls) to ntdll.dll functionality. In this case, the function NtQuerySystemInformation returns the number of cores (and Microsoft even suggests using GetSystemInfo to retrieve this information)
... SYSTEM_BASIC_INFORMATION sbi; NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), nullptr); if (sbi.NumberOfProcessors == 1) ExitProcess(0);
Example #4: The “Trickster” way:
When an application runs, it can use any of the existing cores to execute code and Windows allows getting information on which ones are used with a call to GetProcessAffinityMask.
The trick used here is to utilize the last parameter which indicates the system’s affinity (whereas a value of 1 indicates the system was configured to use a single core)
DWORD_PTR dwProcessAffinity, dwSystemAffinity; GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); if (dwSystemAffinity == 1) ExitProcess(0);
Example #5 : More WinAPI functions
some are not deterministic but can still assist in determining that there’s more than a single core.
Example #6: More Native functions
NtGetCurrentProcessorNumber & NtGetCurrentProcessorNumberEx
RtlGetCurrentProcessorNumber & RtlGetCurrentProcessorNumberEx
RtlGetNativeSystemInformation is undocumented but is similar to NtQuerySystemInformation
Example #7: The “WMI” way
WMI is a system component for querying the OS for its information, including by scripting languages like VBScript & PowerShell, which is why it’s widely used by Fileless malware and malicious scripts to read OS’ data, in our case the query is very simple
Example #8: Using Environment variables
TCHAR buffer; GetEnvironmentVariable(TEXT("Number_of_Processors"), buffer, 10); if (_ttoi(buffer) == 1) exit(0);
BONUS – Example #9: The “Registry” way
This trick is not really used by malware but it’s a nice one as it gives the number in a not-so-intuitive manner by reading the hardware information from the registry (since 0 indicates the first processor, if key 1 exists, the machine has more than 1 core)
HKEY hKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Hardware\\Description\\System\\CentralProcessor\\1"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) ExitProcess(0);
One can also check the processor’s floating-point entry to get the same indicator by reading
As you figured it out, malware authors have many ways just to check one simple indicator about a system to determine if it’s safe for them to attack.
Our Deception technology identifies when malware asks the system such questions, it falsifies the information to deter it from executing, protecting the endpoint from attacks without knowing the threat beforehand and without relying on specific, limited indicators about the threats, as oppose to signatures and heuristics.