Almost Manual Unpacking (using Softice and Icedump)

Text written by r!sc . 6th febuary 2000

Target exe  : aspack.exe . 231,424 . v 2.001
Packed with : ASProtect ? (section added named .aspr)
Url         : Linked next to this text on my homepage! (317kb zip)


part1 . some theory

part2 . getting your hands dirty

part3 . dumping a virgin (import table)

part4 . dumping the rest and fixing the header


=part1===part1===part1===part1===part1===part1===part1===part1===part1===part1=
Some theory.

A pe-file compressor or encryptor has to append its compressed / crypted exe
with unpacking / decrypting code . if it crypts / packs the import table, it
also has to load the import table itself (attack point :) . also, as the exe
loads, it has to have enough memory allocated to uncompress / decrypt the
original code/data (+ a bit of an overhead for its own code (and maybe more
overhead for the compressed data)) We dont know the size of the original
program, but checking out the pe-header, we can get the process size, which
will be ample for the process to load/unpack into and run .

For me, when unpacking a file, i try to locate the import table before its
initialised, dump that, then trace to the original entry point, and dump
the rest of the process. paste these together, fix the pe-header . job done.
Some packers leave all the original sections in the pe-header, making it
quite easy to find the VA for the import table, others 'merge sections' to
create one empty section for unpacking the original code/data and one 
section containing the compressed data, and the last section containing
its own import table / icon / unpacking code.. its still an easy job, but
you need a different approach . maybe covered in Unpacking#2.


=part2===part2===part2===part2===part2===part2===part2===part2===part2===part2=
Getting your hands dirty.

Fire up Procdump's pe-editor, borrow some information from our target file.
we want the process size, and if possible, the VA (virtual address) and the
size of the import table.. Luckily this file has every section left intact 

Size of image : 00079000  ; how much memory to allocate for this pe-file
Image Base    : 00400000  ; yak yak yak

.idata
Virtual Size   : 00002000   ; size of idata im memory
Virtual Offset : 00046000   ; VA of idata (+imagebase == 00446000)

.rdata
Virtual Size   : 00001000
Virtual Offset : 00049000

well, this may be a bad time to tell you, but i suck at this . The import
table may be in the idata section, or the rdata section . looking at their
sizes, i'd put my money on .idata . . 


=part3===part3===part3===part3===part3===part3===part3===part3===part3===part3=
Dumping a virgin (import table :)

Fire up Frogsice, as this version of .aspr has some anti-softice code. we
set a nice bpx on loadlibrarya, and run aspack.exe. . . when softice breaks,
check the memory at 446000 and 449000, to see if the import's have unpacked.

:bpx loadlibrarya
Break due to BPX KERNEL32!LoadLibraryA
Break due to G
:dd 446000 l 40
0030:00446000 00000000  00000000  00000000  0004669C      .............f..
0030:00446010 0004612C  00000000  00000000  00000000      ,a..............
0030:00446020 000468B6  000461AC  00000000  00000000      .h...a..........
0030:00446030 00000000  000468D0  000461B4  00000000      .....h...a......

woo, 446000 isnt all ?? ?? ?? ?? which means it unpacked! and the better news
is that this looks like exactly what we need . The image_import_descriptors,
a structure of 5 dwords containing pointers to the first_thunk, library_name
& original_first_thunk (not in that order.. hehe) . boring part follows.

what is the format of image_import_descriptor's ? well, they contain five
dwords, and er, read on..

dd offset original_first_thunk
dd timedatestamp
dd forwardchain
dd offset library name
dd offset first_thunk

