Unpacking with Windbg

A few weeks ago a friend sent me some packed malware that he was having trouble with. The malware had a number of anti-debugging techniques employed that made it difficult to unpack and my friend was in a desperate rush to create solid host-based indicators for the malware.  After spending about 30 minutes trying to find all the anti-debugging techniques, I decided to try opening it in WinDbg, because most of the anti-debugging techniques were specifically targeting OllyDbg.  OllyDbg is the most popular debugger for unpacking and in our book we devote an entire chapter to unpacking using OllyDbg.  However, in cases like this you can use WinDbg to unpack malware and all the same strategies apply.

The basic steps for unpacking are the same with WinDbg as they are with OllyDbg; you locate the original entry point, dump the process to disk, and repair the import table. For security reasons I can’t show the exact malware in question, but I can demonstrate unpacking with WinDbg using one of the labs from out book.  To demonstrate unpacking with WinDbg, we’ll unpack Lab 18-3 from our book.  In the book we use OllyDbg, but this time we’ll use WinDbg.

The first step is to load the packed program into WinDbg.

ntdll!DbgBreakPoint:
7c90120e cc              int     3

WinDbg stops at the system breakpoint instead of the entry point of the packed program.  We’re not interested in code that runs before the entry point so we set a breakpoint on the entry point and run the program until the breakpoint is hit.

0:000> bp $iment(image00400000)
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=7ffdb000 ecx=0012ffb0 edx=7c90e4f4 esi=00fdf55c edi=7c911440
eip=00405130 esp=0012ffc4 ebp=0012fff0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
0:00> u eip image00400000+0x5130:
00405130 eb06            jmp     image00400000+0x5138 (00405138)
00405132 6877150000      push    1577h
00405137 c3              ret
00405138 9c              pushfd
00405139 60              pushad
0040513a e802000000      call    image00400000+0x5141 (00405141)

Once we hit the entry point of our packed program we’ll use the same strategy that we used with OllyDbg in order to find the original entry point (OEP) of our program.  We step over the pushad instruction and then set a hardware breakpoint on access.  To set a hardware on access breakpoint in WinDbg, we use the command “ba r 4 esp” (if you don’t know why OEP is important or why this strategy works for finding it, see Chapter 18 of our book).  The ba command stands for break on access, the ‘r’ parameter specifies that the breakpoint should be triggered when the address is read.  The ‘4’ parameter specifies the size of the operand that will be read, and esp specifies the address on which to set the breakpoint.

0:000> p
eax=00000000 ebx=7ffdb000 ecx=0012ffb0 edx=7c90e4f4 esi=00fdf55c edi=7c911440
eip=00405138 esp=0012ffc4 ebp=0012fff0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
image00400000+0x5138:
00405138 9c              pushfd
0:000> p
eax=00000000 ebx=7ffdb000 ecx=0012ffb0 edx=7c90e4f4 esi=00fdf55c edi=7c911440
eip=00405139 esp=0012ffc0 ebp=0012fff0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
image00400000+0x5139:
00405139 60              pushad
0:000> ba r 4 esp

After we set the breakpoint we go until the breakpoint is hit.

0:000> g
Breakpoint 1 hit
eax=00000000 ebx=7ffdb000 ecx=0012ffb0 edx=7c90e4f4 esi=00fdf55c edi=7c911440
eip=00407550 esp=0012ffc4 ebp=0012fff0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
image00400000+0x7550:
00407550 50              push    eax
0:000> u eip
image00400000+0x7550:
00407550 50              push    eax
00407551 6877154000      push    offset image00400000+0x1577 (00401577)
00407556 c20400          ret     4

A few instructions away we see the push 0x401577 followed by a ret instruction.  This code is using the ret instruction to transfer execution to a different address far away.  This looks like the tail jump, so let’s step to see where it goes.  When we assemble the code at that location it looks like the entry point for an executable and we can conclude that we’ve located OEP.

0:000> u eip L10
image00400000+0x1577:
00401577 55              push    ebp
00401578 8bec            mov     ebp,esp
0040157a 6aff            push    0FFFFFFFFh
0040157c 68c0404000      push    offset image00400000+0x40c0 (004040c0)
00401581 683c204000      push    offset image00400000+0x203c (0040203c)
00401586 64a100000000    mov     eax,dword ptr fs:[00000000h]
0040158c 50              push    eax
0040158d 64892500000000  mov     dword ptr fs:[0],esp
00401594 83ec10          sub     esp,10h
00401597 53              push    ebx
00401598 56              push    esi
00401599 57              push    edi
0040159a 8965e8          mov     dword ptr [ebp-18h],esp
0040159d ff1530404000    call    dword ptr [image00400000+0x4030 (00404030)]

Now we need dump the file to disk and repair the import table.  Unlike OllyDbg, WinDbg has no built in tools for this, so we’ll use the simple and freely available Import Reconstructor tool.  With our malicious program stopped at OEP, we open Import Reconstructor.  We use the dropbox on the top of the GUI to select the Lab18-03.exe process.  Import Reconstructor contains a built-in process dumping tool, although it is hard to find.  Click on the middle window and select the Advanced Command -> Select code section(s) as shown in the screen shot below.

That brings up a new dialog box that has a button labeled “Full Dump”.  Click that button to create a dump of the file on disk.  Then enter the OEP from our WinDbg analysis (1577) in the OEP field and click “IAT Autosearch”.  This locates the import address table from the original executable.  Then click “Get Imports” to locate the individual imported functions.  To repair the imports in the dumped file click “Fix Dump” and select the filename that you used for the Full Dump command earlier.  Once you select the filename, the file on disk is repaired so that the import table is correct.  At this point you’re done.  The file is unpacked and you can analyze with IDA Pro, strings, or any other static analysis tools.

2 thoughts on “Unpacking with Windbg

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s