Tool to help rebuild and patch 32-bit Windows applications.
dump
- dump information about section of executablegenlds
- generate GNU ld script for re-linking executablepe2obj
- convert PE executable into win32 object filepatch
- apply a patch set from the .patch sectionsetdd
- set any DataDirectory in PE headersetvs
- set VirtualSize for a sectionexport
- export section data as raw binaryimport
- dump the import table as assemblyre2obj
- convert the resource section into COFF objectgenmak
- generate project Makefilegenprj
- generate full project directory (default)
You need GNU binutils
2.26 to successfully do everything without assertion
errors.
All stable releases before 2.26 suffer from missing absolute reloc support
for COFF object files which means you can't jump to or call absolute memory
addresses in GNU as
assembly and it includes inline assembly with gcc
.
You can workaround this by using a different assembler with ELF output format
(e.g. nasm -f elf
).
The 2.25 stable release suffers from a regression that makes relinking resource
sections impossible if the original binary with the .rsrc
section is included
in the linker script.
You can workaround this by removing the resource section from the original binary before using it in the process.
- GNU make
- GNU cc
Type 'make' to build the tools on Linux. On Windows you might need to adjust some environment variables to get a successful build. The developers test with GCC on Linux and Windows (via MinGW), but the code aims to be strictly C99-compliant so any C99-supporting platform should suffice.
petool
uses fixed-with numeric types wherever possible so building on both 64-
and 32-bit architectures is supported. Note however that the code currently
supports working with 32-bit portable executable.
petool
tries its best to create a re-linkable template for any given normal
Windows executable. This is not always successful so be warned it might not
work out of the box without modifications.
To begin, generate a project by giving a path to an executable file as the only
argument. Dragging and dropping an executable on petool.exe
also does this
on Windows and the project is generated next to the original executable in a
subdirectory.
For technical reasons, embedded .bss
inside .data
is not supported but is
instead unwound to separate .bss
after .data
. You can optionally use setdd
command to expand .data
to its original size.
The default linker script uses existing .idata
section if such is in the
original executable, otherwise it adds it as a new section and expects imports
to be rebuilt from the assembly generated by import
command. You can
optionally use setdd
to use the original import section and skip rebuilding by
removing it from the linker script.
You should be able to re-link the executable now by executing make
without any
modifications.
Generating the patch set can be done with GNU as
using the included patch.s
macros. Below are examples how these macros are used in practice.
memsjmp <from> <to>
memljmp <from> <to>
Both short (near) and long (far) variants are included. Jumping to an absolute address is supported and is converted to relative by the linker. No overflow checks are done so do pre-calculate which one you need.
Example: memljmp 0x410000 doMagic /* Do a (far) jump from 0x410000 to label doMagic */
memcall <from> <to>
The memcall macro writes a CALL instruction at from to to. Absolute addresses are converted to relative by the linker.
Example: memcall 0x410000 doMagic /* Make a call from 0x410000 to label doMagic */
memset <from> <byte> <to>
Sets all bytes between from and to (not inclusive) to the 8-bit argument byte.
When you make a memljmp
or anything else over the original code that would
leave some instructions broken or a dead code block, consider clearing the area
before writing the jump. It ensures when you or someone else is following the
code in a disassembler or a debugger that they will not get confused by sudden
far jumps which have broken instructions just after them.
Example: memset 0x410000 0x90 0x410005 /* NOP 5 bytes starting from 0x410000 */
memcpy <address> "<inst>"
This macro will write the given instructions directly on the specified address in the executable. Anything the assembler understands can be used as the inst argument.
Example: memcpy 0x410000 ".long 1; .long 2; .long 3" /* Write three DWORDs to 0x410000 (12 bytes) */
.global _printf
.equ _printf, 0x4B8EE0
When you need to refer to existing symbols inside the executable, you can export global symbols from assembly source. Symbols can be any named memory address: function, data, uninitialized variable. As long as you define them global, you can use them anywhere. Remember decorations if you're referring to exported global symbols from C code.
You can use any compilable language that can produce an COFF or ELF object or
whatever your build of GNU binutils
supports. GNU as
and GNU cc
are the
most compatible tools.
What's important is that whatever external symbols you may need can be exported for the linker somehow and if you use any external dlls you re-create the import table.
When mixing already compiled executable with new code, you need to make sure of the calling convention of your functions and compiler can be made compatible with everything else.
The patch
command reads a PE image section for patch data. The format of the
patch data is as follows:
<dword absolute address> <dword patch length> <patch data>
These binary blobs are right after each other to form a full patch set. The patch command simply looks up the file offset in the PE image file based on given absolute memory address and writes over the blob at that point.
After the patch is applied, you should remove the patch section with GNU strip as it is not needed in the final product. The default project template includes this additional step.