This is the second part of our three-part
“Power of Execution Graph” blog series. The first part which introduces
Execution Graphs can be found at here.
As you may recall, Execution Graphs are
highly condensed control flow graphs, showing information about which part of
the code has been executed and which not. Execution Graphs highlight
additional attributes such API calls, threats starts, and key decisions.
In this blog post, we are going to focus on
an interesting sample we already have analyzed
previously with pure Hybrid Code Analysis
(HCA). The sample includes various sandbox detection tricks including one trick
to identify specifically Joe Sandbox. In the following text, we outline how
to spot these tricks by using Execution Graph.
The analyzed sample relies on packing
and encryption as a first layer of evasion. This technique is quite challenging to inspect manually from the PE file and generally poses a major
problem for static analysis approaches. Hybrid Code Analysis is resilient against packing and therefore facilitates the analysis of unpacked code.
Let us start with having a look at the
Execution Graph summary tab:
The first important striking fact is that
99% of the code is tagged as “Dynamic/Decrypted”. When looking at the prefix of the Execution
Graph in some detail, we notice the following:
- The code starts by allocating
dynamic memory using NtAllocateVirtualMemory native API calls.
- Once the allocation is
performed, the code reaches the node labeled 401065 which is flagged as Unpacker code. At this point, the code is written
into the previously allocated memory sections.
- After execution the unpacker code
then branches to the dynamically generated code.
By clicking on the node 401065, we can check that it indeed
contains unpacker code:
Checking the basic blocks leads us to the
unpacker code itself:
Similarly, by clicking on the following node 164a00, we can see that the corresponding code is located in a dynamically
allocated memory (as almost all nodes reachable from this point):
Please note that according to the status dynamic or unpacked code status the nodes are highlighted with different color:
There are three different branches starting
from node 401065. By clicking on node 401065, (which covers
several basic blocks) then following the hyper-link to basic block 4010CC, we
jump to the following disassembled code:
The computed call call edx at the virtual
address 04010E5 represents the execution branching to the unpacked code.
The Hybrid Code Analysis found three potential targets
represented by the three target nodes, while the executed code starting at
node 164a00 is the most interesting with respect to its behavior.
The sub-graph below outlines the various
- The sample first checks the
its file name (call to GetModuleFileName) and may stall if it looks
suspicious (e.g. in this case a file name like “sample”) by sleeping (branch to
- After checking the serial ID information of the volume C: (call to GetVolumeInformationA), it may stall again if
it matches a given magic value (sandbox detection via disk serial number).
Here both evasions fail since the execution
proceeds as illustrated by the node coloring.
Later in the code, at node 1548dc the
sample tries to detect if it is being run on a virtual machine. To do so it reads
the disk names via registry System\CurrentControlSet\Services\Disk\Enum and
compares to well-known products names such as VMWare. Checking disk names of virtualization
products is a well-known anti-VM trick which we see in nearly 70% of all
Finally, one last check has more success
and the execution ends up stalling in an endless Sleep loop:
Selecting the key-decision node 16499d shows us the disassembly, which indicates the trick is related to the registry key AutoItv3CCleanerWIC:
The code enumerates all software uninstallers. This enables to collect a list of all installed software on the
machine. The fingerprint AutoItv3CCleanerWIC
is then used to check if AutoIt, CCleaner and WIC are installed. If true the
sample falls asleep. AutoIt and CCleaner are two additional software we often
install on machines to make administration more easily. Likely, the guys behind
this malware were extracting the fingerprint by using our free Joe Sandbox Cloud Basic online service.
Beside the evasion tricks, the Execution
Graph can also be browsed for finding hidden / non executed functionalities, in
the form of suspicious sub-graphs. Here is an example:
This sub-graph outlines a
remote process injection technique, which has not been executed during analysis
but still can be found easily in the graph. The various edges to the lower nodes
are error handling, e.g. if CreateToolhelp32Snapshot fails then CloseHandle is
directly called. The code is quite extensive and spans several functions.
Thanks to the condensed and connected graph it is easy to detect and understand.
An Execution Graph often consists of a main
graph as well as several independent graphs:
The main graph contains executed nodes
(marked as red) while the independent graphs do not have any executed code. The
reason behind this is the difficulty to generate a completely connected graph. E.g.
consider the non-executed instruction call eax, where eax is previously
computed. It is not possible to
determine which code location is being called.
In order to focus on the main graph, we
added a new feature to hide independent graphs. Simply click on the Hide
Nodes/Edges label found at the top-left of the Execution Graph panel to hide independent
graphs and focus on the main graph. Click again to restore the full view.
Graph based Signatures
Of course, manually browsing through the
Execution Graph is not the only way for detecting evasive behavior. Execution
Graph Analysis uses an extensive set of behavior signatures to automatically
detect evasion tricks. A nice feature we have recently added is the ability to jump to the incriminated Execution Graph nodes from the signature by using the
links in the report:
The sample covered in this blog post uses a
large panel of techniques to avoid detection by sandboxes. But thanks to the
Execution Graph Analysis, the following information could be quickly obtained:
- The execution starts by
dynamically generating code. The Execution Graph enables to easily find the
unpacker code as well as the newly generated code.
- The unpacked code uses various
evasion tricks that Execution Graph Analysis automatically detected and rated as
malicious. The evasion tricks can be further analyzed in-depth by navigating
from the signature hits to the Execution Graph nodes and from the nodes to the
- Besides the detection of evasive
behavior, the Execution Graph provides a good way of detecting complex malware
functionalities (such as remote process injection) in the form of sub-graphs.
Stay tuned for our last blog post in our Power
of Execution Graphs series!
Report available at: