Wiki

Clone wiki

ultima-exodus / binpatch

binpatch

The binpatch tools provide a way to compare differences and apply patches to binary files. There are three associated programs:

  • bindiff - compares two binary files and outputs the differences to a patch file
  • binpat - applies the contents of a patch file to a binary file
  • binunpat - un-applies changes made by binpat

Additional details are described below.

Patch Files

Patch files contain the differences of multiple pairs of files. They're structured such that they begin with a single patch header (PZ), one or more file headers (FZ), and each file may have one or more data headers (DZ) followed by patch data.

For example, suppose a patch file contained two diff pairs, each with three differences. The structure would follow the following pattern:

PZ:FZ:DZ:data:DZ:data:DZ:data:FZ:DZ:data:DZ:data:DZ:data

Patch Header

A patch header begins with "PZ1", where "1" is the version number. It contains the file size of the patch file:

struct patch_header
{
    char hdr[2]; /* PZ */
    char ver;    /* 1  */
    long size;
}

File Header

A file header begins with "FZ1", where "1" is the version number. It marks the start of input/output file information. It contains the name of the original file and an optional new name for the file (if -u was provided to bindiff). It also contains the size of the original file. Each invocation of bindiff that targets the same patch file will create a new instance of a file header.

struct file_header
{
    char hdr[2];  /* FZ */
    char ver;     /* 1  */
    char name[64];
    char newname[64];
    BOOL newname_flag;
    long size;
}

Data Header

A data header begins with "DZ1", where "1" is the version number. It marks the beginning of a data "difference" section within the patch. It contains the offset to the data in the source file, the size of the data section, and the type of difference found (replace, append, or truncate).

struct data_header
{
    char hdr[2];  /* DZ */
    char ver;     /* 1  */
    long offset;
    long size;
    short type;   /* 0 = replace, 1 = append, 2 = truncate */
    short _padding; /* ensures struct ends on dword boundry in wcc */
}

Data Section

Data immediately follows the data header. The meaning and size of that data depends on the type field specified in the header:

  • replace - two data sections follow the header: the first section contains the old data to be replaced; the second section contains the new data. both are of size data_header.size, therefore the size of the data section is data_header.size * 2
  • append - one data section follows the header containing the new data to append to the end of the file. It is of size data_header.size.
  • truncate - one data section follows the header containing the old data to be truncated. It is of size data_header.size.

Updated