Manually Unpacking a Morphine-Packed DLL with OllyDbg

Tools Required: OllyDbg, Stud_PE, UltraEdit or any suitable hexeditor
Skill Level: Beginner

Unpacking executables in OllyDbg is usually pretty straight-forward, but sometimes, we come across a DLL that is packed, which can affect how we approach the problem. Due to the way OllyDbg uses the loaddll.exe wrapper to analyze DLLs, the DLL's initialization code will run before we hit our startup breakpoint, allowing the code to perform debugger detection or any other nasty tricks before we get a chance to stop it.

This tutorial gives a step-by-step illustrated guide to unpacking a Morphine-packed DLL using OllyDbg. In this case, our target is a piece of malware identified by Kaspersky Anti-Virus as "Trojan-Proxy.Win32.Agent.jz". RDG packer detector tells us that it is packed by Morphine 2.7.

RDG Packer Detector

If we load the file as-is, OllyDbg will detect that it is a DLL file, and prompt us to use LOADDLL.EXE to analyze it.

LOADDLL.EXE

This is not what we want, so we close this out. Before we load this bug into Olly, we are going to make a small change, to make Olly think that our target is a standalone executable instead of a DLL. We do this by using Stud_PE to locate the "Characteristics" field of the PE header. There is a single bit that we want to toggle in the byte at 0x117. We can do this by changing the value 0x21 to 0x01. Save the file, and now we can load it into OllyDbg as if it were an EXE.

Stud_PE Characteristics (DLL)

Stud_PE Characteristics (EXE)

Now when we load the file into Olly, we are taken to the ModuleEntryPoint, and can begin our unpacking.

OllyDbg at ModuleEntryPoint

When a morphine-packed DLL runs, it will unpack the original file and then copy it to memory allocated by VirtualAlloc. All we need to do in order to dump the original file is to interrupt this process and dump the memory before it is loaded and executed. We can do this by finding the VirtualAlloc function (use CTRL-G to go to a memory location by address or by exported name) and setting a breakpoint on it.

Locate VirtualAlloc

Some packers may use anti-debugging tricks or check the first few bytes of the imported functions to insure that they do not have software breakpoints set. In this case however, there are no tricks, and we can simply set our breakpoint at the start of the VirtualAlloc subroutine, and run the code by pressing F9.

Breakpoint at VirtualAlloc

Once we come to the breakpoint, the original code is unpacked and ready to be copied. We can locate the code in memory by going to the OllyDbg memory map window and right-clicking on the first section after the PE header, and selecting "Dump". This opens a window with our dump in "Disassemble" mode. Right-click on the window and choose "Hex->Hex/ASCII (16 Bytes)" and you'll see the hexdump as shown below.

Hexdump of memory

Scroll through the output and find the PE header, starting with the familiar bytes "MZ" followed by the usual "This program must run under Win32" verbage. If this is present, it means our unpack worked, and we can dump the memory by right-clicking on the dump window and selecting "Backup->Save data to file".

Save memory dump to file

At this point all we need to do with the memory dump is delete the bytes preceding our PE header, and truncate the file at the proper length. I usually use Linux for my low-level file manipulation, but since I know most of you reading this tutorial are working on Windows, I'll show the process using the UltraEdit-32 hex editor.

First, open the memory dump file in UltraEdit and locate the MZ bytes indicating the start of the PE header. Note the offset into the file, in this case, 0x4969 hex, in decimal, 18793.

UltraEdit viewing PE header

Go to the start of the file, select the first byte, right-click and choose Edit->Hex Insert/Delete or hit CTRL-D. In the dialog that pops up, choose "Delete" and enter the number of bytes to delete up to the PE header start.

Delete prefix bytes

Now all we have to do is truncate the file at the correct location. (It won't hurt anything in terms of functionality if you skip this step; the file will just be larger than it needs to be.) Save the file in UltraEdit, then open the saved file in Stud_PE. Look at the "Sections" tab, and note the RawSize and RawOffset fields of the last section of the file. Add them together, and that tells you the overall raw size of the original file. In this case, 0x25800 + 0x3800, which equals 0x29000.

Finding the original file length in Stud_PE

Go back to UltraEdit, and select the byte at offset 0x29000. Hit CTRL-D to bring up the delete bytes dialog again, and now enter a sufficient number of bytes to truncate the rest of the file.

Truncating the file in UltraEdit

We now have a copy the original DLL as it was before being packed by Morphine. We can verify its integrity by loading it into Stud_PE and checking that all of the components of the file have sane values and that the import table actually shows imports from various system DLLs, which would not have been shown in its packed state. The export table should now also show any exported functions in the DLL.

Unpacked!


Jan 4, 2006 - Joe Stewart