Download as pdf or txt
Download as pdf or txt
You are on page 1of 23

Beginner Unpacking Tutorials

#1 UPX 2.01w

- Introduction Welcome, to the first part in hopefully a series of tutorials that will try to explain unpacking to beginners. These tutorials assume that you have basic assembly knowledge, know at least the very basics of the PE file format, and OllyDbg knowledge. Basically you just want to know how to analyse a file that has been packed, right ;-) I remember when I still was a beginner, and was literally struggling with some ( minimally customised ) version of UPX. I just didnt get it what was going on, and how I could possibly defeat this without stepping through every instruction until I got some code that actually made sense. I was looking at a maze of ( conditional ) jumps and instructions that didnt seem to make sense at all. Now that I am more experienced ( but still consider myself a beginner ), I want to try and give something back to the community mainly to the beginners who can debug and crack / reverse, but are unexperienced with packers, just like I was a while ago.

I will combine theory ( in a simple way, I wont go too deep into it ) with some practical experience by providing you with executables packed with some packers of increasing difficulty that we are going to tackle in these tutorials. The theory should give you some insight into whats going on and what we need to know, and the packed executables make sure you have some real-world practice example.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

- Theory What is a packer you might ask. Roughly said, a packer is a program that aims to minimise the size of another executable ( basically any valid PE file such as .exes , .dlls etc. ). Compare it to for instance WinZip and WinRar. They compress folders, applications, files to often much smaller filesizes. The only difference between your everyday packer and WinZip for instance, is that WinZip puts all the files into one single archive ( the .zip file ) , and the packer can only compress one single file. There are exceptions to the rule though ;-) Another difference is that generally when you pack a couple of files with WinZip, you will need the WinZip application itself in order to extract all the files from the .zip archive with the exception of self-extracting archives. Executable packers ( PE packers, or just packers in general ) fall into the category of self-extracting packers. They compress a file, but also include a routine that unpacks the file, once its loaded in memory. This routine is called the unpacking stub.

What the packer essentially does, is compress code, data, resources etc. that the target executable is made up of ( through the use of some compression library, a lot of custom ( non-commercial ) packers tend to use the same compression library, cant remember off the top of my head which one, but its not important ;-). The packer will also add code that will de-compress the compressed data/code to its original executable state. This is the unpacking stub that I told you about. This makes sure the application gets decompressed before it is ran :-).

Ill try to explain it a bit more clearly with a couple of simple images on the next page.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Here you have your average, big executable :-)

And here is our good friend, the packer :-)

The packer will try and compress the executable, and also add a bit of code that will unpack the compressed executable at runtime.

As you can see, the total executable ( compressed executable + unpacking stub ) is much smaller than the uncompressed executable. And as strange as it may seem, some packers are that good, that they actually increase the speed of which applications gets loaded! I hope this has explained to you why packers are being used. Mainly for file compression.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

As explained above, the packer will have to attach this unpacking stub to the executable somehow. As far as I understand this correctly myself, the packer will create a new section inside the executable ( read up on the PE file format if you dont know what a section is ), where it will place its unpacking stub. It will then also change the entry point of the application ( the address of the first instruction to be executed once the file is loaded into memory ) to the start of the unpacking stub. So once the application gets loaded, the unpacking stub starts decompressing the executable, and once its done, it will jump to the original beginning of the executable, the so-called Original Entry Point, or OEP. Its called original because this was the entry point before the program was packed.

That should explain the basics of the packer, and the unpacking stub. Hopefully I didnt forget anything.

Now that we know something about out enemy, were going to look at a program that has been packed. In our case, the packer is UPX. UPX is considered to be the most easiest packer to defeat, so thats where well be starting. UPX is created by Markus, Lszl and John ( http://upx.sourceforge.net ). UPX is an open-source packer, which stands for Ultimate Packer for eXecutables. And I must say, it really does what it says on the box ;-)

A compression ratio of 49.11% of the original size , thats not bad! Not bad at all.

We will be analysing a harmless file packed with UPX, and I hope that you will not use this knowledge explained in this tutorial for personal advantages such as illegally obtaining registered copies of commercial programs through breaking their protection and cracking them. If you really like a program, support the author by legally buying it.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

- Whats needed? PEiD 0.94 OllyDbg 1.10 OllyDump plugin AnalyseThis plugin ImpRec 1.6f Unpackme ( unpackme_upx.exe )

- Getting started There is a nifty application made by snaker / Qwerton / Jibz called PEiD. It can identify byte signatures ( specific sequences of bytes ) that get generated by packers. PEiD has a database of signatures of most ( if not nearly all ) packers out there today. And if its still unknown, once can expand the database themselves by making an entry in the database file, entering the byte sequence at the entrypoint of the packed application, and the name of the packer. Run PEiD, and drag the unpackme inside the PEiD window. PEiD will show you this:

PEiD identifies the present packer as UPX 0.89.6 1.02 / 1.05 1.24 . I have packed it with UPX 2.01w actually, so the signature in PEiD will probably have to get updated. This program tells us that we are dealing with a packed executable. Now were going to load the application inside Olly, and see what it looks like.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Right, OllyDbg presents us with this MessageBox.

This message will almost always appear when you are dealing with an application that has been packed. Just click on yes and Olly will try and analyse the code as good as possible for you :-) Heres what youll be looking at

As you can see, alot of ( conditional ) jumps, arithmetic instructions ( add, inc, sub, adc ) and the likes. It deffinately doesnt look like plain code does it?

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Right click somewhere in Olly, and select Search for > All referenced text strings. Olly will spit out the following:

Not a single valid string. Not strange, considering the entire program ( including data such as strings ) have been compressed. We cant analyse what this file may possibly do when its in its packed state can we ;-) ? - Unpacking the application Okay, lets get started then. Im already going to skip something for the second part of this tutorial series. You notice the first instruction to be executed is PUSHAD. This is a very common instruction that is very often one of the first instructions of a packed executable. Im not going to explain what the exact use this instruction has for packers, so just forget about it for now ;-) I will try and explain it as good as possible in the next tutorial. The way were going to tackle this packer, is by simple tracing through the executable, looking for obvious things that could tell us that weve hit the Original Entry Point ( OEP ) and the application is unpacked.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

One thing that I have noticed, is that code has a tendency of flowing downwards, rather than upwards. Were going to use this little trick to our advantage :-)

Again, we start out here:

Start stepping in Olly. Nothing interesting happens until we hit the JMP, and we jump to 1020C62h, a couple of instructions below. Now we end up in a maze of conditional jumps. What Ive discovered is that generally, code tends to flow downwards. Yeah, so what? I hear you say. Well, if we hit a jump that jumps downwards, were ok. If we hit a jump that jumps upwards, something will still have to be done before were allowed to go past this point so to speak. So what do we do? We start stepping until we hit the second conditional jump at 01020C69h. It will jump upwards allright so lets give it a go. A simple method of getting to the point where the jump will not be taken upwards but the code will just skip the jump, is to set a breakpoint below the conditional jump, and hit Run ( F9 ). What will happen is that Olly will freely run and execute instruction by instruction and because this is way faster than stepping through every single instruction manually, waiting untill you hit the conditional jump, only to discover that youre in a loop and will break at the breakpoint when the jump upwards will no longer be taken.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Lets try it :-). Set a breakpoint ( F2 ) on the instruction below the 2nd conditional jump at 1020C69h.

Now hit Run, youll see that Olly breaks at the breakpoint. Right, that didnt look that usefull so far. Trust me, once we hit bigger loops it will be usefull ;-). Keep on stepping until you hit another conditional jump that will jump upwards. Youll find that to be here:

