Well it was about time I wrote some more about packer spelunking, in fact my idleness in this area is more due to a lack of targets so if you have one sat on your hard drive consider sending it to me, 'cue request deluge'. I found Multimedia Builder on PC Direct's cover CD (December 1999), you could try the webpage at http://www.mediachance.com (the precise version number is 4.3 - 1,147,036 bytes).
Multimedia Builder can be registered with a registration code, the scheme is curious to say the least and can be traced in SoftICE, the program reverses your user name before feeding it through a lower casing routine, I think a particular crackers name is blacklisted or parts of it are. After this you might expect an algorithm but there isn't one, the code 94 is hard-coded in (yes it defies belief).
However what is interesting us is the fact that MMBuilder.exe is packed using Petite, tell-tale sign being the .petite section. I couldn't establish quickly which version of Petite was used but I suspect it could be v2.x (ProcDump failed on all of them so I am none the wiser). The first thing we'll do is spelunk the packer using a known target (note MMBuilder.exe has a .text section indicating a MS compiler). I'm using the ubiquitous Start Menu Cleaner.
Lets start our tracing at the entry point :-
PUSHF <-- Save flags. PUSHAD <-- Save all registers. PUSH EAX PUSH 0000BC54 PUSH 0 CALL [EAX+14] <-- GlobalAlloc.
Just looking at those initial pushes you can probably guess the code that will be just before the real entry point (POPAD, POPF quite probably). Notice that with our example Petite seems to 'lose' several sections (in hindsight perhaps amalgamate is a better word), contrast :-
Original Petite ----------------------------------------------- .text .text <-- Packed. .rdata .rsrc <-- Not touched. .data .reloc <-- Stripped. .idata .petite <-- Unpacker/Import Table. .rsrc .reloc
It seems from a preliminary inspection that the .rsrc section will not be touched by Petite (this saves the author hassle I expect, yet probably compromises the packers potential effectiveness), the intriguing section is obviously .petite which must account for 3 sections in total (.rdata, .data & .idata), the latter 2 being of paramount importance (this probably means bye-bye virginity restoration). Lets take a look at what happens next :-
MOV EDI,[EDX+08] <-- RVA. ADD EDI,EAX <-- Add to ImageBase. MOV EBX,[EDX+04] <-- Size. MOV ECX,[EDX+0C] <-- Number of bytes. SAR ECX,02 <-- DWORDS. XOR EAX,EAX <-- Clear EAX. REPZ STOSD <-- From here. MOV ECX,[EDX+0C] <-- Get bytes again. AND ECX,03 REPZ STOSB <-- Move final bytes. ADD EDX,10 JMP .LOOP <-- Loop.
This is a very trivial summary of what actually happens but you can get the gist as this is the main loop through the sections. At the end of this a CALL occurs which must be traced (you'll find it easily because if you don't trace it the program starts, its also reached via a far jump). Below this you should trace the next CALL which is where the import addresses are fixed up (another loop), at this level you should be able to see where the real entry point resumes, see my notes above regarding the final POP's before the entry point. Lets apply this very brief session of spelunking and unpack MMBuilder.exe.
As expected the initial code is similar to that which I described above, yet the actual unpacking and import related code is a lot trickier and harder to trace. Lets devise a new technique, firstly we know that if we can find the real entry point all we really need to do is dump the sections, attach a PE header and perform the necessary fix ups, with MMBuilder I traced the unpacking code but couldn't easily find the entry point, in fact I always seemed to land up inside TlsAlloc. The solution will prove simple. At the very start bpx for something like TlsAlloc or GetVersionA (most Windows programs call this very soon in the startup procedure) and perform a search :-
s 0 l ffffffff 61 66 9D
These of course are the opcodes for POPAD, POPF. You'll strike it lucky and find only 1 location (666105), take note where this is relative to where you actually start out tracing in the Loader :-). Now you just need to bpx for this address and trace 4 lines as we jump to the real entry point (5230B0). If you do a 'map32 MMBuilder' in SoftICE you'll be able to start dumping the sections, in this case there are only 3 (the resource section we know is not touched).
.text 0001 0137:00401000 20A000 CODE RW <-- Dump this. .rsrc 0002 013F:0060B000 5B000 IDATA RO <-- Same as compressed. .petite 0003 0137:00666000 194B CODE RW <-- Dump this. .udata 0004 0137:00668000 1000 UDATA RW <-- Dump this for safety (renamed by me).
So lets grab the PE header from our packed file and glue these dumps together. All thats needed now is to fix everything by hand (or HEX editor), this task is actually very easy, just work methodically through each section, below is my screenshot taken from ProcDump's PE editor (I only use it here to save myself typing, if you want to avoid the "Unpacked with ProcDump nag being stamped in the header you should do the same). Note that Petite in some senses breaks the rules a little, my guess is that allocating less memory than the raw size of a section as per the .petite section is a recipe for disaster.
Update also the new entry point (1230B0) and now you should be able to run your newly unpacked file (at least if you are running Windows 95). If you are running under NT there will be problems with the import address table and maybe even the lack of .reloc). In the second part of my tutorial covering Petite, I'll show you how to fix this and I'll also discuss Petite's unpacking a little more.