unpacking unpackme2 by ellvis
TRANSCRIPT
1
UnpackingUnpackMe2byEllvis
A tutorial by Saduff
In this paper, I’m going to show you my “crazy” method of unpacking this UnpackMe. I did not dig
too deep into this, so I’m not surprised if there are better solutions. Still, this method worked for me
and it’s pretty “decent” I think, so enjoy. :D
Contents
1) Preliminary study of the target ........................................................................................................... 2
2) Unpacking the UnpackMe ................................................................................................................... 2
Finding OEP.......................................................................................................................................... 2
Restoring OEP ...................................................................................................................................... 3
Dumping the target with fixed OEP ..................................................................................................... 4
Fixing the Import Table ....................................................................................................................... 5
“Cleaning” the dump with LordPE ....................................................................................................... 5
Testing the dump ................................................................................................................................ 5
Finding the cause of the problem ....................................................................................................... 5
The more „elegant“ solution ............................................................................................................... 7
Manually creating a TLSTable .............................................................................................................. 7
Creating a TLS Callback ........................................................................................................................ 7
Testing the final unpacked executable ................................................................................................ 8
Conclusion ........................................................................................................................................... 8
2
1) Preliminary study of the target
So, before we do anything else, let’s scan the target with PEiD:
So PEiD confirms it is packed with UPX. Also have a look at the EP section’s name. That’s all we need
to know. Now let’s unpack it.
2) Unpacking the UnpackMe
Finding OEP
So, open the UnpackMe in Olly and you’ll see a standard UPX stub for VB6. As always with UPX, the
quickest way to find OEP is to simply scroll down until the jump to OEP (the last jump before 0 bytes).
You could also use the ‘standard’ methods of unpacking like the ESP trick, or simply tracing your way
to OEP. So set a breakpoint on the jump to OEP and follow the jump to get to OEP:
3
But where does this jump lead to? Directly to the jump to MSVBVM60.ThunRTMain. That’s definitely
not a valid VB6 OEP. So what’s going on here? Stolen bytes/commands are what this is. Some
commands have been “stolen” from the OEP and are executed in the packer’s stub before the jump
to OEP. A valid VB6 EP looks like this:
PUSH XXXXXXXX
CALL <JMP.&MSVBVM60.ThunRTMain>
So to properly unpack, that’s how the unpacked file’s EP should look like. Let’s start fixing the OEP.
Restoring OEP
Before the jump to OEP, we can see that 2 instructions are executed that are not part of the UPX
stub:
PUSH 004011FE
MOV DWORD PTR DS:[ESP+4],00401400
The first PUSH could be the missing push from the OEP, but then what is the 2nd
instruction for?
Actually, the first push is not necessary at all. It’s there only to balance the stack, since there is no
call. A call would push the return address to stack. So that means the OEP should look like this:
PUSH 00401400
CALL 004011EE
I hope you understand why the OEP should look like this.
4
Dumping the target with fixed OEP
So, now that we know how the OEP should look like, we need to find some free bytes where to write
it. This is where we’re going to write the fixed OEP:
This is where you should be after following the jump to OEP from the UPX stub. So write the fixed
OEP there and then right click on the push and select “New origin here” (so that the OllyDump plugin
will automatically fill in the OEP). When that is done dump the target with “Rebuild Import”
unchecked. Here’s how the fixed OEP should look like:
5
Fixing the Import Table
Now it’s time to fix the Import Table. I’m using Scylla to do that. If you’re on Windows 7, you should
be using Scylla too. Scylla should find all imports without any problems, so I will not discuss this
further.
“Cleaning” the dump with LordPE
Now load the dump into LordPE’s PE Editor. First click on “Sections” and then wipe the “UPX1”
section header. Now close the section table and change “BaseofCode” from 00006000 to 00001000.
We wipe the “UPX1” section, because it is no longer needed, since it contains only packer’s code.
“BaseOfCode” means the RVA of the beginning of the code section. After you’ve done this, save the
file and rebuild it with LordPE’s PE Rebuilder.
Testing the dump
Now the UnpackMe should be unpacked. All that remains is to test it, so run it and see what
happens. If you did everything correctly so far, then the dump should run fine! But wait… where is
the window? We must have missed something, because when running the UnpackMe, a window is
displayed. So let’s go back into the UPX stub and see what we missed.
Finding the cause of the problem
You can skip the part of the UPX stub where stuff gets unpacked and the IAT gets restored, so we
land here:
6
At that point, the target is unpacked. We can skip the VirtualProtect calls, as they are not important.
So that leaves us with this code:
MOV EAX,FS:[18]
MOV EAX,[EAX+30]
MOV DWORD PTR [EAX+2],1
The segment register FS is used to access the Thread Information Block (TIB), which is a data
structure that stores info about the currently running thread. FS:[18] points to the linear address of
TIB. Now that the address of TIB is in EAX, [EAX+30] or FS:[30] is moved into EAX, which contains the
linear address of the Process Environment Block (PEB). By looking at the PEB structure on MSDN, it
seems that the next line of code moves 1 into “BeingDebugged”, though I’m not so sure about that,
because “BeingDebugged” is a byte, but the instruction overwrites a dword. 1 = debugged, 0 = not
debugged. After some trial and error, I found out that these 3 lines of code must be executed for the
window to be displayed. And it must be 1 and not 0. 0 does not work, only 1 works. I did not dig
deeper into this to find out why exactly the window does not get displayed when 1 is not written to
that address in the PEB, I just know that it must be done. You could assemble these instructions
before the EP and it would work, although you would need to find another location for the EP (not
enough space there, target will crash when you write these instructions there), but let’s try a more
“elegant” solution.
7
The more „elegant“ solution
This more “elegant” solution I’m talking about relies on the fact that code gets executed before the
entry point. We could write a DLL and as the Windows Loader loads the DLL, we can execute code
before the EP of the main program is reached, but there is another way – using Thread Local Storage
(TLS) callbacks.
Manually creating a TLSTable
Before we can create any callbacks, we must create a TLSTable. We will use LordPE and Olly to do
that. First we must find some empty space in the target. VA 00401500 will do just fine. Now open the
dump in LordPE’s PE Editor and click on “Directories”. There you will see a “TlsTable” entry. Fill in the
RVA with 00001500 and Size with 00000018. Now save and close LordPE. Now reopen the dump with
the PE Editor (yes, you have to save and then reopen, otherwise it will not work), click on
“Directories” and then click on the “…” button next to the “TlsTable” entry. Here we need to fix the
“IndexVariableVA” and “CallBackTableVA” value, the rest is not important. Fill in “CallBackTableVA”
with TlsTable VA + Size (= 00401518) and “IndexVariableVA” with CallBackTableVA + 8 (= 00401520).
Now save and close LordPE and we should have a working TLSTable.
Creating a TLS Callback
Now that we have a working TLSTable, we can create a TLS callback. So open Olly and go to
“CallBackTableVA” (00401518). We will create our TLS callback at IndexVariableVA + 8 (= 00401528),
so when you’re at “CallBackTableVA”, assemble “dd 00401528” (pointer to TLS callback) there. Now
go to 00401528, which is where we will create the actual code. Assemble the following code there:
PUSH EBP
MOV EBP,ESP
MOV EAX,FS:[18]
MOV EAX,[EAX+30]
MOV DWORD PTR [EAX+2],1
LEAVE
RET 0C
When that’s done, copy the changes to executable.
8
Testing the final unpacked executable
Now let’s test if it works, so run it. If you did everything correctly, the executable should run fine and
the window should be displayed. Congratulations, the UnpackMe is unpacked! ☺
Conclusion
It’s not always so simple to unpack. Sometimes you need to trace the packer’s stub. Anyway, I hope
you learned something from this tutorial. That’s it, see you in another tutorial! ;)