Hello all. This post has been stuck in my drafts since roughly November, and I’ve put this off for long enough.
Today’s paid post will discuss malware packers; what they are and how they work. I encourage you to follow along!
Packing, in malware terms, is defined as the process of concealing the malicious executable within another executable. Prior to executing the malicious code, it is “unpacked” with a small routine. The packed part of the executable is usually obfuscated or encrypted, which can throw off analysts. Packing falls under the anti-tamper/anti-disassembly umbrella.
A main part of packing is that the unpacked executable remains in memory. So, there is no extra file you get and can then drop into IDA.
Identifying Packed Executables
Obviously, you can’t unpack something that isn’t packed. So how do you know if an executable as packed?
By String
Some packers can leave distinct strings within the binary that can guide us and tell if the program is packed. Some strings can be obvious, like the name of the packing tool, and others can add custom section names.
*Nix “file” Command
If you are running your reversing machine on Linux (or have WSL), you have access to the file
command. This can possibly reveal if an executable is packed if it used a common packer like UPX or PECompact.
packerid
Found here, packerid is a command-line tool (like file
) that can detect packed executables.
Detect-It-Easy
Found here, Detect-It-Easy is, well, easy. Drop a file into it and it will tell you if it is packed and what kind of packer is used.
Methodology
Acquire a packed executable
Inspect its differences and functionality within packed form
Unpack it
Requirements
A PE explorer
A disassembler
x64dbg (x32dbg is what will be used since the program is in x86)
Unpacking Manually
There are tons of packers and packing algorithms, and don’t forget misdirection and anti-reversing techniques to throw you off even further. Some programs detect when you launch tools like debuggers, sniffers, spoofer, unpackers, and more and then exit immediately to prevent you from inspecting how the program is packed. This is rather advanced, so we’ll skip anything like this for now.
For today’s example, we will explore UPX, as it is a common packer tool. If we wanted to go balls to the wall, we would use something like Themida. But that is something well beyond my knowledge at the time.
On the ol’ Tor site lies a .zip called unpacker.zip, it is under the programs folder as it isn’t malicious.
Go ahead and run halt.exe and inspect what it does. Looks awfully familiar, doesn’t it?
Let’s throw it into PeStudio. It looks weird. There are only 4 imported functions and 1 imported library. Remember RTMA Part 8? An empty executable had 66 imported functions. This is strange.
Obviously, you already know that this file is packed, but the very few imported functions, added sections (that are named UPX0, UPX1, etc.), and high file entropy (>7.5) are hints that clue you in if a file is packed. Also, tossing the file into IDA may cause an error to pop up about code sections being compressed or corrupted. If you continue with analysis, you would see how gobbledegook the file looks.
It needs to be unpacked. Fortunately, there is a tool call Scylla to help us with this. Scylla is one of the more unpopular unpackers which is built into x64dbg, others include OllyDbg’s OllyDump, UnpackMe, KsDumper for kernel-level dumping, and even IDA Pro which has a universal unpacker plugin.
There’s one thing you have to do first. There exists what is called the Original Entry Point (OEP). You know how there is a main() function when you build a C++ program? That is the entry point of the program. However, when a program is packed, that entry point is changed to the entry point of the unpacking algorithm. You are going to have to discover this manually. Fortunately, for some packers, there is a trick you can use.
Many packers utilize a jmp to EAX/RAX which leads you to the OEP. UPX doesn’t do this, but it does bookmark its functionality with the pushad and popad instructions. These instructions respectively push and pop all of the registers in the CPU. So, to unpack this executable, you will want to start your search for the OEP after the popad instruction. Here is what you do:
Open x32dbg
Press F3 and open halt.exe
Press F9 to get past the entry breakpoint
Here you have 2 methods to acquire the OEP: the easy method and the surefire method.
Easy
Press Ctrl+F and enter “popad”
Hopefully only 1 address pops up. Double click it
If there is more than one, make sure you are searching within the halt.exe region
Set a breakpoint at the popad instruction (click the little orb to the left)
Surefire
Press F8 to step down below the pushad instruction
Under the registers tab, right click ESP’s register value and click “Follow in Dump”
Right click the hex value of the address and click Breakpoint → Hardware, Access → Dword
(You may need to hit f9 a few extra times to reach the following jmp instruction if using this method)
Press F9
You should be at or just below the popad instruction now
Find the jmp instruction below it and set a breakpoint on it
Press F9
Press F8
Tada, you are at the OEP. Now you can dump the program.
Press the Scylla S on your toolbar (or Ctrl+I)
Make sure the OEP is set to 004093B4
Click IAT Autosearch (either yes or no on the popup will give the same result)
Click Get Imports
Click Dump and export to a file
Click Fix Dump and select the file you just exported
Scylla has now dumped the program with a reconstructed IAT. You can now open the dumped file in IDA and explore what it contains.
Here is a comparison between the packed and dumped call graph:
Much easier to diagnose. And you can see the password: P@$$VV0Rd
.
That’s all for this post. There is a lot more to packers. Some malware packs itself multiple times, and some malware uses its own specialized packing algorithm. This also opens up much more with self-defending malware. Imagine trying to unpack without access to a debugger.
Also, there is a way to reconstruct the PE header to actually run the dumped executable without getting a Windows error. After several hours of trial and error, I have failed to accomplish this. If you’re cool enough, look into LordPE or some other PE reconstructor and maybe you can fix it for me :). This is also why this post took so long to come out as I kept left-curving myself into failing this. I aim to write another post concerning successfully executing a dumped executable eventually. I’ll admit, I’ve never actually done an unpacking myself before. I’ve just played it on TV.
Thanks for reading, as always.
Go!
-BowTiedCrawfish