Revealing the Trick | A Deep Dive into TrickLoader Obfuscation

Within the TrickBot framework, there has historically been a loader component. This loader has had continued development over the years since TrickBot’s first release where the ECS key and bot binary were stored in the resource section of the loader [1]. However, the function obfuscation has received relatively little treatment until now.

Executive Summary

  • TrickBot developers have continued to be active over the years.
  • Loader used by TrickBot has had continued development related to obfuscation for anti-analysis.
  • The TrickLoader leverages ‘minilzo’ compression, which comes from the LZO library and its usage by these developers dates back to Dyre/Upatre timeframe.
  • The goal is to detail the loader and aid additional automation efforts to process the TrickLoader.

Research Insight

TrickLoader obfuscation development timeline:

2017 – Started obfuscating the resource section name
2017 – Custom base64 of strings
2018 – Adds user account control (UAC) bypass [5], Heaven’s Gate [2], function obfuscation and further hiding the configuration

Most of these have been reported on in detail with the exception of the function obfuscation, which has been mentioned but not really detailed. Researchers who write scripts for config retrieval have stopped putting them out as frequently as in the past, possibly due to the increased focus by TrickBot to obfuscate and hide the data.

Let’s dive into the obfuscation. The function offsets are stored in a table. The first thing the loader does is execute a call over that table that will push the address of the table onto the stack for the next block of code to use.

image of Call over offset table
Figure 1: Call over offset table

 

The next section will then process the word values from the table in sequence by adding them to a value which is initially the start address of the table and then being pushed onto the stack.

image of Overview of rebuilding addresses from table
Figure 2: Overview of rebuilding addresses from table

 

Reconstructing this process into Python code allows us to create the same table as long as we can recover certain values from the binary.

image of Python code to demonstrate rebuilding the table manually
Figure 3: Python code to demonstrate rebuilding the table manually

 

After the function table is rebuilt, a call is made to one of the functions that is responsible for decoding out the other functions and data blobs.

 

image of Call to decode function after rebuilding table
Figure 4: Decode function after rebuilding table

 

image of Decode function
Figure 5: Decode function

 

The function decodes the next function. The key is the last value in the rebuilt table address with 0x18 added to it, and the length of the key is 0x327 bytes. Using this we should be able to decode out all the addresses in the rebuilt table.

image of Decode all objects from the table
Figure 6: Decode all the objects from the table

 

After decoding all the objects, we can check the sizes of each by printing out the size of every element of the decoded_data list.

image of Check decoded object sizes
Figure 7: Check decoded object sizes

 

Most of them look normal; however, there are a few that seem larger than what you would normally observe in the size of a single function.

image of Compressed objects
Figure 8: Compressed objects

 

These larger decoded objects are actually compressed data. It turns out there are at least 3 compressed objects: a 32 bit TrickBot binary, a large blob of 64-bit bytecode which is the 64 bit TrickBot binary, and a smaller 64-bit EXE file which is a loader for the 64-bit bytecode blob.

The compression is ‘minilzo’, which comes from the LZO library, and its usage by these developers dates back to Dyre/Upatre timeframe. After decompressing the 32-bit binary and fixing the missing ‘MZ’, we have the 32-bit TrickBot binary.

Now that we have the normal TrickBot binary, we can decode out the onboard configuration data which is hidden and XOR encoded inside the bot now. Taking an existing decoder from CAPE [4] and adjusting it a bit while adding in our deobfuscation works well!

Indicators of Compromise (IOCs)

SHA-256: ac27e0944ce794ebbb7e5fb8a851b9b0586b3b674dfa39e196a8cd47e9ee72b2
<mcconf>

<ver>1000480</ver>

<gtag>tot598</gtag>

<servs>

<srv>144.91.79.9:443</srv>
<srv>172.245.97.148:443</srv>
<srv>85.204.116.139:443</srv>
<srv>185.62.188.117:443</srv>
<srv>185.222.202.76:443</srv>
<srv>144.91.79.12:443</srv>
<srv>185.68.93.43:443</srv>
<srv>195.123.238.191:443</srv>
<srv>146.185.219.29:443</srv>
<srv>195.133.196.151:443</srv>
<srv>91.235.129.60:443</srv>
<srv>23.227.206.170:443</srv>
<srv>185.222.202.192:443</srv>
<srv>190.154.203.218:449</srv>
<srv>178.183.150.169:449</srv>
<srv>200.116.199.10:449</srv>
<srv>187.58.56.26:449</srv>
<srv>177.103.240.149:449</srv>
<srv>81.190.160.139:449</srv>
<srv>200.21.51.38:449</srv>
<srv>181.49.61.237:449</srv>
<srv>46.174.235.36:449</srv>
<srv>36.89.85.103:449</srv>
<srv>170.233.120.53:449</srv>
<srv>89.228.243.148:449</srv>
<srv>31.214.138.207:449</srv>
<srv>186.42.98.254:449</srv>
<srv>195.93.223.100:449</srv>
<srv>181.112.52.26:449</srv>
<srv>190.13.160.19:449</srv>
<srv>186.71.150.23:449</srv>
<srv>190.152.4.98:449</srv>
<srv>170.82.156.53:449</srv>
<srv>131.161.253.190:449</srv>
<srv>200.127.121.99:449</srv>
<srv>45.235.213.126:449</srv>
<srv>31.128.13.45:449</srv>
<srv>181.10.207.234:449</srv>
<srv>201.187.105.123:449</srv>
<srv>201.210.120.239:449</srv>
<srv>190.152.125.22:449</srv>
<srv>103.69.216.86:449</srv>
<srv>128.201.174.107:449</srv>
<srv>101.108.92.111:449</srv>
<srv>190.111.255.219:449</srv>

</servs>

<autorun>

<module name="systeminfo" ctl="GetSystemInfo"/>

<module name="pwgrab"/>

</autorun>

</mcconf>

References

1: https://www.fidelissecurity.com/threatgeek/archive/trickbot-we-missed-you-dyre/
2: http://www.hexacorn.com/blog/2015/10/26/heavens-gate-and-a-chameleon-code-x8664/
3: http://www.oberhumer.com/opensource/lzo/
4: https://github.com/ctxis/CAPE
5: https://sysopfb.github.io/malware/2018/04/16/trickbot-uacme.html

0 / 55