Since I love to play with the WinAPI or debugging in general, I decided to write a small unpacker for the open source PE executable packer UPX today (Windows version).
In order to accomplish this, I proceeded as follow:
CreateProcess
API all withDEBUG
andDEBUG_ONLY_THIS_PROCESS
flags.GetThreadContext
API call in order to read value ofEIP
.ReadProcessMemory
API call loop searching for the lastJMP
instruction.- Overwriting the
E9
withCC
in order to set anINT3
breakpoint on the address. - Entering
DebugEvent
loop waiting for the breakpoint. Once reached, reset byte back toE9
, decreaseEIP
by one and jump to the address (OEP
) of the target.
After reaching the OEP
, I proceed as follows in order to dump the process:
- Read ImageBase, Base of code, ImageSize, ... from original PE headers
ReadProcessMemory(hProcess, header32.ImageBase, buffer, header32.SizeOfImage, bytes_read)
- Save buffer content to payload.bin, update the PE header of the file with new EntryPoint (
OEP
) and setRawDataOffset
andRawDataSize
of each section to its correspondingVirtualAddress
/VirtualSize
.
After creating the dump with fixed OEP
& RAW offsets/sizes for the sections, I fix the dump with ImpREC (right now manually, but I plan to use ImpREC.dll
or the ImpREC lite source in order to assemble everything in one tool at a later point).
The thing that confuses me though, is the fact, that the resulting binaries worked perfectly fine (exact match with the MUP) for one test case (a small hello world fasm application) and my dump file was exactly the same I had received through OllyDump, but when I tried to do the same unpacking with an UPX packed version of putty.exe
, my dumped memory varied from the one OllyDump had dumped starting at RAW offset 0x73970
(exact match before that address).
However - the file size is again the same one (and all bytes before that offset match), just after that certain address the bytes magically won't match anymore (they are still non-zero though).
I studied the source code in OllyDump.c
thoroughly regarding this difference, but as for now I didn't find my mistake... In some cases my dumps are equal to the ones generated by OllyDump and in some they aren't. Or is the mistake probably in my approach already?
Note: Source code omitted on purpose, since it's a few hundred lines long and super messy as for now. Can/will add further details if required or if I missed something, please just let me know in the comments.