PACKERS
In this post I will cover the effects of a simple packer and 2 ways of patching a packed executable - either by unpacking first or in-line patching. I use UPX1.25 since this is an executable compressor and doesn't use advanced protection mechanisms
First, we scan our app with PEiD
In this post I will cover the effects of a simple packer and 2 ways of patching a packed executable - either by unpacking first or in-line patching. I use UPX1.25 since this is an executable compressor and doesn't use advanced protection mechanisms
First, we scan our app with PEiD
Next, we pack our app with UPX. This is a command line utility so we open a DOS box where our app is an type upx <filename.exe>
We notice the file down from 225kb to 91kb and in PEID we see this:
PEBrowse Pro shows that there are only 3 sectons UPX0, UPX1 and .rsrc. The resource section now contains the import directory but for each DLL there are only two imported functions - the others have disappeared.
Note the .rsrc section has retained the original name even though the others have changed. Interestingly this dates back to a bug in the LoadTypeLibEx function in oleaut32.dll in win95 in which the string ".rsrc" was used to find and load the resource section. This created an error if the section was renamed. Although this bug has been fixed it seems most packers do not rename the rsrc seciton for compatibility reasons.
By opening the app in LordPE editor and pressing the compare button we can open an original copy of our app and see the changes made to the headers.
Open the app in Olly. Click OK on the warning which tells you that the executable is probably packed and we land at the entry point.
UPX has compressed our app and appended the code with a stub containing the decompression algorithm. The entry point of this app has been changed to the start of the stub and after the stub has done its job, execution jumps to the original entry point to start our now unpacked program.
The rationale for dealing with this is to let the stub decompress the app in memory and then dump the memory region to a file to get the unpacked copy of the app. However, the app will not run straight away because the dumped file will have its sections aligned to memory page boundaries rather than file alignment values, the entry point still points to the decompression stub and the Import Directory is also wrong.
Note at our entry point in Olly we have Pushad. This stands for push all double and instructs the CPU to store the contents of all the 32 bit registers on the stack staring with EAX and ending with EDI. Following this, the stub does its job and then ends with a POPAD instruction before jumping to the OEP. POPAD copies the contents of the register back from the stack. This means that the stub will have restored everything back the way it was and exited without trace before running the app. Since this method is ideal in this situation, it is common to other simple packers.
From the time of the first PUSHAD instruction, the contents of the stack at that level must remain untouched until accessed by the final POPAD. If we put a hardware breakpoint on the first 4 bytes of the stack at the time of the PUSHAD Olly will break when the same 4 bytes are accessed by the POPAD instruction and we will be right in front of the jump to OEP.
First, press F7 to execute the PUSHAD instruction. Next we place the breakpoint. The ESP register always contains the top of the stack so, rightclick on ESP and select follow in dump - this puts the stack in hexdump window.
Now highlight the DWORD of the stack, rightclick and select breakpoint, hardware on access, DWORD:
Next, run the app by pressing F9 and Olly breaks directly before the jmp to OEP. The OEP shown here ahs ImageBase 400000h added to it so to make it an RVA we subtract it which leaves us with 2ADB4h
If you want to cheat, for some packers simply scroll to the end of the code in the CPU window in Olly and just before all the zero padding starts you will see the POPAD instruction.
Next, we single step once so we are the OEP and dump the app using Ollydump plugin. Just click on plugins, Ollydump and select dump debugged process. In the next box we will deselect fix raw size and rebuild imports to illustrate some points of interest:
Note that OllyDump has already worked out the base address an size of image and has offered to correct the entry point for us. Press dump and save the file.
Unfortunately we see that something is wrong because our file has lost its icon and if we try to run it we get an error.
This is because of the alignment issues mentioned earlier - the filesize has also increased as a result. Open the app in LordPE and look at the sections. The raw offset and the raw size values are wrong. We will have to make the Raw values equal to the virtual values for each section for the app to work. Rightclick the UPX0 section and select edit header.
Now make RawOffset equal VirtualAddress and RawSize equal VirtualSize. Repeat for the other sections, save and exit (this is what fix raw sizes checkbox in Olly means). now the icon has returned and we get a different error when we try to run it. "The application failed to initialize properly." This is because the imports still need rebuilding.
To do this, we use ImpRec. It needs to attach to a running process and also needs the packed file to find imports. Start ImpRec and follow these steps:
1. select basecalc.exe in the box at the top (it should still be running in Olly.)
2. Next enter our OEP (2ADB4) in the appropriate box
3. Press the "IAT AutoSearch" button and click OK on the messagebox
4. Press the "Get Imports" button
5. Press "Show Invalid" - in this case there are none
6. Press "Fix Dump" and select basecalc_dmp.exe in the open dialogbox
7. Exit.
ImpRec will save a fixed copy of our dumped file appended with "_". So run and test it. If we examine the file, we see an extra section named "mackt" - this is where ImpRec puts the new import data.
Since UPX is purely a compressor, it has taken the existing import data and stored it in the resource section without encrypting or damaging it. This is why ImpRec finds all valid imports without resorting to tracing or rebuilding - it has taken the import directory from the packed executable in memory and transferred it to the new section in the unpacked executable.
PEiD now shows Borland Delphi instead of UPX.
These are the steps necessary to unpack an executable packed with a simple compressor. More advanced packers add various protection schemes to this e.g. antidebugging and anti-tampering tricks, encryption of code and IAT, stolen bytes, API redirection etc. which are beyond the scope of this post.
If it is necessary to patch a packed executable, it may be possible to avoid unpacking it first by using a technique called "inline-patching". This involves patching the code at runtime in memory after the decompression stub has done its work and then finally jumping to the OEP to run the app. In other words we wait until the app is unpacked in memory, jump to patching code we have injected, then finally jump back to the OEP.
To illustrate this we will inject code in the packed executable to pop up a messagebox and let us know when the app is unpacked in memory. Clicking OK will then jump to the OEP and the app will run normally.
The first task is to find some free space for our code so open the packed app in the hex editor and look for a suitable "cave". Free space at the end of a section is better as it is less likely to be used by the packer and is extensible by enlarging the section if necessary. You can see how efficient UPX is - there is hardly any free space - but a small cave exists here. Now add the text "Unpacked" and "Now back to OEP" in the ASCII column of the hex editor as shown:
This will mark our spot for the patch in Olly without having to worry about calculating RVAs. Save changes and open the app in Olly. Rightclick in the hex window and select search for binary string. Now enter "Unpacked" and note the VA of the two strings. In the CPU window, right click and select go to expression. Enter the address of the first string and you will see the two strings in hexadecimal form. Olly has not analyzed this properly so it displays nonsense code next to it. Highlight the next free row underneath and press spacebar to assemble the following instructions.
PUSH 0
PUSH 440C30 [address of first string]
PUSH 440C40 [address of second string]
PUSH 0
CALL MessageBoxA
JMP 42ADB4
Make a note of the address of our first PUSH instruction - 440C4E. Our code should look like this
Now rightclick and select copy to executable, selection. In the new window rightclick and select save file etc. If we check in the hexeditor we see that our code has been added.
Finally we need to change the JMP at the end of theUPX stub to go to our code. Find it as shown earlier, double click the JMP instruction to assemble and change the address to 440C4E. Save changes again and run app to test it.
This ends the entire PE File Format Series :-)
No comments:
Post a Comment