Tuesday, October 21, 2008

Unpacking UPX

This was a presentation I gave at a SPARSA meeting. It's just a basic overview of how packers work and how one might go about unpacking a packed executable.

A packer is a compression tool (in this example used for PE files) for binary files. Other types of compression could be: Zip, rar, tar, bzip, gzip, etc. When UPX compresses the PE file, it has to know how to decompress it once the program is run. This version of UPX (http://upx.sourceforge.net/#download) uses a decompression loop that is inserted during compression. Once the binary executes the decompression loop, it is unpacked in to memory. If we wish to obtain the original unpacked binary, we just have to dump the process from memory..sounds easy enough. Why would we want to obtain the unpacked executable? If we weren't sure of the packer, or it wasn't UPX (which you can decompress using the command "upx -d") we would be unable to understand the disassembled code in your favorite disassembler.

To start, I'll show the PEiD (http://www.peid.info/) output of winmine.exe to show it isn't packed. PEiD works much like antivirus products do. It uses a signature database to find byte-matching patterns within the file.


To pack the executable, we simply run the UPX command on the command line.


We can still run the new executable, winmine_packed.exe, from the command line because it simply decompresses the binary file in to memory. To show that the file was successfully packed, we can throw the new executable back in to PEiD.

Ok, now for the fun part. We have to open the packed executable in a debugger. For this presentation I used OllyDBG (http://www.ollydbg.de/download.htm). OllyDBG will complain that the file is compressed but we already know this. Once we get in to OllyDBG, the first comamnd we see is PUSHAD. This command pushes all the registers on to the stack. This way they can be decompressed in to memory. The call we are looking for is POPAD, which would make sense because it pops the registers back off the stack after the decompression loop.


If you scroll down in Olly, you should find POPAD near the bottom of the loop.


You can see at the end of the loop the program compares the ESP (stack pointer) with the EAX register. If it is not decompressed, it jumps back to the the PUSH 0 call. If however, the decompression loop is complete, it uses a JMP command. This is exactly what we're looking for. If we follow this jump, we will find our original entry point in the program (OEP). The original entry point is where the unpacked binary starts. We will start by placing a breakpoint on the final JMP call. This way, once we start the program, it will hault on that call. You can set a breakpoint in OllyDBG by pressing F2 on the JMP call.

You then would start the program execution either by clicking the Play button in Olly, or by pressing F9. It should hit the breakpoint you set and hault execution. Now, the JMP should lead us back to the OEP. To move one step in Olly, rather than execution the remaining code, you can press F7 (step into). You should now be at the oep and olly should display something like this:


Now that we have gone through the decompression loop, our binary is unpacked in memory. The next step is to dump the process from memory. To do this, I used a tool called LordPE (http://www.woodmann.net/collaborative/tools/index.php/LordPE). Open up LordPE and select the winmine_packed.exe process that is running through OllyDBG. Right click the process, and select "Dump Full".


I would suggest naming it something that you will remember such as winmine_dumped.exe. Now that the program has been dumped from memory, lets try to run it.


As you may have thought, the fun is not over yet. Once the dumped program is executed, you are confronted with an error saying it was unable to initialize properly. When a process is dumped from memory, this can mess up the import table. A PE file's import table is used to know which files it needs to dynamically link to when mapping in to memory (DLLs). So how do we fix this? We use another program I used in this presentation called ImportREC (http://vault.reversers.org/ImpRECDef). Again, select winmine_packed.exe from the process list. The program should finish loading the process, and give you an Image Base. Lets go back to our Olly window that's still open, and get the address of our OEP.


As seen earlier, our address of the OEP is 01003E21. Back in ImportREC, we need to set the OEP in the IAT Info section. If our image base is already 01000000, then our OEP would be at 0003E21 (Image base plus + OEP = relative location in memory). We then click the IAT AutoSearch button in ImportRec:


You should see a good looking message stating that it found an address which may be in the original IAT. If we follow the instructions in the dialog box, we would click Get Imports at the bottom of ImportREC.


ImportREC should look something like the screenshot above. It has successfully found imports for winmine_packed.exe. We then click Fix Dump, and select our previously dumped winmine file (winmine_dumped.exe). ImportREC will then save the file as winmine_dumped_.exe. Let's throw that file back in to PEiD to see if it's still packed:

We are back to where we started, and the dumped binary is able to run successfully.

No comments: