Log in

View Full Version : Decompressing and saving UPX compressed section to a file


egg
August 26th, 2002, 12:53
Ive just written my first decrypter (for LameCrypt ), and am now trying to write my first unpacker - UPX seems a good one to start with (im using 1.20) as it has no protections, small decompressor etc. (Yes i know upx.exe has a built in decompress option, but im doing this for learning so that doesnt matter). Ive ripped the decompressor out ok so I can call it and it compiles fine, but im having troubles setting it up at the start -- what should the registers be?

For example, it starts out like this:
pushad ;save registers
mov esi, 0100D000 ;which is the very first address in the disassembly
lea edi, dword ptr [esi+FFFF4000] ;what does this do, and why?
push edi
or ebp, FFFFFFFF ;why?
jmp 01011672
nop (x 6)
:01011672
mov ebx, dword ptr [esi]
sub esi, FFFFFFFC
adc ebx, ebx

.... down to ...
popad
jmp 01006420 ;jump to the (now decompressed) original program

All I want to do (and i'll do it even if it kills me!) is decompress the compressed section and save it to a file. I don't want to rebuild the exe or anything like that, all i want to do is decompress and save the decompressed bit. Can anybody help me on what I should be doing before calling the UPX decompress algorithm?

Any help would be very much appreciated, I really want to learn how to do this but it's going to take about ten years longer without help from you guys!

Cheers,
Egg

DakienDX
August 26th, 2002, 19:59
Hello egg !

I don't really see your problem here. The decompression code works regardless to which value the registers are set at the beging of the decompression procedure (of course ESP=00000003h would be bad )

As you already wrote, ESI is the start of the compressed code. EDI is the address where the decompressed code is written to. These are the only registers which must be set at the start of decompression.

I can't tell you why EBP is set to "-1" before decompression, but to understand that you must also study the compression. Since I doubt that you're planning to do this you should just take it as it is.

If you just want to save the decompressed section to a file you don't even need to take care about the OEP.

egg
August 27th, 2002, 03:56
Ok thanks, it seems Im calling it correctly
But one last problem -- it seems to be decompressing too much, and it then GPF's with a memory read error. Any idea what I should be looking for in regards to how she gets out of the loop/knows when its at the end and can stop decompressing/call the OEP ?

DakienDX
August 27th, 2002, 15:19
Hello egg !

I can only think of two possible reasons for your problem.
You have not copied all the compressed data out of the file. (including appended 00h bytes at the end of the "UPX1" section)
You have to few space in your destination buffer. The data is compressed, so it'll become much bigger when getting uncompressed.
You'll need enough space, so you could take 10x the size of the compressed data or simply execute UPX -l <filename>, take the size shown there and add a few extra bytes.

egg
August 28th, 2002, 05:35
Thanks very much for your help Dakien, nobody else seems able or willing
Ive 99% finished it, it's just this last bit that's strange . And if I can get this working just once with UPX, it'll open the gate for me to attempt other unpackers, so I'm not going to give up on this one!

Im definately reading the compressed section correctly, including 0's at the end, LordPE verified that the section I had taken was the right one, and 100% intact. I'm also allocating a string that is 10 times bigger than the compressed section, so space shouldnt be an issue (especially as it's just notepad.exe compressed from 50k to 28k).

Code:
sPtr = STRPTR(sData) ;sPtr points to sData, the compressed data
sDec = STRPTR(sChunk) ; sDec points to the allocated area to decompress to (just nullchars)
;now set up some registers so that theyre the same as UPX
! xor eax, eax
! mov edx, &hFFFFFFFF
! mov ecx, &h01010101

;now starts the UPX algo ...
! pushad
UnUPX:
! MOV ESI, sPtr ;esi points to sData
! MOV EDI, sDec ;edi points to sChunk
! PUSH EDI
! MOV EBP, &hFFFFFFFF
! JMP LOC_010118C2 ; (i used TMG Ripper to get the algo)
...
... down to ...
...

LOC_010119E8: ';Ref: 010119DF
! CALL DWORD PTR [ESI+&h000011DB0]
LOC_010119EE:
! popad

And then, I write the contents of sChunk to disk (which should now contain the decompressed section). Sounds like flawless theory to me

It compiles fine but crashes with "0x00000000 referenced memory at 0x00000000. The memory could not be 'read'"

Any ideas?

evaluator
August 28th, 2002, 08:09
hello!

>>mov esi, 0100D000 ;which is the very first address in the disassembly
>>lea edi, dword ptr [esi+FFFF4000] ;what does this do, and why?


IF you will do little analyze, you will FIND:
At start ESI used by UPX for keep UPX-packed section address,
then at EDI it calculates unpacked-section start address.
Don't be lazy, debug & understand.

UPX also changes content of code section for relocation purposes.
So dumping directly after unpacking is NOT right idea in 90%.
You must wait, when UPX also finishes relocating in CODE section.
Or unpacked will crash..

egg
August 28th, 2002, 08:43
Quote:
At start ESI used by UPX for keep UPX-packed section address,
then at EDI it calculates unpacked-section start address.

That was obvious from after my first post

Ive done a lot of debugging and analysis, everything looks right so im not too sure whats wrong , that is why I come here for help, it's a last resort but I don't know anybody else anywhere who is capable of helping with this specialist area

evaluator
August 28th, 2002, 08:52
So last step for help you can this:

pack & upload somewhere all files and I will look.

OK?

DakienDX
August 28th, 2002, 09:29
Hello egg !

The part where the code craches doesn't belong to the unpacking code any more, but to the import handling. The call is a call to LoadLibraryA and since your import table will not be at the location the call points to, it will fail.

Since you wrote you just want to decompress the section and not rebuilt the .EXE, you're finished after the plain unpacking. The unpacker will end right after the Loop instruction. If you put you're Popad there and delete the code after it it'll work fine. You don't need to set EAX, ECX, EDX at the start of the unpacker. Their values will be set by the unpacker before they're used.

egg
August 28th, 2002, 09:57
Dakien, THANK YOU! Youve hit the nail on the head -- I had originally ripped the whole thing down to popad, but trimming it down to the loop instruction as you suggested and putting the popad after that worked perfectly -- the decompression worked perfectly and because im no longer running code that didnt need to be executed, im not getting any GPFs.
So, my problem solved, and I can now go on to learn how to unpack other unpackers, hopefully without having to bother you guys
The door is now open!