3

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 with DEBUG and DEBUG_ONLY_THIS_PROCESS flags.
  • GetThreadContext API call in order to read value of EIP.
  • ReadProcessMemory API call loop searching for the last JMP instruction.
  • Overwriting the E9 with CC in order to set an INT3 breakpoint on the address.
  • Entering DebugEvent loop waiting for the breakpoint. Once reached, reset byte back to E9, decrease EIP 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 set RawDataOffset and RawDataSize of each section to its corresponding VirtualAddress/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.

1

Hard to tell what the reason for the differences might be without actually seeing the differences, but one guess is that you're doing ReadProcessMemory(hProcess, header32.ImageBase, buffer, header32.SizeOfImage, bytes_read), while the other tool may be doing foreach(section) {ReadProcessMemory(hProcess, header32.ImageBase + section.RVA, buffer, section.VirtualSize, bytes_read)}; this may cause the "caves" between sections to differ.

(BTW, I assume your header32.ImageBase is the actual base address of the module in memory, not just the image base address from the PE headers, since ASLR could relocate it at runtime.)

  • Thank you I gotta check this out next week (forgot my laptop at the office). – beta Jul 19 '14 at 9:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.