Replace the PE stub in an existing Win32 .exe

Viewed 333

I have an existing Win32 .exe with a PE stub in the beginning, and I have another PE stub stored in a separate file. This separate PE stub is longer than 20 KiB, the original PE stub is at most 512 bytes. I don't have the source code, so I'm not able to recompile or relink. How do I replace the PE stub in the Win32 .exe?

Probably I need a tool for that which updates section file offsets. But that's not enough: according to diff of the outputs of objdump -x file.exe, these also have to updated: AddressOfEntryPoint, BaseOfCode, BaseOfData, SizeOfImage, SizeOfHeaders, offsets in the data directory, addresses in relocation fixups.

1 Answers

TL:DR Use the Perl script in pe-setstub to replace the DOS stub in a PE .exe.

Win32 PE .exe files with large stubs (even larger than 100 000 bytes) do work on various Windows versions, but there is a requirement: the VirtualAddress of each section must not be smaller than the header size (which includes the stub, the PE header and the PE section table). Thus if a program replaces the stub with a much larger one, the program also has to increase the VirtualAddress of each section. This sounds like a very complicated operation, so it's unlikely that there is some tool ready-made for that.

FYI On Win32s, there is an additional requirement: the PE header (ending with the last byte of the last section header) must fit in 0x800 (2048) bytes.

Even with these requirements, it's possible to add a long stub, without touching the VirtualAddress of sections or the ImageBase. The PE .exe would look like this:

  1. 32 bytes of DOS .exe header (including a few bytes of padding at the end), starting with MZ. The header field at offset 8 points to the DOS stub code (#3).
  2. About 368 bytes of PE header (containing 4 section headers of 40 bytes each), starting with PE, and ending with the last section header.
  3. The rest DOS stub code, will be loaded to memory and run by DOS. This can be as small as 32 bytes, or as large as several hundred KiB.
  4. Some padding bytes to align the first section to a multiple of 0x200.
  5. Section data, aligned to a multiple of 0x200 each.

I've implemented such a stub replacement and splitting as a Perl script in pe-setstub.

It works because there is no (small) upper limit on the size of #3.

Related