Understanding Anti-analysis Techniques used in Malware
In this write-up, I will be diving into the anti-analysis techniques used by malware in the wild. There are many different ways this is conducted. For example, processor checks, memory checks, running process checks, and other checks such as virtual port checks and CPUID checks. I will try to keep this write-up short and to the point, as it’s easy to over-explain. These techniques are not all universally the same when it comes to their implementation in malware nor are they always implemented in every malware sample that comes across the tape. However, these are the most commonly used techniques that you will find. Let’s begin.
Checking the CPUID
For the first anti-analysis technique, we will be looking at the CPUID checks. CPUID is an assembly-level instruction that allows for a program to pull down information regarding the current processor. This is a very common technique used for multiple reasons. For example, there are no direct API calls needed to make it work and it also is easily overlooked by researchers who are not only trying to do dynamic analysis in a virtualized/sandboxed environment but also static analysis. Now that we have the basics out of the way, let’s get a deeper understanding of how this works.
From the cyberbit post here, it explains the following:
This instruction is executed with EAX=1 as input, the return value describes the processor's features.
The 31st bit of ECX on a physical machine will be equal to 0. On a guest VM, it will equal 1.
Let’s take a look at this code sample below. It is just a basic C++ program that uses inline assembly to check the value of the 31st bit in the ECX register. Remember, in an un-altered virtualized environment, this value will be equal to 1. Below the inline assembly, I added a small amount of logic to show how it might be used in a sample, but obviously, they won’t just exit the program, the steps to halt the execution of the sample will be more complex.
bool VmCheck = false;
xor eax, eax
bt ecx, 0x1f
mov VmCheck, 0x1
if (VmCheck == 1)
std::cout << "Device is not virtualized" << std::endl;
Take a look at the sample of malware below. You can see the implementation of the CPUID check in the sample by comparing the ECX register to see if it is equal to one.
The next anti-analysis check we will be looking at is basic memory checks. When malware researchers set up sandboxes, they usually allocate a low number of resources to the box given all that it is doing is detonating a malware sample for dynamic analysis. In some cases, malware authors implement hardware checks to view information about the allocated resources of a computer. A common anti-analysis method is to check for the allocated amount of memory. The reason for this as mentioned above is that researchers will usually only allocate a very small number of resources for their sandboxes. Some functions of interest might have to do with querying system information such as GetSystemInfo() and or GetNativeSystemInfo(). For this section of the writeup, we will be looking at GlobalMemoryStatusEx().
Alright, let’s dig into this a little more. You can see from the screenshot above, that we make a call to GlobalMemoryStatusEx(). MSDN explains that this function retrieves information about the system’s current usage of both physical and virtual memory. Let’s take a look at the syntax of the function.
[in, out] LPMEMORYSTATUSEX lpBuffer
[in, out] lpBuffer
A pointer to a MEMORYSTATUSEX structure that receives information about current memory availability.
Let’s now look at where this is used later in this anti-analysis function. We can see that the pointer is then used in this conditional check (See screenshot below) to see if the total physical memory is less than or greater than 2 gigabytes as 0x7D2B7500 in hex is 2100000000. You can see that if it is less than, it will call sleep for 10,000 ms, and if it is greater than, then it will continue execution flow.
Virtual Port Checks
The next anti-analysis check we will be looking at has to do with querying information about the virtual I/O port. There are two main values to look for when trying to identify this. The first one is 0x5658 which is “VX” in ASCII and then the second one is 0×564D5868 which is “VMXh” in ASCII. It is possible for malware samples to detect / query information regarding the Virtual I/O ports. Let’s take a look at a sample now.
In the sample above, you can see that a1 which is treated as an argument for this function and is checked to see if the value matches 0×564D5868 or “VMXh”. If a1 is equal to that, variable v4 will be set to the value of 110. When looking at the cross-references to this function sub_4033FC, it is the first check done in the function sub_403EF7 which handles all of the anti-analysis functions.
Below is an example of some C++ code that can be used to conduct this check which can be found from here:
#include <iostream>int main()
bool result = true; __try
push ebx mov eax, 'VMXh'
mov ebx, 0
mov ecx, 10
mov edx, 'VX' in eax, dx cmp ebx, 'VMXh'
setz[result] pop ebx
result = false;
} return res;
File / Process Checks
Another anti-analysis technique that is used by malware is to check for certain files/processes that are running. If you spin up a Windows VM and query Get-Process vm* using PowerShell, you can see some processes that are related to a Virtual Machine.
Below is a list of common files that are searched for:
As you can see, malware authors are pretty adamite about checking for these types of things before having their sample run on a machine. Usually, malware samples will implement more than one check before it runs as well. Hopefully, you have learned something from this write-up.