Boy…that took way longer than I anticipated….
After opening up the initial binary in Part 2 I then took my time to get all the way down and into the final stage to see the first connect to the C2 in action. However, this turned out to be a maze of rabbit holes. API-Hashing, SEH-Exploits, dozen unknown (for me at least) Anti-Debugging-Techniques and hours wasted debugging code. Not everything I learned along the way was relevant and needed to analyze this sample BUT it served as a great „reality check“ and showed me how much I really
don’t know about Windows Internals. To broaden my knowledge and feel even less knowledgeable I ordered the Windows Internals (Amazon, no ref). If you ever think you know it all…read this book! 😉
First of all, what do we know so far:
- Sample exports a lot of seemingly obfuscated functions
- Runs via rundll32.exe with Control_RunDll
- No interesting strings (packed)
- Several Anti-Debug-Functions
- First function-calls via macro seem to be decoy
- Final stage will be run either from C:\Windows\SysWOW64 (Admin) or %appdata% with random folder name and random name
Now, first thing will be to unpack the sample. We know so far that the later stages will be run from either SysWOW or appdata folder, therefore we could wait and catch the next stage from said location. Stepping through, this is exactly what I did. After observing data copied to heap we can see the first interesting non-obfuscated function call which will create the new Process with rundll32.exe.
Rabbit hole 1
This is where I lost a lot of time trying to find any clue or any clever decoy from the authors. Maybe there was something I missed, some clever anti-vm or anti-debug-technique. Maybe something major that I overlooked? This led me down all kinds of rabbit-holes and while I learned a lot along the way, I also wasted a lot of time on other things that where not at all connected to this sample. For example, did you know that James Howells mined 7500Bitcoins in 2009 and then decided to throw the HDD away?
No? Well, now you do 😉 (don’t ask me how I got here though)
After days and days I am now fairly certain that I found all the interesting functions of the malware. The meat of the binary is still hidden in the final stage which still needs to be unpacked at this point.
After getting around some Anti-Debug and checking for any other interesting activities I ended up with the potentially final stage of the malware. It turns out that the malware, no matter where it is running from, will go through the following cycle:
- Start via macro with random function-calls
- Create random folder in %appdata% or SysWOW and random name then run from there with function call Control_RunDLL
- Decrypt the whole thing and rewrite itself and drop it again with random name and function call Control_RunDLL
After realizing this, I dumped the final stage before it was able to run and compared the exports. As you can see, all of them gone except Control_RunDLL.
There are no imports either which is an indicator for dynamically resolving functions and if we look at the code in ghidra we also see no function calls which means API-Hashing, which lead me to…
Rabbit hole 2
The final stage is supposed to be run via Control_RunDll which will then start contacting the C2. However, the dll itself could also be launched without any function call which will then call Dll_main which will again loop and relaunch itself by going through the mentioned cycle above. After analyzing the differences between first and last stage again it turned out that the only real interesting difference is the missing obfuscated functions. Those are, as already seen, stripped from the last stage and could either mean hidden code or simply decoy or a mix of both. I spent way too much time trying to de-obfuscate functions and connected code without coming to a real interesting conclusion. At least in this regard this version is behaving similar to older samples.
As we are only left with 2 functions, I wanted to checkout the main function first. The code here seems to be very simple and confirms the cycle I described before.
If Module 1 is called of Control_RunDll then do all the other stuff (bracket), otherwise return 1 which will lead to aforementioned procedure.
Now, at first the code of the interesting function looks simple but here is where I fell down the next rabbit hole…trying to decipher obfuscated and flattened code.
head -> desk
After a lot of trial and error I went the manual route and simply sat there and just stepped through all the code manually. Issue here was that each function call was hashed, therefore not visible directly. The binary encrypted any interesting string/function just for a few instructions and decrypted it again shortly afterwards. If you are able to find the key you may be able to decrypt all function-calls in a shorter timeframe than going through it all manually. Did not workout for me this time.
After some more anti-debugging-techniques I then finally ended up with the interesting functions. By hooking the dll itself I was able to catch all obfuscated function-calls which then lead me to the final code where the binary opens up a socket and tries to connect back to the C2. After some OSINT I was able to match those IOCs to the Emotet Epoch 5. At the moment only sending out spam and connecting back to the C2.
I started collecting IOCs but stopped shortly after. The idea of this blog was not to be another emotet-tracker but get a bit more into the details of what is going on here. Now to be fair, the meat of it was more about Trickbot/Dridex and less about emotet itself. Nonetheless, I think I got a good understanding of what is going on at each step and what the main idea of the binary is. Obviously, I am late to the party and others already analyzed emotet/trickbot long before me. Emotet itself already learned new tricks and therefore this blog may be already old news.
Still, I personally learned a lot and am eager to go deeper in some of those rabbit holes I discovered. For now I will leave you with this emotet-tracker.