Aymeric on Software

Because we needed another of these blogs...

Changing a Signed Executable Without Altering Windows Digital Signature

It should not be possible, but it is… sort of.

The way Microsoft authenticode works is the following. During the signature process, it computes the hash on the executable file. The hash is then used to make a digital certificate which is authenticated by some authority. This certificate is attached to the end of the PE exectuable, in a dedicated section called the Certificate Table. When the executable is loaded, Windows computes the hash value, and compares it to the one attached to the Certificate table. It is “normally” impossible to change anything in the file without breaking the digital authentication.

However three areas of a PE executable are excluded from the hash computation:

  • the Checksum in the optional Windows specific header. 4 bytes.
  • the Certificate Table entry in the optional Windows specific header. 8 bytes.
  • the Digital Certificate section at the end of the file. Variable length.

You should be able to change those area without breaking the signature. I have discovered by accident that it is possible to append an arbitrary ammount of data at the end of the Digital Certificate. These data are ignored by both the signature parsing and hash computation algorithms. It works on all version of Windows I tested (2000, XP, Vista) as long as the length of the Certificate Table is correctly increased. The length is stored in two different location: the PE header and the beginning of the certificate table.

How to add a payload

  1. Locate beginning of PE header (PE)
  2. Skip COFF header (+=28 bytes)
  3. Go to Certification Table Entry in the Windows specific optional PE header (+=120 bytes after COFF; total +=148 bytes)
  4. Change size of Certificate Table as defined in IMAGE_DATA_DIRECTORY.Size to add the size of the payload.
  5. Go to location defined IMAGE_DATA_DIRECTORY.VirtualAddress. This is the absolute location of the Certificate Table within the file.
  6. Change again the size of the header, inside the PKCS1_MODULE_SIGN.dwLength
  7. This should normally be the last section in the executable; so go to the end and add payload
  8. Possibly calculate the new checksum of the file

Caution: the previous constants are true for the 32bit x86 versions of Windows. Payload needs to be 64bits aligned. All the 32 bits constants are of course little endians woo woo!

Documentation Links:

Sources: AppendPayLoad.tar.bz2