You know what to do :-) Set a breakpoint on the JNZ at 1020CCEh, and hit Run. Keep on stepping again until you hit the next jump that will go upwards, but dont go too fast ;-). Youll find that next situation to be here:

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Ive already commented it :-x , but the instruction below the conditional jump that goes upwards, is an unconditional jump that jumps upwards aswell! Right, the solution for this might be quite logical, but try and follow anyways ;-) If you look at just the JNZ and the JMP at respectively 1020CF4h and 1020CF6h, there is no way how were ever going to get past this point. If the conditional jump gets taken, we jump upwards. In the case that the jump will not be taken, the unconditional jump will jump up anyways! So there has to be another element that takes us past this jump pair. Lets take a look a bit more upwards.

Right, the only jump that takes us past the unconditional jump, is the JBE at 1020CEBh. The easy way out will be to put a breakpoint at where the JBE will jump to when it gets taken. This is at 1020CFCh so lets breakpoint that and hit Run again. You might break on a previous breakpoint aswell, so its a good exercise to remove breakpoints when you dont need them anymore. Good, we break where we wanted to :-). Lets continue Heres the next jump that goes upwards.

Breakpoint the ADD EDI,ECX instruction below, and run. Yup, we break once more... continue. Right below that is an unconditional jump that goes upwards again! Right, the same problem as weve encountered before, so lets take a look for a jump that jumps past this unconditional jump.

Anthracene - 2006

Beginner Unpacking Tutorials Ive found that jump to be quite a bit upwards, here it is:

#1 UPX 2.01w

As you can see, it jumps to 1020D12h, so set a breakpoint there, and hit Run and continue stepping. Heres where youll end up then:

The JA will jump upwards, but the JNZ below will jump upwards aswell but only if the jump will actually get taken. So lets save us a little time and just set a breakpoint below the JNZ, and hit Run. Good, the breakpoint breaks again, continue stepping again. Damn! Im getting quite sick of this already, arent you yet? ;-) Heres another loop:

We dont have to worry about the JE below it, it jumps downwards :-). Set a Breakpoint below the LOOPD instruction and hit Run. Good, we break. Continue stepping downwards, well hit our first call! Wohooo :-P

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

The call is a call to LoadLibrary here the unpacking stub will load needed libraries for the executable.

Look closely if you will :-). The call to LoadLibrary takes one parameter that gets pushed on the stack. Thatll be the PUSH EAX a couple of instructions above the call. So in EAX we can see the library thats about to be loaded. The JE below will form a loop, that will decide whether more libraries will get loaded ( the jump gets taken ), or that all the needed libraries have been loaded. So set a breakpoint below the JE and hit run. Ive taken a little peek for you, but it seemed that the JE didnt get taken so there probably is another jump that decides whether we jump up a little ( and load more libraries ) or not. Start stepping again till you hit the next jump. That should be here:

Its unconditional so were going to have to find a jump that jumps past this. If you want, you can keep on stepping this piece of code with F8 some interesting things will be shown to you if you take a close look at the code in Olly and the registers ;-) Right, the jump were looking for is the JE right above the JMP :-) , so breakpoint where its jumping to, and hit run.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Hehe :-) this is unexpecting, the program ran! So what does this mean? We were actually fooled by this jump :-D. There has to be another jumplets search for it. Close the application and restart it in Olly. Check the last image to see where you were so you dont have to step through everything again ;-). Here is the good jump we were looking for:

So set a breakpoint on the instruction where the jump jumps to, and hit Run. Good, we break.

After some more stepping ( and finally no more conditional jumps ;-) youll end up at a pair of calls ( just step over them with F8 ) and youll end up here:

Sick and tired of it yet? I nearly am ;-) , but luckily were nearly there. Hang on. Right, this one is simple again, just set a breakpoint below the JNZ, and run. The breakpoint breaks. Keep tracing until you hit the JMP 1012475. After executing that instruction, youll end up here:

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

