Most of you must’ve already heard of the mighty “ZeuS” aka Zbot. First identified in July 2007 and is estimated to have caused damages worth US$100 million. So it’s a pretty big deal. Today we are going to take a quick look at it. The ZeuS malware mutated over the years so obviously the hashes will differ. The sample I am going to analyze have the below hash:
SHA256: 9ed85a6de31604eb431cdd7632cad0e5be54af10a16cc6ca0b886d1f92bb91b8
Note: I am no expert malware analyst. This writeup simply shows what methods i used to analyze this sample. Obviously different tools and techniques could be used.
Let’s begin. When we try to execute the malware and have a look at it in the Process Hacker
the malware just runs for a few seconds and then exits. If we run a behavioral analysis on this sample what we get useful is that CaptureBat
tells us that it modified and deleted some files under certain directories. One of them being a batch file called upd25acfa62.bat
and located under %TEMP%
directory.
The file content shows us that it tries to delete the malware sample we ran.
Ok. Let’s have a look at it in IDA pro.
If we look at the code we will see a lot of junk code like this.
We can see these API calls in almost every Windows GUI application. This is a method used by a lot of malware families like Poison Ivy
. By implementing this pattern malware tries to bypass static analysis tools by looking like a legit Windows GUI app.
The IAT shows this malware calls only non-suspicious APIs. We already know that this sample is packed.
If we were to look at the strings we can’t see anything useful either.
A lot of malware samples are dealing with the unpacking process by decrypting their contents, create a new process and inject the malicious content inside the newly created process. However this does not seem to be the case with “ZeuS” since we did not see it creating a new process. In this case we can say that the malware decrypts malicious content and injects it inside its own .text
section. It makes sense because all we got in the .text
section was boring Windows GUI API calls. So the malware must’ve implemented this method.
Let’s fire up the Immunity Dbg
and give it our sample as an input file.
Since we know that the decrypted contents will be written into the .text
section we can place a Hardware on Write
breakpoint in that section. When we do that and run the sample, somewhere in the code the breakpoint gets hit.
When we run until exit of the current function the .text
section gets zeroed out and we fall in the space of another function.
The other function:
After we run until exit of this one as well the contents of the .text
section is filled with data.
After the decryption routine the malware must resolve the OEP in order to start executing the malicious code. Most of the time the indicators of decrypted OEP is a call to the eax
register or an unconditional jump followed by a lot of garbage code. We are gonna look out for both.
if we run until exit of the current function after the .text
section is decrypted we find ourselves in a place like this.
There is the call eax
instruction we have been looking for. If we step into the function looks like the address is in the range of the .text
section and we can see valid assembly instructions.
So we are sure this is the OEP we were searching for. Now we can dump the process with Scylla
. For the unpacked code to be runnable we need to Fix the Dump. After doing so we got ourselves the unpacked version of malware.
Here is the virustotal’s analysis on our unpacked sample
After opening the unpacked PE in IDA pro we still see that the Imports table is incomplete
This means that the malware is resolving the function names during run-time. Let’s find out how. When we scroll through the functions and look at the xrefs in IDA we come across something like this
(I already knew what it was that’s why I renamed it). As we can see the xref count is to high for this function. This is a common technique used by malwares to resolve function names dynamically.
The get_api
function in itself calls two functions lib_decryptor
& string_deobfuscator
(Again, I already knew what they were that’s why I renamed them).
The lib_decryptor
function has a loop that goes through certain blocks of memory and decrypts the contents then makes a call to LoadLibraryA
or GetModuleHandleA
to load the module.
By placing a breakpoint in the loop we can see certain strings appear in the memory
Here is the list of the loaded modules
The string_deobfuscator
function is similar to the lib_decryptor
function. It also has a loop that goes through certain blocks of memory to decrypt the strings.
By placing a breakpoint on this loop as well we come across some interesting strings.
Here we see that the malware tries to gather information related to the operating system.
We can see the malware implements some anti-debugging techniques by searching for strings that tell about existence of a virtual machine in the system. It does that for VirtualBox
too.
Then we can see the contents of the .bat file that is supposed to delete the sample.
The API resolving happens with the help of get_api
function. After calling the get_api
function each time the malware makes a call to the eax
register which holds the resolved function name. Instead of locating each encrypted blob in each loop(Because different addresses used for different strings) I let the malware resolve the function names for me.
So I wrote a python script that searches for a pattern like call e
and places breakpoints with conditions on those addresses with the condition being printing the value of EAX
.
After getting the addresses we need them to resolve to function names. That’s why I wrote a Windbg
script.
I know most people are gonna laugh at me for doing such a sloppy job and I know there are other ways, the right ways of doing it, like with pykd
but I was too lazy so a went with the lazy way.
After executing the script the output is kinda messy
So we are going to beautify it
And there is our Import table
Thanks for your attention :)