corrected version
prehistory:
Acid_Burn sent me a file,which was packed with UPX.Can't remember the
version right now.It was very interesting stuff, and at the first i wasn't
able to unpack it(although it is not that hard as i found out later), i
admit.Well some days after that i located the newer version of UPX 0.82.I
downloaded the file and studied the docs.I found out that it is a beta
version and could have some bugs in it.I have to admit that i did not encounter
any misbehaviour of the program.To understand the program better i coded
my own test program,which only consited of a MessageBox (explained later).Then
i ran upx on it and began to debug it.And at this point starts the tut
(although i include the test program source code too.hehe).
tutorial:
First question is what do i need in order to follow the tut.The
Answer is: you will need:
first approach / the aim is to get a dumped,unpacked file |
First we going to code our little test program:
this was the source-code i used:
.386P
jumps locals Model Flat, Stdcall extrn ExitProcess :proc
.Data
.Code
mov [_flag],00
push 0
_reg:
_exit:
End Start
|
save the file (i used upx1.asm) and compile it with the help of a batch
file
tasm32 /mx /m3 /z /q upx1
tlink32 -x /Tpe /aa /c upx1,upx1,, import32.lib del *.obj del *.map |
you should have now a running pe-file.Use procdump to change the section
characteristics to E0000060 (apply it to all three sections UPX0,UPX1 and
UPX2,to be sure).Which means that the file is executable,and contains code
and data.If you don't do that symbol loader won't break.
Now use symbol loader and trace through your file.You will see it is
pretty small.
Now it is time to run upx on it,so to pack the whole thing.Use this
parameters: upx.exe -7 upx1.exe.Upx will wrap your file like a virus (hehe
kind of ).Load your file into symbol and once f10 and you will see the
following code:
:004050A0 60
pushad
:004050A1 BE00504000 mov esi, 00405000 :004050A6 8DBE00C0FFFF lea edi, dword ptr [esi+FFFFC000] :004050AC 57 push edi :004050AD 83CDFF or ebp, FFFFFFFF :004050B0 EB10 jmp 004050C2 |
What we see here is following:
pushad pushes all registers on the stack.Next one moves 00405000 (which
is entrypoint -80h) into esi.So what kind of code is this between 00405000
and 00405080?I looked it up in the hexeditor and found out that it countains
the importtable, the strings i used in may prog (upx1).So there is no need
for it yet.000405000+FFFFC000= 00401000, and that is the dword which is
moved into edi.If you have investigated your own prog (as i told you before),you
would see that this is the original entry point,of our file. (sure it can
be different due to preffered imagebases ;)).And that's also the memory
location,where the unpacker routine starts writing our packed (unpacked)
code to.So the jump only overjumps some nop instructions and enters the
unpacking routine.Next thing i often do, is to look at the unpacking routine,
how it unpacks my code.(Don't know why,so don't blame on me :)).bpm 00401000
w is the right breakpoint.After pressing f5 you will enter a loop (a sub
loop indeed),the unpacking loop (heh).With an enabled data window you can
follow how code is unpacked and wrote to the memory location while pressing
f10.As i said,you are in a sub loop.So it will take you a while to exit
all these loops (ca. 7 min).So i tell you the next important instruction.it
is 004051B4.lea eax,[esi+eax+00005000] loads the import table into eax.So
now we are just a min away from entring our unpacked program.So be careful.Step
with f10 till you reach 0040521D.You see what it is?
jmp 00401000.(If your code is different to mine,then load the exe with
symbol loader and search for jmp 00401000,should be around 0040521D)
Nice isn't it?
so now we wanna enter an infinite loop to dump the prog then.Type 'a
eip' and then 'jmp eip' and one more time press enter.Okay now exit softice
(f5,g or whatever).Open up procdump, in the task channel you will find
upx1.exe.Right click and select dump(full).Now open your new dumped file
with the pe-editor and change the entry point to 00001000.Fixed and ready
to run.Try!
Now you can apply your patches to it.Shouldn't be hard.If you can't
solve it, then i can't imagine that you understand what i explained till
now ;)
second approach / the aim is to insert our own code into the packed file (code redirection) |
I think it would be better to explain the theory first.I have to say,
that this part of the tut is not for beginners!
So whats code-redirection?
For me and a lot of other guys in the scene code-redirection means
to insert our own code "into" the unpacking routine, so that the program
on its own execute our inserted code,which patches the exe.I have to admit,that
i've done it a little more complicated.I found that out later on...
What we need first is some space,which will be used to insert our code.So
open the file and look for 00 00 00 00....a lot of them.For me a good place
was 00405230.Plenty of 00's.Now we have the space, next we must redirect
some code of the unpacking routine ,so that it jumps to our inserted code(will
be inserted in 00405230 of course).
#Explaination: we want the unpacking routine to unpack the file first,and
then we jump to our code and patch the file in memory.#I made a mistake,which
made the whole thing a little bit more complicated.But i thought why not
doing something more complicated,some more brainstorming :).The mistake
happened while using hview and looking at the real entry point of
the prog at 0040521d.Hview did not show jmp 00401000 (real entry point)
but something else.Therefore i thought the unpacking routine calculates
the real entry point first,and the overwrites 0040521d. (hope you can follow
me).Therefore it would be senseless to change 0040521d jmp 004ffbc0 (thats
what hview showed) into jmp 00405230, because it would get overwritten
anyway.Therfore i searched for a fix jump, i found it quite on the beginning
at:
:004050A0 60
pushad
:004050A1 BE00504000 mov esi, 00405000 :004050A6 8DBE00C0FFFF lea edi, dword ptr [esi+FFFFC000] :004050AC 57 push edi :004050AD 83CDFF or ebp, FFFFFFFF :004050B0 EB10 jmp 004050C2 -->here |
you remember that jump,don't you? I found that jump in hview too,and
therefore it changed it to jmp 00405230.Some of will now scream, because
that would change the following code,but upx has a nice feature:after that
jump are a bunch of nops.So that makes it easy to change.the opcodes for
jmp 00405230 are : E9BFB1BFFF Apply
those changings with the help of hview.Imgagine stepping with softice (or
step,and make temporary changes) through that code reaching 004050B0 and
jumping too 00405230.Yes you are right, there is nothing (at the moment),only
some mov [eax],al which signalise our 0000's.
So next thing we need to do is change that 0040521D
jmp 00401000 into jmp 00405260.You ask why? Well after unpacking
it wants to jump to the real program,but we have to run our patch first,therfore
we don't jump to 00401000 but to 00405260 (where we will add our patch).
Changing that jump into jmp 00405260 looks
like this:
jmp 00405260 in opcodes are :
EB41
But at 00405260 does not stand something like
EB43 so that we can overwrite it,no some more bytes we find there something
like EB43FF32BC so we gonna patch with EB41000000
to
fully overwrite that.
In asm that overwriting routine at 00405230 looks
like following:
00405230 66C7051D524000EB41
mov word ptr[0040521d], 41EB
00405239 66C7051F5240000000 mov word ptr[0040521f], 0000 00405242 C6052152400000 mov byte ptr[00405221], 00 00405249 E974FEFFFF jmp 004050C2 |
okay i hope you understand the first three lines (remember the reversed
order of the first line), if not,they patch the jmp 0040100 to jmp 00405260.The
last line jumps to 00405242.Scroll up a bit to the yellow table.00405242
is the beginning of the unpacking routine.
Summary what has been done so far:
We patched an jmp from jmp 00405242 to jmp 00405230
We inserted our first code routine, which pacthes the jump to the real
prog from 00401000 to 00405260
Imagine the running program: It starts;jumps to our fisrt routine;patches
the jump; jumps back to unpacking routine;finally reaches the jump at 0040521d
jumps to 00405260; and now?
Now we add the second routine,which patches the prog in memory:
thats pretty easy, because the prog we coded,can be beaten be changing
a jnz into a jz.(It is only a demo,remember?)
We reach 00405260: inserting:
00405260 C6051210400074
mov byte ptr[00401012],74
00405267 E974FEFFFF jmp 00401000 |
fisrt line patches the jnz into a jz and the second line jmps to the real prog now.You now have a running packed/unpacked but that's the point you have a patched file.
After making it temporary with softice, take the opcodes i marked in blue and insert all needed stuff into the file,with the help of hview.Now it is static!
Greetings and thanks goto:
Volatility
Lord Soth
Lucifer 48
Tornado
Acid_Burn
Risc
Pain
ytc_
LaZaRuS
RevX
knotty
Warezpup
...........and all i forgot :( sorry