Reverse Engineering Packed Malware
Updated: a day ago
Hello all, In this blog I will be unpacking few malware samples one of the famous banking trojans - Dridex. Malware packers are most common things a malware analyst would come across. Almost every malware is packed and obfuscated to bypass signature checks and behavioral check from antivirus software.
Basically a Packer is a software that protects other software through obfuscation, compression, virtualization etc. There are free, paid and custom packers available at present. Some of the free packers are easily detectable and can be unpacked to deobfuscate the packed binary as there will be a unpacker available for these. Then there are custom packers written solely for obfuscating malware and hiding from antivirus softwares. These are sold on markets like hack forums. Finally there are commercial packers created to protect legitimate software, licensed software. Its very rare that malware samples use commercial packers.If at all we find, then its gonna be our worst nightmare to unpack. Usually, country sponsored or APT groups come up with such strong mechanisms.
Free packers : UPX, nPack, MEW, PolyCryptor etc
Malware packers : Warzone cryptor, Yakuza cryptor, Emotet, Dridex, Trickbot etc
Commercial : VMProtect, Themida, Armadillo, PElock etc
So how to detect malware that's packed ? We can always check few attributes listed below Signatures : tools like yara and PEID can pick up signatures and detect based on rules. Its always good to keep updating yara rules by gathering information through open source intelligence.
Strings : lack of strings or abundance of obfuscated strings in binary can indicate that the binary is packed.
Imports : You will usually see very less number of imports in the binary which is an indicator that the program is packed
Section Names : Packers either add an extra section to the binary or add obfuscated resources to the resource section of PE file.
Entropy : Entropy is determined by the frequenc of recurring bytes. Higher entropy usually indicates the data in encrypted
Raw/Virtual Sizes : Raw section sizes of the binary indicates the size of binary on disk, where as virtual size indicates the size when its loaded into memory. So when you see a huge difference mostly in the code section's raw size and virtual size, it indicates the binary is packed.
okay enough of theory, lets unpack few packed malware samples now
Lets open dridex in PE studio, you can observe the high entropy of the binary. Description says nProtect KeyCrypt Program database DLL, quick google search tells that it is a online security company, malware author is trying to make it look legitimate.
Then lets goahead and look at optional headers of the PE file. You can clearly see the size of the code is zero byte which clearly indicates that its packed.
Now lets take a look at directories tab in PE Studio tool, you can see the timestamp of 2020 and 2038 which doesnt match and clearly not possible.
Now lets look at the sections present in the PE file, you can see a new section named text1 which is normally rare in case of regular executables.
On looking at imports sections of the PE file clearly says what the binary is intended.
advapi32.dll - usually used while accessing registry keys
wininet.dll - provides support to use ftp, http protocols
winsock dll - used for socket programming for ex create network packets, listen on ports etc
resource section of the pe file have two resources, out of which one has E X C E L signature.
here is a snapshot of strings in the binary, except the section names, rest everything is obfuscated.
Now lets proceed with dynamic analysis and extracting the original dridex file from the packed binary.
One of the best ways to unpack is to use a debugger, in my case I used x32dbg and place breakpoints on common unpacking functions: VirtualProtect(Ex), VirtualAlloc(Ex), WriteProcessMemory(Ex).
VirtualProtect - Changes the protection on a region of committed pages in the virtual address space of the calling process.
VirtualAlloc - Allocates memory in the target process. Incase of packers, mostly this is current process's memory.
WriteProcessMemory - Writes data to the specified memory location
you can use the hard method to find what all function calls made by the packed binary used while it executed. You can do this safely if you have a linux os with wine installed in it. wine is an open source software for running windows applications in linux.
wine has an awesome feature called debug channels where you can dynamically analyze function calls are made by malware samples.
In case of dridex sample, you can find from the below screenshot that the above specified win api functions are used.
The following command lets you find all api calls
As mentioned, set the breakpoints and run the debugger, you will observe that debuggers stops at VirtualAlloc function primarily.
Hit execute till return button and follow the memory dump closely at the memory address i.e the return value stored in EAX register.
we can see the unpacked executable that's needed to be dropped now in the region thats recently allocated. At this stage, its unpacked executable as we couldnt find any section names.lets wait until the original process get mapped into memory.
We need to Keep track of the memory addresses in map returned by the VirualAlloc until we hit the breakpoint at virtual protect. At this point you can see that its mapped into memory.
Post the call to virtual protect, jump to user code and put a break point at jmp eax instruction post virtual protect.When we hit this breakpoint, we can clearly see the entry point of the dridex loader.
Once we got the entry point, lets use process hacker to dump unpacked binary from the dridex process's memory. As you can see, the entry point is in range above address 0x10000000, dump the the specific memory from process hacker.
On opening the dumped binary in PE Bear, still we can see the imports are unresolved.This is because its mapped into memory, we need to unmap it. For that we need to update the raw address to virtual address and adjust raw size of pe file.
Here I updated imagebase to 0x10000000 i.e address in virtual memory where the executable should be loaded, raw address to map the virtual address and updated the raw size of the bin file.
Here you can clearly see that the imports are resolved and now we can save dridex.exe unpacked sample for further analysis using IDA
This way we can unpack packers like dridex. Similarly we can unpack other packers too, I will be updating them in the upcoming blogs. I would like to thank @VK _Intel for my learnings. Thanks!