timedatestamp and forwardchain are useually set to 00000000, original first
thunk isnt needed, its just an exact copy of the first thunk . libraryname
is a pointer to the libraryname :d and the first thunk is the array of
pointers to the asciiz's. its the first thunk that gets overwritten with the
api's address's . . . the image_import_descriptors are terminated with five
NULL dwords . good hint for locating these is searching for the beginning
of the first thunk (will contain either pointers to the asciiz's or the
actual api address ( xx xx f7 bf or something for kernel api's (on 9x)))
or search for a libraryname, then using the RVA of that, you can locate
the image_import_descriptors . . 

just a small reversing session of our image_import_descriptors..

:dd 446000 l 40
0030:00446000 00000000  00000000  00000000  0004669C      .............f..
0030:00446010 0004612C  00000000  00000000  00000000      ,a..............

4669c is the pointer to the LibraryName (RVA, you need to add the imagebase)

:db 44669c l 10
0030:0044669C 4B 45 52 4E 45 4C 33 32-2E 44 4C 4C 00 00 00 00  KERNEL32.DLL....

and 4612c is the pointer to the firstthunk for that library

:dd 44612c l 10
0030:0044612C 000466AA  000466C2  000466DA  000466F2      .f...f...f...f..

these are pointers to the asciiz's, the actual api names . but they point to
two bytes before the asciiz, to the HINT . . 466aa is the first api to load,
466c2 is the second .. .NULL terminated with a single dword

:db 0004466aa l 20
0030:004466AA 00 00 44 65 6C 65 74 65-43 72 69 74 69 63 61 6C  ..DeleteCritical
0030:004466BA 53 65 63 74 69 6F 6E 00-00 00 4C 65 61 76 65 43  Section...LeaveC

well, thats deffinatly our virgin import table . dump it!! (and remember the
address of the image_import_descriptors)

:pagein d 446000 2000 c:\aspack.idata.bin


=part4===part4===part4===part4===part4===part4===part4===part4===part4===part4=
Dumping the rest and fixing the header.

well i suppose you know how to trace? trace from the break on loadlibrarya, f8
or f10 . setting hardware break points before you trace over a call helps, as
these breakpoints dont patch the memory with a 'cc' thus, dont get overwritten
when code/data is unpacked over them . 'bpm <address> x' . all the unpacker
code appears to be around VA 00C1xxxx . thus, if we find execution jumps to a
lower address than this, we could be pretty sure thats the original code . 

:bpm c10da8 x
Break due to BPMB #016F:00C10DA8 X DR3
:u eip l 30
0167:00C10E98  89C4                MOV     ESP,EAX
0167:00C10E9A  89D0                MOV     EAX,EDX
0167:00C10E9C  8B1D6C66C100        MOV     EBX,[00C1666C]
0167:00C10EA2  89041C              MOV     [EBX+ESP],EAX
0167:00C10EA5  61                  POPAD
0167:00C10EA6  50                  PUSH    EAX  ; push 442b98
0167:00C10EA7  C3                  RET          ; ret to that address.
:?eax
00442B98  0004467608  "D+"
:u eip l 10
0167:00442B98  55                  PUSH    EBP
0167:00442B99  8BEC                MOV     EBP,ESP
0167:00442B9B  83C4F4              ADD     ESP,-0C

how nice this is . Write that down, the original entry point . . dump the
whole process now . best to bc* before hand . 

:pagein d 400000 79000 c:\aspack.dumped.exe

. now we have to copy&paste the virgin import table into this dump, fix the
pe-header, then its all over!

since we dumped from 400000, the file-offset's will be equal to the RVA's.
our import table was at RVA 46000, so it will be at file offset 46000. 
Use hex workshop or whatever hex editor you have, to copy the 2000 bytes
of 'aspack.idata.bin' over the 2000 bytes of data in 'aspack.dumped.exe',
from file offset 46000 to 48000 .. ..

psize==vsize, offset==rva.
every RAW offset will now be equal to the RVA's aswell.. 

CODE RVA : 00001000 .. . CODE new file offset : 00001000

every Virtual Size will be equal to the RAW size, unless . . (they are
normally aligned on a 1000h byte boundry . Virtual size could be 45001, but
when windows loads it, it would allocate 46000 bytes for it.)

CODE virtual size : 00042000 .. CODE new RAW size : 00042000 . . 

okay, go fix the sections using procdump. . if this is done properly, when 
you save changes and refresh explorer . . the icon should come back.

two more things to fix before it runs . the programs entrypoint, and the
location of the import table . . 

new entry point is 00042B98 . (original entrypoint - imagebase)

click on the 'directory' button to edit the address for the import table

new import table RVA is 46000 . (rva of the image_import_descriptors)
size of the import table? hopefully bigger than 0 :d

save changes, exit procdump . cross your fingers . run aspack.dumped.exe .


well, it runs . it runs sweet. . its not fully restored, you still have the
extra unpacking code, and the resource section is a bit mangled, with some
resources moved into the .aspr section aswell . you cant WDasm the file! 
haha, edit the section characteristics for the first section..

change them from c0000060 (data, writable) to 60000040 (code, executable)
or e0000060 (code, data, etc etc)


the end

lookout for Unpacking#2 and Unpacking#3, coming to a pc near you soon!
