Unpacking Malware
Different Types Of Packers
Packer is a software that protects other software through obfuscation, compression, virtualization, etc.
Free [Easiest]: Created as part of a research project or simply out of interest, very commonly used to pack less sophisticated malware. Example: UPX, nPack, MEW, PolyCryptor, MPRESS, PE Protector.
Regular: Custom packers written solely for obfuscating malware and hiding from AV (Anti-Vires), Either custom to a specific group, or sold on markets HF. Examples: Warzone Crypter, Yakuza Crypter, Atilla Crypter, AspireCrypt, Spartan Crypter, Emotet, Dridex, ISFB, Trickbot, etc…
Commercial [Difficult]: Created to protect legitimate software, typically licensed software, occasionally used to protect malware.
Example: VMProtect Themida, Obsidium, Armadillo, ASPack, PELock.
Detecting Packed Malware
- Signatures: Tools like PEID, YaraScan, etc. Can pick up signatures and detect them based on rules, signatures range from values to byte patterns
- Strings: A lack of strings (or an abundance of nonsensical strings) in the binary could be an indicator the program is packed in some way.
- Imports: Once again, a lack of important (or an abundance of unusual imports) in the binary could be an indicator that the program is packed.
- Section Names: Packers Commonly add extra sections to the binary, such as UPX. These names could be named after the packer, or be completely random.
- Entropy: Entropy is determined by the frequency of recurring bytes- the higher the number of recurring bytes – this usually indicates the data is encrypted.
- Raw/ Virtual Sizes: Raw section sizes signify the size of sections while not running, while virtual section sizes are the opposites. Noticeable differences between the two could indicate the sample is packed
Common Packer Functionality
Now we going to have a look at common packer functionality in the context of malware, so in this part, we show how malware is packed.
We have a malicious executable that is developed and passed to a software packer, the packer will pack the executable and append an unpacking stub to the packed executable.
So, the unpacking stub will basically decrypt and reverse what the packer does, so let’s say for example the packer will go ahead and AUS encrypt the payload and will then be obfuscated using jz compression, the unpacking start with go ahead and jz decompress the payload the AUS decrypted using a key obesely from the backer and then will be responsible for loading the unpacked payload into memory and executing it.
And now we go looking at how unpacking works:
Unpacking the stub here with the malicious executable will allocate a region of memory inside of the process memory and then copy the shellcode inside of it (in memory), so this shell code can be stored as encrypted plain text and copied on the allocated region of memory. Then will jump to the shell code and execute it, the shell code will allocate another region of memory and will decrypt the executable and copy it into that region of memory that is allocated. But at this point, we have the plain text executable so you can dump it out
Method Of Unpacking Common Packers
Statically: this is the most difficult you can do and involves reverse engineering, an entire unpacking routine: Algorithms, “Egg Hunting”, Parsing EXE & Shellcode, and defiantly very time-consuming.
Dynamically: Using a debugger to place breakpoints on common unpacking functions: VirualProtect(Ex)
, VirualAlloc(Ex)
, WriteprocessMemory
, etc.
Automatically: Automated software either online or local: Unpac.me, PE-Sieve, Sandboxes, etc.
In this, I will focus on dynamic one…
Step-By-Step Malware Analysis Using x32dbg
I want to put a few breakpoints on ProcessInjection, just in case malware injects running processes, VirualAlloc
, VirtualProtect
, CreateProcessInternalW
, WriteProcessMemory
, and last one is DebaggerePresent just in case it uses one of the common anti-debug techniques
And let’s go ahead and run, so immediately it calls CreateProcessInternalW
So we going to put a breakpoint into NtResumeThread to inject unpack code and run
And that is what’s looks like immediately, in this case, we will open another x32dbg that attaches to another process and put the same breakpoint we did previously.
After run we get the VirtualProtect and after VirtualAlloc
And after following it in the dump we will find the shellcode that will be allocated into the memory by using VirtualAlloc and change the privileges by using VirtualProtect
And we can find it’s using the UPX technique right now!
We can dump it out before it is mapped into memory and unpack UPX manually or just automatically.
Get the dump from the process hacker and save it
By using cff explorer we can unpack UPX