Category Archives: malware

Extracting a Windows Zero-Day from an Adobe Reader Zero-Day PDF

In May 2018, when ESET published a blog post covering PDFs with 2 zero days, our interest was immediately piqued. Promptly after our analysis of these PDFs, we send out an early warning to our customers.

Now that Microsoft published a blog post with the detailed analysis of the zero days, we find it appropriate to explain how to quickly extract the payloads of these 2 PDFs.

We updated this blog post with a video.


We will start with PDF (MD5 e6b7392fb03ff9ff069a9ec5d4221641), this one contains an Adobe Reader exploit (CVE-2018-4990), but no Windows exploit.

With, we start the analysis process:

This tells us the PDF contains JavaScript and an OpenAction. These are often found together: the OpenAction triggers the execution of the JavaScript upon opening of the PDF document.
Using, we can search and extract the JavaScript from the PDF document:
The script is contained in object 1 (/JS 1 0 R):

It is compressed (/FlateDecode), we can decompress it with option -f:

The script starts with a long array of hexadecimal values: this is often the payload in malicious PDFs.
To decode it, we will use This is a tool to decode embedded payloads, not only base64 encodings, but several other encodings like the hexadecimal encoding used in this script.

With option -w for pdf-parser, we extract the raw script (e.g. without escaped whitespace characters).
With option -w and -i , for base64dump, we ignore all whitespace characters and commas. This will create a long string for the payload: 0x81ec8b550x0002d0ec0x57… This encoding is called zx (zero-x, e.g. 0x). It can be little-endian (le) or big-endian (be). With JavaScript in Adobe Reader, it is little-endian: we use option -e zxle to decode this long string. And finally, to limit the amount of strings detected and decoded by base64dump, we want the decoded string to be at least 10 bytes long: -n 10.
The first decoded string is very long (110690 encoded bytes). With YARA rule contains_pe_file, we can quickly check if it contains a PE-file (Windows executable):

No surprise, it does! Now with base64dump, we can extract this payload (and the PE file). With option -s 1, we select the first decoded string and show an hex/ascii dump (-a):

This is not the PE file, but shellcode to load the PE file directly into memory.
PE files start with MZ, we can use option -c (cut) to cut-out the part of the decoded string that starts with MZ like this:

This is still not the embedded PE-file, let’s search for the second instance of MZ, like this:

This looks like a PE-file. Let’s dump it (-d) and pass it to, a tool to analyze PE-files:

It’s indeed a PE-file, more precisely, a 32-bit DLL:

This shows how it is possible to triage and analyze zero-day malicious PDFs with static analysis tools. The same one-liner can be used to analyze the second PDF (MD5 bd23ad33accef14684d42c32769092a0), containing a 32-bit EXE with zero-day privilege escalation (CVE-2018-8120).

This one contains an interesting IOC, under debug info:

In May 2018, we performed a retro-hunt on VirusTotal Intelligence with this IOC, but identified no new samples.


The goal of this post is to teach you how to triage and analyze malicious PDF documents. With static analysis tools, even sophisticated zero-day PDFs can quickly reveal their payload, sometimes with very distinct IOCs.

Microsoft and Adobe have patched these zero-days.


We created a video with step-by-step instructions to analyze these malicious PDFs:

If you are interested in receiving our advisories via our mailing list, you can subscribe by sending us an e-mail at

Want to learn more? Please do join us at the upcoming BruCON training on malicious documents, which was authored by NVISO’s experts!

About the authors
Didier Stevens is a malware expert working for NVISO. Didier is a SANS Internet Storm Center senior handler and Microsoft MVP, and has developed numerous popular tools to assist with malware analysis. You can find Didier on Twitter and LinkedIn.

Painless Cuckoo Sandbox Installation

TLDR: As part of our SANS SEC599 development efforts, we updated (fixed + added some new features) an existing Cuckoo Auto Install script by Buguroo Security to automate Cuckoo sandbox installation (& VM import). Download it from our Github here.

As a blue team member, you often have a need to analyze a piece of malware yourself. For example, if you discover a malware sample in your network and suspect it might be part of a targeted attack. There’s a few options in this case: you could reverse the sample or do some static analysis, but maybe you want to get a “quick” insight by running it in a sandbox… It is often not desirable to submit your samples to public, online malware analysis services, as this might tip off your adversaries. So… How to proceed?

