You are here

Detecting anomalies in the RICH header

ivan's picture

A few days ago, Kaspersky published a blog post regarding a likely false flag in the wiper component of OlympicDestroyer. The attempt is based on an undocumented, lesser-known PE header called the RICH header. I don’t want to go into too much details regarding its layout, as many other sources have done a great job documenting it. Suffice it to say that this is an opaque structure added by Microsoft’s build environments during link time. If two programs have the same (or a very close) RICH header, one can assume that they were built in the same environment.

I had heard about this structure in the past and had been wanting to add support for it in Manalyze, as a way to improve the compiler detection beyond somewhat unreliable Yara rules. This was an opportunity to go back to it and look for additional ideas.

First of all, let’s look at one such header dumped from a sample executable (Notepad++):

 

This calls for a few comments:

  • The toolchain fingerprinting is based on its build number, and a few of them are missing in the example above. This implies that an effort needs to be made to curate the version information of all known VS components.
  • Conversely, not all object types are recognized. This is because the same objects can have different identifiers between toolchains, so that’s another moving target. So far, I haven’t been able to identify a reliable source that lists them all.
  • The   key present in the structure is used to obfuscate it. It is derived from the contents of the DOS header and the RICH header itself, so it also acts as a checksum of sorts.

Initially, I guessed that this checksum was the way Kaspersky detected the false flag attempt. Due to the way it is calculated, it turns out not to be the case: the DOS header is mostly constant across files. However, thinking back, I figured it could be used to detect an antivirus bypass trick that was posted on Twitter a few months ago:


This is a simple, stupid, yet apparently effective way to decrease VT scores, just by altering the “This program cannot be run in DOS mode” string. Changing a single byte from it however renders the RICH checksum invalid and will now lead to the following message in Manalyze:

 

Looking for other ideas, I stumbled upon this 2017 paper from Technische Universität München. What they’re doing is malware clustering based on the contents of the RICH header. They also propose two ideas to detect packed binaries based on “RICH corruption”:

  • Validating the   key, as I had done above.
  • Looking for duplicate entries, which apparently Visual Studio never causes. I have to admit I’m a little bit suspicious about this method, as I fail to imagine what kind of packer would make such modifications to the RICH header.

However, I noticed that this header contained the total number of imported functions and thought this might be a good way to see if the file was modified after the compilation step. I ran a few tests, and I ran into a high number of false positives. For some reason I haven’t been able to figure out, it’s quite common for the RICH header to report more imports than there actually are. However, I have yet to find a legitimate executable where the RICH header indicates less of them, so I’ve added this heuristic to Manalyze as well.

If we see a discrepancy between the reported number of imports and the actual one, we can make one of the two following hypotheses:

  • The program has been packed and its   was replaced.
  • The RICH header of the PE has been manually edited or does not belong to it.

Here’s Manalyze’s output for the wiper described in Kaspersky’s article:

 

To the best of my knowledge, this is an original finding, and I’m currently gathering files which exhibit this behavior. So far, here are a few I’ve located (excluding those with an invalid checksum):

 

While I haven’t looked into them at the moment, they all seem pretty suspicious from a static perspective. Let me know if you have other ideas on the subject!