On January 29, 2020, The Twitter account of VeraCrypt (@VeraCrypt_IDRIX) posted a tweet about a fake VeraCrypt website (httx://vera-crypt[.]com) that was distributing modified VeraCrypt installers that are signed with a valid EV code signing certificate from an unknown company. I was intrigued. The fake website was still up, so I decided to look into it. Here is a write-up of my analysis to try to understand what the modified binaries do, how are they obfuscated, who the authors could be, and what’s the motivation.
A phishing website?
The fake website looked identical to the official VeraCrypt website, but the links on the pages didn’t work too well. In particular, the download page was only serving the installer binaries for Windows and Mac, and the portable version for Windows. The rest led to a 404 error page. Interestingly, the Mac binary was actually genuine, only Windows binaries were modified.
Assuming the binaries are malicious in some way (which we will know for sure very soon), a successful attack would first require a victim to be lured into visiting the fake website. In fact, someone abused Google Ads to promote the fake website when searching for “veracrypt” on Google. A contact at ESET further told me that the ad was most likely targeted at Canada only.
Modified VeraCrypt installer
In this article, I will focus on the modified installer for Windows, as it’s probably the most common format people download. It is signed by a certificate issued to Calmic Software Ltd, a UK software development company.
The fake installer version info matches that of the official VeraCrypt v1.23 from September 2018.
In terms of size, the fake installer is slightly smaller than the official one (35,821,320 vs. 35,837,752 bytes, respectively). This does not necessarily mean something was “removed”. For instance, the difference in the signature certificates could easily account for the difference. But this may hint at a slight modification of VeraCrypt, maybe a backdoor?
I compared both binaries using Beyond Compare, which looks at each byte from the two files and tries to account for misalignment due to inserted/removed data. That’s how I started when I studied the official builds of TrueCrypt against their source codes. On the right image here, you can visualize in red the sections that are dissimilar. The white block that fills the first quarter is a section where both files fully match. So, this is not a totally different binary. Rather, there is still a taste of VeraCrypt here.
TrueCrypt/VeraCrypt’s installer is actually built as follows: the files to extract/install on a system are compressed and packaged at the end of the installer’s binary file. The logic of the installer is located at the beginning, which is roughly the part that is identical between the official and fake installers. The non-matching part therefore seems to correspond mostly to the compressed payload.
Roughly same installers
Firing IDA Pro and BinDiff, I was able to identify mismatching functions inside the installer. Most functions matched, except for few ones.
The biggest difference is in
sub_4236F0 (real) /
sub_421540 (fake). The real function is populated with 100+ lines of decompiled code, while the fake installer’s version simply consists of “
These functions are called from the main function as follows.
The string “DIST_PACKAGE_CORRUPTED” led me to a line in VeraCrypt source code in Setup.c that gives me the name of this function:
VerifyModuleSignature is an addition in VeraCrypt compared to TrueCrypt, which verifies that the signing certificate used to sign the binary is the genuine VeraCrypt’s certificate, by comparing its hash against a hardcoded value. That should have pissed the malware author, who went the extra mile to re-sign the modified installer with a valid EV code signing certificate, and could not run the installer without modification 🙂
Next, the functions
write_string_0 and other statically-linked libraries seem to be functionally the same, but technically a slightly different. They are most likely fine. The differences could be explained by the mismatch between the version of the compiler used for the official and fake builds.
sub_41AC50 is a VeraCrypt function responsible for checking whether the system boots with EFI/GPT or not. I was able to identify the function thanks to hardcoded error messages pointing to
GetSystemDriveConfiguration. Due to code inlining, the source code looks much more concise than the actual generated code. That makes the identification of differences more difficult. Nevertheless, I was able to understand the few small differences I found.
One difference resides in the code generated for
.str(). Again, this has to do with compiler versions. Another one also probably has to do with a library, but I was unable to confirm. The location of this difference, in
GetSystemDriveConfiguration (a low interest function), probably indicates this is just an artifact of the compilation rather than a motivated change. The difference in the decompiled code is shown below.
So, essentially, the installer code is the same as the official one, minus the signature certificate check.
Different extracted files
Now, let’s run the installer to extract its files. I often use Sandboxie to run those kind of unknown executables, but there’s always a risk it grabs real info from my system when it runs and sends it away. So in this case, I prefer to run it inside a virtual machine, on a fresh install of Windows.
Next, we continue to compare the extracted files against the official VeraCrypt v1.23 files. However, most of them are different… This could be explained by a different way of compiling VeraCrypt, in which case I might need to figure out which version of the compiler and environment settings were used. That could be a pretty painful process.
Before I start the endeavor of recompiling VeraCrypt with different configurations, how about we check the extracted files’ version info again? Good hunch, the versions of the extracted files do not match. While the fake installer corresponds to v1.23, the extracted files are actually from v1.23-Hotfix2. Go figure who repackaged this with the wrong installer…
OK, let’s compare with VeraCrypt v1.23-Hotfix2 extracted files then:
Now, only VeraCrypt.exe and VeraCrypt-x64.exe differ. We are getting closer…
Firing IDA Pro and BinDiff, I was able to identify mismatching functions inside VeraCrypt-x64.exe. Most functions matched, except for few ones.
Note: I did the same exercise with VeraCrypt.exe and found similar results, so I’ll skip the analysis here.
Let’s start with the most different function, with a similarity score of 0.00:
sub_140001900 in the fake installer.
What you see in this function is something you do not want to see in an application like VeraCrypt: it wants to connect to a server. Note the first condition on the result of
sub_140001780, which is already identified with BinDiff as another mismatching function (second-to-last in the list).
The result of
sub_140001780 is simply the result of calling InternetCrackUrlA on the argument to the function, which basically splits parts of the URL (yes, it’s a legitimate Windows function, despite the name). So this condition will always work if the URL is good.
So what’s the URL? The function
sub_140001900 is called by
sub_140001E00, the third-to-last function identified by BinDiff. And here is your URL passed as argument!
Let’s rename the functions with the knowledge we gained so far.
sub_140001900 is basically in charge of fetching a URL, let’s call it
sub_140001780 parses a URL, it’ll be called
Now let’s dig further into
sub_140001E00 to understand what it does with the downloaded file. From my understanding, it simply is a PE loader: it makes sure the file is a Windows binary (checks for MZ and PE signatures), copy the content to a newly allocated memory region, parses the file’s import table to load the required DLLs into memory and provide their addresses, then it passes control to the file’s entry point.
We will therefore rename
download_and_run_dll. In turn, this function is called by a
StartAddress is called from the main (wWinMain) as a new thread, which keeps running thanks to the infinite loop. Note the addition of
StartAddress compared to the official VeraCrypt’s main function.
What’s in getdll.php?
At this point, it is clear that the modified VeraCrypt’s main binary has been added with a downloader that fetches a remote payload hosted at 184.108.40.206.
The DLL returned from
/getdll.php is a pretty verbose piece of code that further fetches other payloads and places them in a folder in
%AppData%, named after some unique identifier returned from a request to
To fetch the payloads, the “getdll” DLL comes with its own small HTTP client.
It proceeds to do a POST request to various URLs while sending the data “geo”.
Eventually, the payloads will look like this on disk:
The mapping between URLs and filenames is as follows:
- 220.127.116.11/work/?work <-> [ID]\[ID].exe
- 18.104.22.168/work/?code <-> [ID]\big_log
- 22.214.171.124/work/?data=[ID] <-> [ID]\data
- 126.96.36.199/work/?service <-> [ID]\pulse
- 188.8.131.52/work/?check <-> [md5(username)].dll
pulse is encrypted when written to disk, by simply XORing the content with the [ID].
Similarly, the file
proxy.txt contains the string “veracrypto.com” XORed with the [ID], and the file
mask.txt contains the encrypted string “%d_yq_%02u.%02u.%02u”.
data is also encrypted the same way, this time by the server (recall the
?data=[ID] argument). Finally, so that it knows which unique ID was picked, the ID is kindly written in the
id.txt file in
%AppData%. If the file is present,
getdll will not fetch again these DLLs.
In the next parts of this write-up, I will cover what’s included in those multiple payloads, and how I emulated the malicious server as it stopped serving the malicious payloads due to the complaint addressed to its hosting provider. Stay tuned!
Update: Part 2 deals with plenty of obfuscation and anti-analysis techniques in the payloads.