In the SANS training SEC599 that we’ve co-developed at NVISO (“Defeating Advanced Adversaries – Implementing Kill Chain Defenses”), we decided we wanted to show students how analysis can be performed using Cuckoo sandbox, a popular open source automated malware analysis system (We do love Cuckoo!).

After re-deploying manually Cuckoo a number of times in different environments, I (Erik speaking here) figured there must be a better way… After doing some Google’ing, I found the CuckooAutoinstall script created by Buguroo Security!

An excellent effort indeed, but it hadn’t been updated for a while, so we decided to update this script to include some additional features and enabled it to run with the latest version of Ubuntu (16.04 LTS) and Cuckoo (2.0.5). You can find it on our GitHub repository.

Preparing your sandbox
Before we do a walk-through of this script, let’s pause a moment to consider what it takes to set up a malware analysis environment. The type of analysis performed by Cuckoo can be classified as dynamic analysis: the malware sample is executed in a controlled environment (a Virtual Machine) and its behavior is observed. As most malware targets the Windows operating system and/or the applications running on it, you will need to create a Windows VM for Cuckoo.

You will need to step out of your role as a blue team member to prepare this VM: this VM has to be as vulnerable as possible! To increase the chances of malware executing inside the VM, you will have to disable most of the protections and hardening you would implement on machines in your corporate network. For example, you will not install an anti-virus in this VM, disable UAC, don’t install patches,…

To properly analyze malicious Office documents, you will use an older, unpatched version of Microsoft Office and you will disable macro security: you want the macros to run as soon as the document is opened, without user interaction.

Take your hardening policies and guidelines, and then …, do the opposite! It will be fun (they said…)!

Using CuckooAutoinstall
Installing Cuckoo with CuckooAutoinstall is easy: prepare your VM and export it to the OVA format, update the script with your VM settings, and execute it as root. We will discuss how you can create Cuckoo analysis VMs in a follow-up blogpost!

It’s best that your Ubuntu OS is up-to-date before you launch the script, otherwise you might encounter errors when CuckooAutoinstall will install the necessary dependencies, like this error on Ubuntu:


Updating the script with your VM settings is easy, these are the parameters you can change:





Then execute the script as root. It will take about 15 minutes to execute, depending on your Internet speed and size of your VM. If you are interested in seeing the progress of the script step by step, use option –verbose.


When the script finishes execution, you want to see only green check-marks:


Testing your Cuckoo installation
To start Cuckoo, you execute the script created by CuckooAutoinstall for you:



Then you can use a web browser to navigate to port 8000 on the machine where you installed Cuckoo:


Submit a sample, and let it run:



After a minute, you’ll be able to view the report. Make sure you do this, because if you get the following message, your guest VM is not properly configured for Cuckoo:


The best way to fix issues with your guest VM, is to log on with the cuckoo user (credentials can be found & modified in the CuckooAutoinstall script), start VirtualBox and launch your VM from the “clean” snapshot.



Once you have troubleshooted your VM (for example, fix network issues), you take a snapshot and name this snapshot “clean” (and remove the previous “clean” snapshot). Then try to submit again (for each analysis, Cuckoo will launch your VM from the “clean” snapshot).

This will give you a report without errors:


Although installing Cuckoo can be difficult, the CuckooAutoinstall script will automate the installation and make it easy, provided you configured your guest VM properly. We plan to address the configuration of your guest VM in an upcoming blog post, but for now you can use Cuckoo’s recommendations.

It is possible to install Cuckoo (with CuckooAutoinstall) on Ubuntu running in a virtual environment. We have done this with AWS and VMware. There can be some limitations though, depending on your environment. For example, it could be possible that you can not configure more than one CPU for your Cuckoo guest VM. As there are malware samples that try to evade detection by checking the number of CPUs, this could be an issue, and you would be better off using a physical Cuckoo install.

Want to learn more? Please do join us at one of the upcoming SEC599 SANS classes, which was co-authored by NVISO’s experts!

About the authors
Didier Stevens is a malware expert working for NVISO. Didier is a SANS Internet Storm Center handler and Microsoft MVP, and has developed numerous popular tools to assist with malware analysis. You can find Didier on Twitter and LinkedIn.

Erik Van Buggenhout is a co-founder of NVISO with vast experience in penetration testing, red teaming and incident response. He is also a Certified Instructor for the SANS Institute, where he is the co-author of SEC599. You can find Erik on Twitter and LinkedIn.

Creating custom YARA rules

