This paper is a brief introduction to unpacking. We'll review a simple packer named UPX.
Originally, a packer is a program used to compress a binary's code in order to make executables smaller.
Nowadays however, with the current storage capacities, executables's size is not an issue.
Still, packers are now heavily used by malware authors to make it more difficult for AVs to detect, and harder
to reverse engineer.
They can also be used by professional developers to prevent their softwares from being cracked.
The packer generally adds a bunch of code to the program, the loader.
When the program will be executed and mapped into memory, that loader will be the first chunk of code to be
executed, before the program itself so as to decompress the original code.
Once done, it will start the execution of the original code.
Now let's see how to decompress a program packed with UPX.
1. Dump the program: The loader will unpack/decompress the program in the memory, so we'll need to dump it to
disk while it's running
in memory in order to have an unpacked/decompressed program.
2. Fix the original entry point (OEP) and rebuild the Import Address Table (IAT): Once dumped, our program won't run yet
because the packer also updates the OEP to be able to load first.
It will also destroy a part of the IAT which the program needs to load the DLLs and their APIs.
More info will be given later regarding the IAT.
Let's load the program in Olly:
The selected row is the loader's OEP. The PUSHAD
instructions saves all registers on the stack.
This mean we're pretty confident about finding a POPAD
instruction at some point in the loader's code, to restore these registers.
Finally, we should get to the original entrypoint of our program.
With UPX, this last step is done immediately after the registers have been restored. It means we
will find the following pattern:
POPAD (61h)
JMP [ OEP ]
So let's search for this JMP: it's generally at the bottom of the listing. Once found, set a breakpoint on it
run the software (F9) untill Olly breaks, then step over (F8) and you'll be at the OEP:
Now we're out of the loader's code, and the program has been unpacked in the virtual memory.
Write down the OEP: it is a RVA, it means it's relative to the ImageBase address and our ImageBase is 400000.
As the OEP here is 0040131C, we need to fix the ImageBase:
OEP=40131C-400000=131C. Now dump the program while it is unpacked in memory (using LordPE here).
We now need to fix the OEP: load the packed executable into ImpREC and fill in the fixed OEP (1) with the one we wrote down earlier.
Now we need to rebuild the IAT. First, some info about the IAT:
Every program relies on some APIs to do its job.
These APIs are loaded into virtual memory and shared between the running softwares.
The IAT is a required mechanism since these APIs are loaded at different locations in
the virtual memory across machines/reboots.
It is basically composed of 2 arrays, each containing the names of the APIs the software uses.
At execution time, the names in the first array are resolved to addresses in the second array.
Now, a packer usually removes the first array to save up some space and uses the second to resolve addresses in-place, ie in this exact array.
But why should we rebuild the IAT ? Well, the dump we acquired is actually an image of our program in virtual memory, so the program has
already been executed and the second and unique array contains the addresses, not the function names.
Thus, when our program will look for the function names to retrieve their addresses, it will find addresses and crash.
Hopefully, ImpRec will make it easy for us to fix the IAT. Click IAT AutoSearch, then Get Imports, and finally Fix Dump and
choose the dump. We are done, everything should work fine.