I have to apologise for the very bad example though, but the unpacking stub is done now, and has jumped to the OEP. Normally, youd very clearly see when youve hit the OEP. Please refer to my other document for a couple of guidelines to see whether youve hit the OEP or not. Ill include another application packed with UPX for you ( test_upx.exe ), where youll see the difference more clearly. ( Hint: After youve hit that final unconditional jump, youll see calls to GetVersion, and GetCommandLineA indicating youve hit the entrypoint of a program compiled with visual studio 6 there are some other indications as explained in the document). - Dumping the application from memory to disk Back on track though. We now have an uncompressed ( unpacked ) copy of the application in memory. What we do is dump this application from memory to disk. Now why would we do that? When we dump the application once its unpacked, we have an on-disk copy of the unpacked program that we now have in memory! That means weve reached our goal. Now, how do we perform this dump ? There is a usefull Olly plugin called OllyDump by Gigapede. Im assuming that you already know where to find this, and have this plugin loaded. When youre at the OEP, click on the Plugins menu, and select OllyDump > Dump debugged process. Youll be confronted with the following window:

Right, more stuff Im going to have to explain :-).

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

For starters, remember that all you need to do now is fill in the new entry point of the unpacked application in memory ( which is where were at now, at 01012475h, but we need it as RVA this calculation is as simple as Virtual Address Imagebase. So thats 01012475h 01000000 = 12475h. ) And dont forget to untick the Rebuild import box in the bottom of the window. Ill explain why in a bit. Click the Dump button after youve filled in the OEP and unticked the box, and enter a filename to dump the file ,thats currently in memory, to. Now try to run the dumped file, youll see that it will crash even before it has started :-( - Rebuilding the IAT Now why would this happen? Ok ok, Ive wasted your time long enough :-P Ill tell you. Its because the application cant find any of its needed imports. The packer probably compressed the import table ( or at least has done something to it ) , and now the dumped file does not have a valid import address table ( IAT ) , so it any attempts to call any windows API function will fail and probably make the application crash. If Im going too fast here, an import is a function that is being used from an external program ( mostly .dlls ). A good example of this is for instance kernel32.dll. Kernel32.dll exports a function, for instance GetProcAddress. When a program wants to use GetProcAddress, it will have to import this function. If you want to know more about the IAT, read up on the PE file format :-).

So, our goal is clear here, we have to fix the IAT somehow. Inside the PE Header is a pointer to the IAT. Olly is a fabulous debugger, allowing us to view each and single member of the PE header. Click on the blue [ M ] button in Olly, that opens the Memory Map.

Then youll be confronted with a window that shows all the modules that have been loaded into the applications address space. Olly has nicely divided them all into sections, and it also identified the PE header for each module for us.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

What were looking for is the PE header of our application. Ive marked it for you, double click on it.

Well then see the DOS header we have been looking for.

Its not really that visible here, but if you know the PE file format, youll know that inside the DOS header is a pointer to the PE header. Just scroll down, youll see it ;-).

There it is, according to this, the PE header is at F0h. Now we scroll down to the PE header. Ive already marked what we are looking for on the next page, you can see that the PE header really starts at F0h.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

The import table address is a pointer to the IAT. So at 010277F8h should be our IAT. Close the Memory window and press CTRL + G in Olly. Enter 010277F8h and hit enter. Youll end up here:

Looks nice and structured to me :-), but is this really code and not data? We cant analyse this, because its outside of the code segment. Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Thats what well be using the AnalyseThis plugin for. Right click any of the code, and select Analyse This. Right ;-) We get a totally different picture now:

Even more things to explain ;-). You see all the IMAGE_IMPORT_DESCRIPTOR structures? Well, for each .dll that this program imports functions from, there is an IMAGE_IMPORT_DESCRIPTOR structure. You dont need to know what all the members in the struct are for, but what you do need to know is that there is an additional structure filled with all zeroes you can see that in the image. So this program imports functions from 7 .dlls, minus one! Remember, one was filled with all zeroes, so it imports functions from 6 .dlls. If you scroll down a little, you can see all the .dll names and functions that get imported.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Right, youll have to forgive me, but Ive already forgotten what actually is going on here :-( What you have to remember though, that once youve unpacked and dumped a program, its imports are not correct anymore, and will have to get fixed. You can do this manually, but MackT / uCF created a very nice application for this, called ImpRec.

What this program essentially does is fix the IAT for you, so youll have a working dump. Right, lets cut the cr*p and give it a go :-) , Ive been awake for far too long.

I assume you still have Olly running while at the OEP of the unpacked program dont forget that. In the drop-down box in Imprec called Attach to an active process, select the process youve loaded in Olly. Then in the bottom right corner, in the OEP box, enter the OEP of the unpacked program. You can check this in Olly, its 12475h remember? Fill it in, and hit IAT AutoSearch.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

You will see that ImpRec has found something:

It thinks the IAT is at 1000h. Click on OK. Youll see that ImpRec has filled in some information:

Now all you need to do is click on Get Imports, and ImpRec will try and see if there really are valid imports at 1000h untill 1228h ( start at 1000h, size 228h ).

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Well, it seems that ImpRec has found imports from 6.dlls, just as I told you before. And it appears they are all valid aswell. To make sure, click on Show Invalid. You will see nothing happens so dont worry about that for now ;-). Now click on Fix Dump, and point ImpRec to the file that youve dumped from Ollys memory. Try to run the file now youll see that ImpRec appended an underscore to the filename.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

Wooohoooo, it runs :-D. It seems that ImpRec did its job correctly. If you want to check, you saw that ImpRec found an IAT at 1000h, go to Olly and in the dump window, go to 01001000h. Youll see some pointers to API functions in the dump, separated by zeroes when the functions are from a different .dll.

Now youll have to excuse me again for the bad example, but I dont know what exactly is wrong here either :-(. If you load the unpacked and fixed dump in Olly, youll still see that there still are no valid strings! If you look at a calc.exe that hasnt been packed before though youll see that it looks the same, so I guess this has nothing to do with the program not fully being decompressed. This is what the uncompressed program actually looks like, I guess.

- Conclusion Right, what have we ( hopefully :-x ) learned: 1. 2. 3. 4. 5. What a packer is, and what it does How we can identify if a program is packed How we can unpack a very simple packer like UPX Why the dumped file will crash when we run it What we have to do to fix this by using ImpRec

In short, what we have done is this: We determined what packer we were dealing with. When you get more experienced, youll get to know more packers, and when you identify one, youll already know how to deal with specific packers. Then we had to figure out a way how we could know that we were at the OEP, and the program was unpacked in memory. For starters, we used a bit of logic and simple tracing for this. Once were at the OEP and the program was unpacked, we had to dump the program from memory to disk. Then we had to rebuild the import table with ImpRec because the packer had messed with the IAT.

Anthracene - 2006

Beginner Unpacking Tutorials

#1 UPX 2.01w

I could have expanded this tutorial about 10 pages more, but 23 pages just dealing with UPX and rebuilding the imports are enough I think :-P.

In my next tutorial, I will show you an easier way to unpack programs that have been packed with UPX ;-) until then, keep practicing until you get the hang of it. If you want, you can try the other program that Ive included aswell and see if you can unpack that aswell its the same UPX ;-). Untill then, happy unpacking and good luck. Take care of yourselves.

- Credits and thanks Myself ( writing this tutorial, aiming at giving something back to the beginners out there ) ARTeam ( basically everyone posting there and sharing knowledge ) Oleh Yuschuk ( for the best, and also non-commercial, usermode debugger out there ) Snaker, Qwerton, Jibz ( PEiD ) Gigapede ( OllyDump plugin ) Joe Stewart ( AnalyseThis plugin ) MackT/uCF ( ImpRec )

Anthracene - 2006

You might also like