Statically Unpacking a Brazilian Banker Malware

Published: 2018-02-20. Last Updated: 2018-02-20 17:30:49 UTC
by Renato Marinho (Version: 1)
0 comment(s)

After going through an almost endless amount of encoded droppers and loader scripts while analyzing a Brazilian banker, I finally managed to reach the actual payload, an interestingly packed/encrypted banking malware. How I statically unpacked this payload is the subject of today’s diary and I hope it will help you in your future analysis.

The Sample

One of the first things we do when we get a new sample is using a tool to identify important characteristics of the file, like the file type (whether it’s a PE or ELF file), the compiler, if it is packed and, luckily, the packer used. Packing is a very common way used by adversaries to compress the malware and make it harder to reverse engineer.

Let’s take a look at our sample using the Die (Detect it Easy) tool.

Figure 1 – Sample information

Among other things, Die tries to detect the sample packer based on binary signatures. If it does match with any known ones, it is shown near the compiler and link information. If it does not, as ours did, you may try to figure it out by analyzing the file’s entropy. The higher the entropy or randomness of a binary file, higher are chances it is packed. Let’s check it out.

Figure 2 – Sample entropy

As you can see, the overall entropy is very high (7.97 out of 8), which indicates, with a high probability, the file is packed.

Analyzing this sample with IDA Pro, there is another great indicator of packing. As seen in Figure 3, there is a tiny block of real code (blue color) in the beginning of IDA’s overview navigator band followed by a giant blob of data (brown color) where the packed malware payload might be.

Figure 3 – Sample graphic view into IDA Pro

In situations like those, where the file is packed by an unknown packer, there is a great chance the malware developer used a self-made function to pack the payload. Let’s try to find it.

Looking for packing function

Moving the navigator overview to the beginning of the giant blob, it is possible to find its start address, as seen in Figure 4.

Figure 4 – Blob start address

Additionally, to start address (0x6D1C9020), there is an important information in this figure, which is the function that refers to it (sub_6D1C1FD9:loc_6D1C213C). In other words, there is a great chance this is the unpacking function.

Moving forward to this function, we have the assembly code shown in Figure 5.

Figure 5 – Unpacking function analysis

From this we have:

  1. The payload size: we already knew the payload initial address (0x6D1C9020), but we didn’t know yet its size. Now we have it: 0x2F4200h;
  2. The blob packed address is loaded into “rsi” register;
  3. Decryption loop comparing r12 (blob size) with “rax” (the loop counter) while interacting with blob bytes;
  4. Decryption function: xor <blob byte> with 8h;

So, as seen, this is the packing function. Let’s move on.

Unpacking

Now, it’s time to try to unpack the payload using the found function. To this end, it’s necessary to extract the packed payload from the binary and implement a function to interact with its bytes while applying the ‘xor’ function.

To extract the packed payload, I used the Python script [1] shown in Figure 6. It basically receives the initial address and size of the blob and the output file.

Figure 6 – Memdump IDA Pro Python script by herrcode [1]

The result of this operation will be a bunch of bytes with no meaning, as expected, as seen in Figure 7.

Figure 7 – Extracted packed payload

Finally, it’s time to try to decrypt this payload applying the ‘xor’ function. To this end, I implemented a simple Powershell script, as seen in Figure 8.

Figure 8 – Unpacking Python Script

After running this script against the packed content, I ended up with the binary code shown in Figure 9.

Figure 9 – Unpacked binary

As seen, the result is an executable binary file (MZ header), which means the unpacking/decrypting process run successfully.

Normally, at this point, we should have a more palatable binary, in theory, easier to be handled in a static analysis. However, in this case, the resultant binary was also packed and I had to apply the same process to open it until I had enough information on the malware intentions and IOCs.

Final notes

While writing this diary, I found a very interesting video [2] from Sergei Frankoff (@herrcode), which helped me a lot better structuring my analysis and report. Thanks for sharing with the community @herrcore.

Binary Hash

a3de2862fc7cc4aa27cccfcef2c094b7f6eebb6aab73507c1836be8c3b80fedb

References

[1] http://codegists.com/snippet/python/ida_memdumppy_herrcore_python
[2] https://www.youtube.com/watch?v=HfSQlC76_s4

-
Renato Marinho
Morphus Labs| LinkedInTwitter

Keywords:
0 comment(s)

Comments


Diary Archives