In a previous post, we created YARA rules to detect compromised CCleaner executables (YARA rules to detect compromised CCleaner executables). We will use this example as an opportunity to illustrate how the creation of these custom YARA rules was performed.

In its blog post, Talos shared 3 hashes as Indicators Of Compromise (IOCs):


Although not explicitly stated in the Talos report, these are SHA256 hashes. We can infer this from the length of the hexadecimal strings. A hexadecimal character represents 4 bits, hence  64 hexadecimal characters represent 256 bits.

Admittedly, YARA is not the best tool to scan files with hashes as IOCs. YARA is designed to use pattern matching to scan malware, and early versions of YARA did not even have the capability to use cryptographic hashes. In later versions, a hash module was introduced to provide this capability.

A simple rule to match files based on a SHA256 IOC can be implemented like this:

import "hash"</p>
<p style="text-align:justify;">rule simple_hash_rule {
hash.sha256(0, filesize) == "1a4a5123d7b2c534cb3e3168f7032cf9ebf38b9a2a97226d0fdb7933cf6030ff"

Line 1 imports the hash module, which we need to calculate the SHA256 value of the content of a file.

The rule simple_hash_rule has just a condition (line 5): the SHA256 value of the content of the file is calculated with method call hash.sha256(0, filesize) and then compared to the IOC as a string. Remark that string comparison is case-sensitive, and that the cryptographic hash functions of the hash module return the hash values as lowercase hexadecimal strings. Hence, we have to provide the IOC hash as a lowercase string.

Using this simple rule to scan the C: drive of a Windows workstation in search of compromised CCleaner executables will take time: the YARA engine has to completely read each file on the disk to calculate its SHA256 value.

This can be optimized by writing a rule that will not hash files that can not possibly yield the hash we are looking for. One method to achieve this, is to first check the file size of a file and only calculate the SHA256 hash if the file size corresponds to the file size of the compromised executable.

This is what we did in this rule:

import "hash"</p>
<p style="text-align:justify;">rule ccleaner_compromised_installer {
filesize == 9791816 and hash.sha256(0, filesize) == "1a4a5123d7b2c534cb3e3168f7032cf9ebf38b9a2a97226d0fdb7933cf6030ff"

In this rule, we first compare the filesize variable to 9791816 and then we calculate the hash. Because the and operator uses lazy evaluation, the right-side operand will only be evaluated if the left-side operator is true. With this, we achieve our goal: only if the filesize is right, will the SHA256 hash be calculated. This will speed up the scanning process by excluding files with the wrong file size.

There is one caveat though: Talos did not report the file sizes for the IOCs they published. However, we were able to obtain samples of the compromised CCleaner files, and that’s how we know the file sizes.

If you are not in a position to get a copy of the samples, you can still search the Internet for information on these samples like the file size. For example, this particular sample was analyzed by Hybrid Analysis, and the file size is mentioned in the report:

You can also find information for this sample on VirusTotal, but the analysis report does not mention the exact file size, just 9.34 MB.

This information can still be used to create a rule that is optimized for performance, by accepting a range of possible file size values, like this:

import "hash"</p>
<p style="text-align:justify;">rule filesize_and_hash {
filesize &amp;gt;= 9.33 * 1024 * 1024 and filesize &amp;lt;= 9.35 * 1024 * 1024 and hash.sha256(0, filesize) == "1a4a5123d7b2c534cb3e3168f7032cf9ebf38b9a2a97226d0fdb7933cf6030ff"

This rule will first check if the file size is between 9.33MB and 9.35MB (1024 * 1024 is 1 MB) and if true, then calculate the hash.


Writing custom YARA rules is a skill that requires practice. If you want to become proficient at writing your own YARA rules, we recommend that you embrace all opportunities to write rules, and step by step make more complex rules.

About the author

Didier Stevens is a malware expert working for NVISO. Didier is a SANS Internet Storm Center handler and Microsoft MVP, and has developed numerous popular tools to assist with malware analysis. You can find Didier on Twitter and LinkedIn.


“We are happy to share our knowledge with the community and thus hope you enjoyed the content provided on this article! If you’re interested in receiving dedicated support to help you improve your cyber security capabilities, please don’t hesitate to have a look at the services NVISO offers! We can help you define a cyber security strategy / roadmap, but can also offer highly technical services such as security assessments, security monitoring, threat hunting & incident response ( Want to learn similar techniques? Have a look at the SEC599 SANS class, which was co-authored by NVISO’s experts! (”

Going beyond Wireshark: experiments in visualising network traffic

At NVISO Labs, we are constantly trying to find better ways of understanding the data our analysts are looking at. This ranges from our SOC analysts looking at millions of collected data points per day all the way to the malware analyst tearing apart a malware sample and trying to make sense of its behaviour.

In this context, our work often involves investigating raw network traffic logs. Analysing these often takes a lot of time: a 1MB network traffic capture (PCAP) can easily contain several hundred different packets (and most are much larger!). Going through these network events in traditional tools such as Wireshark is extremely valuable; however they are not always the best to quickly understand from a higher level what is actually going on.

In this blog post we want to perform a series of experiments to try and improve our understanding of captured network traffic as intuitively as possible, by exclusively using interactive visualisations.

Screen Shot 2018-02-15 at 00.07.26.png

A screen we are all familiar with – our beloved Wireshark! Unmatched capabilities to analyse even the most exotic protocols, but scrolling & filtering through events can be daunting if we want to quickly understand what is actually happening inside the PCAP. In the screenshot a 15Kb sample containing 112 packets.

For this blog post we will use this simple 112 packet PCAP to experiment with novel ways of visualising and understanding our network data. Let’s go!

Experiment 1 – Visualising network traffic using graph nodes
As a first step, we simply represent all IP packets in our PCAP as unconnected graph nodes. Each dot in the visualisation represents the source of a packet. A packet being sent from source A to destination B is visualised as the dot visually traveling from A to B. This simple principle is highlighted below. For our experiments, the time dimension is normalised: each packet traveling from A to B is visualised in the order they took place, but we don’t distinguish the duration between packets for now.

IP traffic illustrated as interactive nodes.

This visualisation already allows us to quickly see and understand a few things:

  • We quickly see which IP addresses are most actively communicating with each other ( and
  • It’s quickly visible which hosts account for the “bulk” of the traffic
  • We see how interactions between systems change as time moves on.

A few shortcomings of this first experiment include:

  • We have no clue on the actual content of the network communication (is this DNS? HTTP? Something else?)
  • IP addresses are made to be processed by a computer, not by a human; adding additional context to make them easier to classify by a human analyst would definitely help.

Experiment 2 – Adding context to IP address information
By using basic information to enrich the nodes in our graph, we can aggregate all LAN traffic into a single node. This lets us quickly see which external systems our LAN hosts are communicating with:

Tagging the LAN segment clearly shows which packets leaves the network.

By doing this, we have improved our understanding of the data in a few ways:

  • We can very quickly see which traffic is leaving our LAN, and which external (internet facing) systems are involved in the communication.
  • All the internal LAN traffic is now represented as 1 node in our graph; this can be interesting in case our analyst wants to quickly check which network segments are involved in the communication.

However, we still face a few shortcomings:

  • We still don’t really have a clue on the actual content of the network communication (is this DNS? HTTP? Something else?)
  • We don’t know much about the external systems that are being contacted.

Experiment 3 – Isolating specific types of traffic
By applying simple visual filters to our simulation (just like we do in tools like Wireshark), we can make a selection of the packets we want to investigate. The benefit of doing this is that we can easily focus on the type of traffic we want to investigate without being burdened with things we don’t care about at that point in time of the analysis.

In the example below, we have isolated DNS traffic; we quickly see that the PCAP contains communication between hosts in our LAN (remember, the LAN dot now represents traffic from multiple hosts!) and 2 different DNS servers.

When isolating DNS traffic in our graph, we clearly see communication with a non-corporate DNS server.

Once we notice that the rogue DNS server is being contacted by a LAN host, we can change our visualisation to see which domain name is being queried by which server.We also conveniently attached the context tag “Suspicious DNS server” to host (the result of our previous experiment). The result is illustrated below. It also shows that we are not only limited by showing relations between IP addresses; we can for example illustrate the link between the DNS server and the hosts they query.

We clearly see the suspicious DNS server making request to 2 different domain names. For each request made by the suspicious DNS server, we see an interaction from a host in the LAN.

Even with larger network captures, we can use this technique to quickly visualise connectivity to suspicious systems. In the example below, we can quickly see that the bulk of all DNS traffic is being sent to the trusted corporate DNS server, whereas a single hosts is interacting with the suspicious DNS server we identified before.

So what’s next?
Nothing keeps us from entirely changing the relation between two nodes; typically, we are used to visualising packets as going from IP address A to IP address B; however, more exotic visualisations as possible (think about the relations between user-agents and domains, query lengths and DNS requests, etc.); in addition, there is plenty of opportunity to add more context to our graph nodes (link an IP address to a geographical location, correlate domain names with Indicators of Compromise, use whitelists and blacklists to more quickly distinguish baseline vs. other traffic, etc.). These are topics we want to further explore.

Going forward, we plan on continuing to share our experiments and insights with the community around this topic! Depending on where this takes us, we plan on releasing part of a more complete toolset to the community, too.

Making our lab rats happy, 1 piece of cheese at a time!

Squeesh out! 🐀

About the author
Daan Raman is in charge of NVISO Labs, the research arm of NVISO. Together with the team, he drives initiatives around innovation to ensure we stay on top of our game; innovating the things we do, the technology we use and the way we work form an essential part of this. Daan doesn’t like to write about himself in third-person. You can contact him at or find Daan online on Twitter and LinkedIn.


YARA rules for CCleaner 5.33

First reported by Talos and Morphisec, the compromise of CCleaner version 5.33 is still making news.

At NVISO Labs, we created YARA detection rules as soon as the news broke, and distributed these rules to our clients subscribed to our NVISO Security Advisories. In a later blog post, we will explain in detail how to create such YARA rules, so that you can do the same for your organization.

Here are the YARA rules we created:

// YARA rules compromised CCleaner
// NVISO 2017/09/18

import "hash"

rule ccleaner_compromised_installer {
		filesize == 9791816 and hash.sha256(0, filesize) == "1a4a5123d7b2c534cb3e3168f7032cf9ebf38b9a2a97226d0fdb7933cf6030ff"

rule ccleaner_compromised_application {
		filesize == 7781592 and hash.sha256(0, filesize) == "36b36ee9515e0a60629d2c722b006b33e543dce1c8c2611053e0651a0bfdb2e9" or
		filesize == 7680216 and hash.sha256(0, filesize) == "6f7840c77f99049d788155c1351e1560b62b8ad18ad0e9adda8218b9f432f0a9"

rule ccleaner_compromised_pdb {
		$a = "s:\\workspace\\ccleaner\\branches\\v5.33\\bin\\CCleaner\\Release\\CCleaner.pdb" 
		$b = "s:\\workspace\\ccleaner\\branches\\v5.33\\bin\\CCleaner\\ReleaseTV\\CCleaner.pdb" 
		uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and ($a or $b)

You can scan the C: drive of a computer with YARA like this:

yara64.exe -r ccleaner.yara C:\

And there are also many other scanning tools that include the YARA engine, like ClamAV.


The first 2 rules we created are hash based, but the third rule (ccleaner_compromised_pdb) is based on a particular string found in CCleaner’s 32-bit executables. This string is the full path of the Program Database (PDB) file, a debug file created by default by Visual Studio and referenced in compiled executables.

With this rule, we were able to identify 235 files on VirusTotal. Most of these are actually container files (like ZIP files): CCleaner is a popular application, and is distributed through various channels other than Piriform’s website. We saw examples of portable application packages distributing this compromised version of CCleaner (like LiberKey) and also RAR files with pirated versions of CCleaner.

23 files were actual executables, and were all compromised versions of the 32-bit executable of CCleaner version 5.33, except one. Most of these files did not have a (valid) signature: they were modified versions, e.g. cracked and infected with other malware.

Only one executable detected by our ccleaner_compromised_pdb rule was not infected: an executable with SHA256 hash c48b9db429e5f0284481b4611bb5b69fb6d5f9ce0d23dcc4e4bf63d97b883fb2. It turns out to be a 32-bit executable of CCleaner version 5.33, digitally signed on 14/09/2017, e.g. after Talos informed Avast/Piriform. The build number was increased with one (6163 instead of 6162). This executable was signed with the same certificate that was used for the compromised version 5.33 (thumbprint f4bda9efa31ef4a8fa3b6bb0be13862d7b8ed9b0), and also for follow-up version 5.34. Yesterday (20/9/2017), Piriform finally released a new version (5.35) signed with a new digital certificate obtained yesterday.

At this moment, we are uncertain about the origins and purpose of this particular executable (c48b9db429e5f0284481b4611bb5b69fb6d5f9ce0d23dcc4e4bf63d97b883fb2).

Are you infected?

Our rules allow you to detect compromised CCleaner executables in your environment, but this does not imply that the machines identified by these rules were infected.

Our analysis shows that the compromised CCleaner installer (version 5.33) will install 32-bit and 64-bit versions of the CCleaner executables on a Windows 64-bit machine, and only the 32-bit version on a Windows 32-bit machine.

The shortcuts (like Start and Desktop shortcuts) deployed during the install on Windows 64-bit machines will point to the 64-bit executable, hence normal usage on a Windows 64-bit machine will execute 64-bit CCleaner.

Only the 32-bit executable of CCleaner is compromised.

It is therefore perfectly possible that compromised 32-bit executables of CCleaner are detected on Windows 64-bit machines with the YARA rules we provided, but that this compromised version was never executed.

If the compromised 32-bit executable runs successfully, it will create the following registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Piriform\Agomo

Two values will be found for this key: MUID and TCID


We recommend that you check for the presence of this registry key, should our YARA rules detect compromised CCleaner installations on your machines.

Compromised machines should be reinstalled after a DFIR investigation.

Decoding malware via simple statistical analysis


Analyzing malware often requires code reverse engineering which can scare people away from malware analysis.

Executables are often encoded to avoid detection. For example, many malicious Word documents have an embedded executable payload that is base64 encoded (or some other encoding). To understand the encoding, and be able to decode the payload for further analysis, reversing of the macro code is often performed.

But code reversing is not the only possible solution. Here we will describe a statistical analysis method that can be applied to certain malware families, such as the Hancitor malicious documents. We will present this method step by step.


First we start with a Windows executable (PE file) that is BASE64 encoded. In BASE64 encoding, 64 different characters are used to encode bytes. 64 is 6 bits, hence there is an overhead when encoding in BASE64, as encoding one byte (8 bits) will require 2 BASE64 characters (6 bits + 2 bits).

With, we can generate statistics for the different byte values found in a file. When we use this to analyze our BASE64 encoded executable, we get this output:


In the screenshot above see that we have 64 different byte values, and that 100% of the byte values are BASE64 characters. This is a strong indication that the data in file base64.txt is indeed BASE64 encoded.

Using the option -r of, we are presented with an overview of the ranges of byte values found in the file:


The identified ranges /0123456789, ABCDEFGHIJKLMNOPQRSTUVWXYZ and abcdefghijklmnopqrstuvwxyz (and single charcter +) confirm that this is indeed BASE64 data. Padded BASE64 data would include one or two padding characters at the end (the padding character is =).

Decoding this file with (a BASE64 decoding tool), confirms that it is a PE file (cfr. MZ header) that is BASE64 encoded.


Now, sometimes the encoding is a bit more complex than just BASE64 encoding.

Let’s take a look at another sample:


The range of lowercase letters, for example, starts with d (in stead of a) and ends with } (in stead of z). We observer a similar change for the other ranges.

It looks like all BASE64 characters have been shifted 3 positions to the right.

We can test this hypothesis by subtracting 3 from every byte value (that’s shifting 3 positions to the left) and analyzing the result. To subtract 3 from every byte, we use program takes a file as input and an arithmetic operation: operation “byte – 3” will subtract 3 from every byte value.

This is the result we get when we perform a statistical analysis of the byte values shifted 3 positions to the left:


In the screenshot above we see 64 unique bytes and all bytes are BASE64 characters. When we try to decode this with base64dump, we can indeed recover the executable:


Let’s move on to another example. Malicious documents that deliver Hancitor malware use an encoding that is a bit more complex:


This time, we have 68 unique byte values, and the ranges are shifted by 3 positions when we look at the left of a range, but they appear to be shifted by 4 positions when we look at the right of a range.

How can this be explained?

One hypothesis, is that the malware is encoded by shifting some of the bytes with 3 positions, and the other bytes with 4 positions. A simple method is to alternate this shift: the first byte is shifted by 3 positions, the second by 4 positions, the third again by 3 positions, the fourth by 4 positions, and so on …

Let’s try out this hypothesis, by using to shift by 3 or 4 positions depending on the position:


Variable position is an integer that gives the position of the byte (starts with 0), and position % 2 is the remainder of dividing position by 2. Expression position % 2 == 0 is True for even positions, and False for uneven positions. IFF is the IF Function: if argument 1 is true, it returns argument 2, otherwise it returns argument 3. This is how we can shift our input alternating with 3 and 4.

But as you can see, the result is certainly not BASE64, so our hypothesis is wrong.

Let’s try with shifting by 4 and 3 (instead of 3 and 4):


This time we get the ranges for BASE64.

Testing with confirms our hypothesis:



Malware authors use encoding schemes that can be reverse engineered by statistical analysis and testing simple hypotheses. Sometimes a bit of trial and error is needed, but these encoding schemes can be simple enough to decode without having to perform reverse engineering of code.

Recovering custom hashes for the Petya/Notpetya malware

During our malware analysis, we often come across samples that contain (custom) hashes in stead of cleartext. Hashing is done in an effort to bypass detection and hinder malware analysts. There are tools to recover cleartext from known hashing methods (like John the Ripper and hashcat). But for custom hashing methods, you’ll have to write some code. In this blog post, we illustrate a method to recover the custom hashes of a non-croptygraphic hashing method used by malware to obfuscate its behavior.

The Petya/Notpetya malware contains code to check which processes are running on a victim machine, and change its behavior accordingly. Microsoft has explained this in detail, with the custom hashing function and hash values to identify processes, however without reporting the process names the malware looks for.

At NVISO, we like to share knowledge and this blog post is no different. We will explain you how we recovered the process names, so that you can use this method in your own malware analysis endeavors.

The names of the processes are not hardcoded in the malware code, but a custom hash function is used to identify the processes of interest:

The custom hash function clears bits in variable v10 if process names that match custom hash values 0x2E214B44, 0x6403527E and 0x651B3005 are found.

A (cryptographic) hash function is not reversible, so we will need to figure out another way to match these hashes with actual process names. Cracking hashes is done with dictionary and brute force attacks: a trial and error method where the hash function is used with input values from the dictionary/brute-force generator until a matching hash is found. Remark that this custom hash function is not a cryptographic hash function and that the hash value is 4 bytes long, so many collisions will be found when brute forcing.

We suspected that the process names of interest are security related: antivirus software, firewalls, … Meterpreter has a killav function that contains a list of process names of security software.  We used this list in our dictionary attack.

Next step is to write a program to perform the attack. Because execution speed could be crucial, we wrote it in C. We took the decompiled custom hash function source code and modified it a bit to be compiled with Visual Studio:

void ConfigCheckProcesses(_TCHAR* processname)
unsigned int v0; // ebx@3
unsigned int v1; // kr00_4@3
unsigned int v2; // edx@4
unsigned int v3; // esi@5
char *v4; // ecx@6
char v5; // al@6
int v9; // [esp+230h] [ebp-8h]@3
int v10; // [esp+234h] [ebp-4h]@1

v10 = -1;
v9 = 0x12345678;
v0 = 0;
v1 = _tcslen(processname);
v2 = 0;
if (v1)
v3 = v0;
v4 = (char *)&amp;v9 + (v3 &amp; 3);
v5 = (*v4 ^ LOBYTE(processname[v2++])) - 1;
*v4 = v5;
} while (v2 &lt; v1);
} while (v0 &lt; 3);
if (v9 == 0x2E214B44)
_tprintf_s(TEXT("0x2E214B44: %s\n"), processname);
else if (v9 == 0x6403527E)
_tprintf_s(TEXT("0x6403527E: %s\n"), processname);
else if (v9 == 0x651B3005)
_tprintf_s(TEXT("0x651B3005: %s\n"), processname);

While performing a dictionary attack with our customized hash function and Meterpreter’s list as dictionary, we recovered one hash: 0x2E214B44 is avp.exe (Kaspersky). When we searched Twitter for avp.exe, we found one interesting tweet. We looked at this person other tweets to see if they had recovered the other hashes, unfortunately they did not.

So the next step was to perform a brute-force attack. We generated process names with characters a-z, A-Z (the custom hash function is case sensitive), 0-9 and . – _ and assumed the extension would be .exe.
Here is the result:

Hash 0x651B3005 is NS.exe (Norton Security). That left us with hash 0x6403527E to recover. Since these two hashes are used to clear the same bit, we assumed that the processes might somehow be related. Googling for process names related to NS.exe, we came upon different process names for Norton and Symantec software. A short dictionary attack with these names revealed that 0x6403527E is ccSvcHst.exe (Symantec).


When you have a decompiler available to recover the source code of custom hash functions, one can quickly transform that source code in a working program to perform dictionary attacks and (small) brute force attacks. Larger brute force attacks will require more complex code to speed up the recovery process: multi-threaded code or code that uses GPUs.