Log in

View Full Version : manual unpacking.. and i mean manual :)


Kr0n0
August 9th, 2002, 23:29
hello fellow reversers
i was trying to reverse a prog, but it showed me that i was not good enought to reverse it, so i learnt about PE file structure, still it kicked me, so i decided to learn about unpacking and decrypting.
my first victim was good old UPX 1.20w, i packed notepad and decided to unpack it WITHOUT generic unpackers neither "upx -d" switch neither in Procdump,
i searched the web(blah blah blah fire up procdump dump it and fix EOP) and the forum(use procdump or -d)

my idea of manual unpacking, is with softice(debugger , icedump(dump sections), hexeditor(assemble all stuff). because this is how one learns!
IMO i think a reverser should dump/decrypt manually a protection at least once. and hexassemble it at least once in a lifetime

i'll paste here my walktrough (i wrote this stuff like a tutorial, personal notes... so don't pay attention , please correct me if something is incorrect

ps: i got all the packers+cryptors on protools, and i wanted to know IYO what packers(cryptors go last should i go for next, i'm doing a progression that's why i started with UPX (the easiest

ps2: about import rebuild.. for the ".import_section" work does it have to be exacly like the original, or can the order of the imported functions be another(being a correct one, corresponding to true values)

ps3: i read a thread about UPX+NT, that i don't remember exactly, but does UPX fux0res the ".relocations_section". if not htf do i restore the old .reloc

ps4: how can i merge resources from the packed .EXE with the .resources it unpacked. i tried to grab the resources from packed.exe(icon+version_info), but it said "i'm too stupid i can't recognised the reloc section, even thought it is there"













;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UPX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

tools needed: softice, icedump, frogice, ultraedit32(or other nice hexeditor), PE knowledge, lots of girls (i'm hopping you don't need a tutorial on what to do with them
compact notepad.exe using default options with UPX 1.20w

size optional header - 0xE0
size of code - 0x4000
size of data - 0x1000
base of code - 0xb000
base of data - 0xf000
section alignment - 0x1000
file alignment - 0x200
EP(entry point) - RVA 0xe8f0
IMAGE_DIRECTORY_ENTRY_IMPORT: - RVA 0xfc14 ; - size 0x170. file offset - 0x4a14

upx0
{
virtual size - 0xa000
virtual address - 0x1000
size raw data - 0x0
pointer raw data - 0x200
}
upx1
{
virtual size - 0x4000
virtual address - 0xb000
size raw data - 0x3c00
pointer raw data - 0x200
}
.rsrc
{
virtual size - 0x1000
virtual address - 0xf000
size raw data - 0xe00
pointer raw data - 0x3e00
}


018F:0040E9C2 5E POP ESI <- finished unpacking itself... or so it seems
018F:0040E9C3 89F7 MOV EDI,ESI
018F:0040E9C5 B9DE000000 MOV ECX,000000DE
018F:0040E9CA 8A07 MOV AL,[EDI]
018F:0040E9CC 47 INC EDI
018F:0040E9CD 2CE8 SUB AL,E8
018F:0040E9CF 3C01 CMP AL,01 <- but if you look carefully, you notice the LOOP at :0040E9F4, it's playing with the .text
018F:0040E9D1 77F7 JA 0040E9CA
018F:0040E9D3 803F05 CMP BYTE PTR [EDI],05
018F:0040E9D6 75F2 JNZ 0040E9CA
018F:0040E9D8 8B07 MOV EAX,[EDI]
018F:0040E9DA 8A5F04 MOV BL,[EDI+04]
018F:0040E9DD 66C1E808 SHR AX,08
018F:0040E9E1 C1C010 ROL EAX,10
018F:0040E9E4 86C4 XCHG AL,AH
018F:0040E9E6 29F8 SUB EAX,EDI
018F:0040E9E8 80EBE8 SUB BL,E8
018F:0040E9EB 01F0 ADD EAX,ESI
018F:0040E9ED 8907 MOV [EDI],EAX
018F:0040E9EF 83C705 ADD EDI,05
018F:0040E9F2 89D8 MOV EAX,EBX
018F:0040E9F4 E2D9 LOOP 0040E9CF <- don't know HTF this LOOP worked!? but it's used to do some rearrangements on the .text
018F:0040E9F6 8DBE00C00000 LEA EDI,[ESI+0000C000]
018F:0040E9FC 8B07 MOV EAX,[EDI] <- :d edi, to check out imported functions, and just below the PE header
018F:0040E9FE 09C0 OR EAX,EAX this is the right place to dump
018F:0040EA00 743C JZ 0040EA3E <- as it finished all imported functions from all DLLs ???
018F:0040EA02 8B5F04 MOV EBX,[EDI+04]
018F:0040EA05 8D843014EC0000 LEA EAX,[ESI+EAX+0000EC14]
018F:0040EA0C 01F3 ADD EBX,ESI
018F:0040EA0E 50 PUSH EAX
018F:0040EA0F 83C708 ADD EDI,08
018F:0040EA12 FF96A0EC0000 CALL [ESI+0000ECA0] <- LoadLibraryA
018F:0040EA18 95 XCHG EAX,EBP
018F:0040EA19 8A07 MOV AL,[EDI]
018F:0040EA1B 47 INC EDI
018F:0040EA1C 08C0 OR AL,AL
018F:0040EA1E 74DC JZ 0040E9FC <- if AL == 0, pass to next DLL
018F:0040EA20 89F9 MOV ECX,EDI
018F:0040EA22 57 PUSH EDI
018F:0040EA23 48 DEC EAX
018F:0040EA24 F2AE REPNZ SCASB <- advances EDI pointer to next imported function
018F:0040EA26 55 PUSH EBP
018F:0040EA27 FF96A4EC0000 CALL [ESI+0000ECA4] <- GetProcAddress
018F:0040EA2D 09C0 OR EAX,EAX
018F:0040EA2F 7407 JZ 0040EA38 <- if ZERO... error
018F:0040EA31 8903 MOV [EBX],EAX
018F:0040EA33 83C304 ADD EBX,04
018F:0040EA36 EBE1 JMP 0040EA19
018F:0040EA38 FF96A8EC0000 CALL [ESI+0000ECA8] <- ExitProcess
018F:0040EA3E 61 POPAD
018F:0040EA3F E98826FFFF JMP 004010CC <- EntryPoint of unpacked EXE
(look at memory contexts... we're at 0040EA3F and JMP to 004010CC; besides remember when we dumped the .text



:/dump 401000 3e9c c:\_text.PE <- OK!
:/dump 405000 084c c:\_data.PE <- OK!
:/dump 406000 0de8 c:\_idata.PE <- NOT OK! we have to rebuild this!!! it's the import data [**]
:/dump 407000 4fb8 c:\_rscr.PE <- NOT OK! this one is messed up! [***]
:/dump 40c000 0a9c c:\_reloc.PE <- NOT OK! it was only 0x0!! how do we rebuild this? [****]
:/dump 40d000 7e0 c:\_import.PE <- NOT OK! imported functions names [**]
:/dump 40d7e4 1260 c:\_header.PE <- OK!
:/dump 40f000 1000 c:\_UPXrscr.PE <- .rscr that UPX didn't unpack [***]
:/dump 4062e0 240 c:\_IAT.PE <- IAT, Import Address Table [**]


-> get yourself a good hex editor, i use UltraEdit32
make a copy of packedpad.exe
paste the _pehead.PE over packedpad.exe
since file aligment is 0x1000, you have to fill it with 0x0 to file offset 0xfff
now it's time to paste the sections, the first one it's .text, check it's 'PointerToRawData', it points to 0x1000, so we paste the _text.PE at 0x1000 (remember 'PointerToRawData' is at 'start_of_section_header' + 0x14)
after that we have to do file padding, filling it with 0x0, until file offset 0x4fff
looking at PE header again we see .data, and 'PointerToRawData' is 0x5000... what a surprise , paste _data.PE at 0x5000
fill it up with 0x0 to file offset 0x5fff
paste the rebuilt .idata at 0x6000 and do file alignment
fixed _rscr.PE is to be pasted at 0x7000, file align it
last one is fixed _reloc.PE at 0xc000

Kr0n0
August 9th, 2002, 23:29
[**] rebuilding the .idata
(for now i just copied it from good old notepad.exe)
so we will have 7 IMAGE_IMPORT_DESCRIPTORs, one for each .DLL and one more that is NULL -> KERNEL32.DLL ADVAPI32.dll comdlg32.dll GDI32.dll SHELL32.dll USER32.dll
IMAGE_IMPORT_DESCRIPTOR
{
OriginalFirstThunk - (32bit) a RVA pointing to a 0-terminated array of RVAs to IMAGE_THUNK_DATAs, each describing one imported function. The array will never change.
TimeDateStamp - (32bit) for bound imports(0 if not used), DLL version checking. If binarie TimeDateStamp != DLL TimeDateStamp, it has to calculate and patch FirstThunk [read until c) to understand better]
ForwarderChain - (32bit) index of the first forwarder in the list of imported functions. Forwarders are also advanced stuff; set all bits to 1 for beginners.
Name - (32bit) RVA to the name of the DLL (0 terminated ASCII string)
FirstThunk - (32bit) RVA to a 0-terminated array of RVAs to IMAGE_THUNK_DATAs, each describing one imported function. The array is part of the import address table and will change.
}
IMAGE_THUNK_DATA is a RVA to a IMAGE_IMPORT_BY_NAME which describes the imported function.
IMAGE_IMPORT_BY_NAME: a 16bit-number(a hint) followed by an unspecified amount of bytes, being the 0-terminated ASCII name of the imported symbol.
the HINT is an index into the exporting DLL's name table(making search faster); but in reality most compilers screw it, so don't rely on it.
open your hexeditor and create a new file, and remember when writing RVAs, remember the offset they should be in unpackpad.exe. the .idata start at file offset 0x6000. let's begin...
for now write 4 bogus bytes (OriginalFirstThunk), leave 4 bytes 0x0 (TimeDateStamp), write the 'FF' byte 4 times (ForwarderChain), write 4 bogus bytes (Name) and finally another 4 bogus bytes (FirstThunk).
then do this 5 more times(since we have 6 DLL files), and leave 4*5 = 20d bytes 0x0(NULL IMAGE_IMPORT_DESCRIPTOR), and some more to pad them at 8byte boundarie, you should be at offset 0x6090 (remember what i said about the 0x6000).
replace the 1st OriginalFirstThunk, at offset 0x0, to 90,60,00,00(0x00006090), and FirstThunk to that value also. we'll leave the 'Name' for latter.
remember our first DLL is KERNEL32.DLL (see _UPXrscr.PE1) and it has 37d imports (see _import.PE), so we'll have to do 37 RVA + 1 NULL RVA (RVA is 32bits sized), each RVA points to one IMAGE_THUNK_DATA,
and an IMAGE_THUNK_DATA is a RVA to a IMAGE_IMPORT_BY_NAME (2 bytes 0x0 and a 0x0 terminated string of the imported function).
after doing all the 37 RVAs and corresponding IMAGE_THUNK_DATAs and IMAGE_IMPORT_BY_NAMEs, we insert the name of the .DLL (in this case KERNEL32.DLL), and make the 'Name' point to where it is.
you can see how much work this gives us... so we must definetly code an auxiliary tool.


[***] fixing the .rscr section
so we have "_rscr.PE" and "_UPXrscr.PE", open then in your hexeditor
so in "_rscr.PE" we have it 0x0 from offset 0x0 to 0x8af (0x8af and not 0x8b4 because we are working in 8byte boundaries)
look at "_UPXrscr.PE", it as some data from 0x0 to 0x8af, apply the sacred and mighty rule of copy-paste (i did this on a guess feeling and it worked... almost
i don't know how to fix this the .rscr is fuxored in 2 ways: the icon and the Version (right click on unpackpad.exe, properties, should also show a 'Version' tab)
maybe with a resource editor we could fix up things... we have to copy the resources from packpad.exe and paste them in unpackpad.exe, if only i knew how
(i tried with a couple of resource editors but with no success)
in packpad.exe:
size raw data - 0xe00
pointer raw data - 0x3e00
IMAGE_DIRECTORY_ENTRY_RESOURCE - 0xf000 ; 0x0c14
in unpackpad.exe
size raw data - 0x5000
pointer raw data - 0x7000
IMAGE_DIRECTORY_ENTRY_RESOURCE - 0x7000 ; 0x4fb8

[****]
no idea on how to solve this problem, without a .reloc our unpackpad.exe will only run on OS like ours (if you have NT only runs on NT, if XP only on XP...etc)














CONCLUSION: the prog works, but i lost the .resources from the packed.exe, and lost the .reloc section

nikolatesla20
August 10th, 2002, 00:34
Don't worry about losing the reloc section, most likely any info in there was only put there by the packer itself. Very very few linkers put a reloc in an EXE by default. You usually have to explicity tell it to do so. It's a very rare thing if you would ever need a reloc in an EXE. A DLL on the other hand, is different. For those you MUST have it...

-nt20

esther
August 19th, 2002, 18:27
Hi Kr0n0,
Do some string searching youwill able to find it

DakienDX
August 19th, 2002, 21:35
Hello Kr0n0 !

You got something wrong. Not the .reloc section locks the unpacked .EXE to one OS, but the import table does.
Since you used the default option of UPX on a .EXE file, the relocations are stripped automatically and you can't rebuild them since they're not present in the packed file.

Your unpacked file will not run on an other OS since you may not have rebuilt the import table correctly. In UPX you have never a uncompressed "original" import table in memory, since UPX already compresses it a bit before the real compression takes place. So the unpacked import table is not "normal" import table, which you could insert into the dump later, but one just UPX can use to set up the imported functions. So you'll need a import rebuilder for it. (one is included in ProcDump, you'll find many other doing this if the imports are not redirected, which is not the case here)

For the resources I suggest Resource Hacker. Save the unpacked resources from the original (packed) file. In the unpacked file delete this entries first and import your saved data again. This should work most of the time.

evaluator
August 20th, 2002, 14:40
So MAIN reason, why unpacked prog not runs on other OS is:

many Imports from one DLL has same address for one OS & not same for other OS.
So if you do resolving, your results will different for each OS.

However Icedump(& Imprec) has built in future, called Export-Renormalization.
But I suggest, you should trust to your eyes.

So to be sure, you have right ImprotName, you must debug program & catch moment,
when unpacker-engine builts IAT. So you will see right ImortNames.