I reverse-engineered Microsoft's AuthentiCode format a few years ago while,
uhh, investigating its security but never really published the details, here
they are in case anyone finds them useful.  There's nothing terribly tricky
about it, it's just a PKCS #7 detached signature inserted as a COFF record.
Now you can create your own signed files and users can run them secure in the
knowledge that it's perfectly safe to do so (it's signed, so it has to be


-- Snip --

Format of a Signed File

A signed file is a standard Windows PE executable with signature data appended
to it.  A PE file begins with a 16-bit MSDOS executable stub (which just prints
a message that you can't run the program and exits).  Following this is the
real data, organised in a COFF-like format.  The general COFF header which is
always present is followed by another header which contains information on
executables (it's referred to as an optional header, but it's always present
for executables).  This header defines a number of data directories which
contain data sections within the executable.  One of these directory entries is
an (undocumented) IMAGE_DIRECTORY_ENTRY_SECURITY, which is used to store the
signature: Hash the entire file, add a security directory entry large enough to
contain the signature, and write the signature at that position in the file.

The signing process is as follows:

1. Hash the file, skipping the file checksum (another undocumented attribute,
   but there are standard Windows functions to calculate it) and the
2. Generate the signature and append it to the file.
3. Write the signature position and size (padded out to a multiple of 16 bytes)
   into the IMAGE_DIRECTORY_ENTRY_SECURITY.  The signature position is the end
   of the file, since it's simply appended to the existing data.
4. Update the file checksum.

The security information begins with a 32-bit length (which is ignored) and a
32-bit flags field which should be set to 0x00020200.  Most of the flags are
unused, although changing the first 0x02 to a 1 gives an invalid signature, and
changing the second one to anything other than 0x02 results in the signature
check silently failing with no error message or other indication.

Immediately following this is a complex PKCS #7 signature record which contains
a detached signature for the rest of the file.  The outer wrapper is PKCS #7
signedData, with the content being an spcIndirectDataContext (an MS-defined
data type) which contains an (obsolete) spcPelmageData record and an MD5 hash
of the file.  This is followed by a certificate chain containing a complete
chain of certs from a known CA to an end-users AuthentiCode signing
certificate.  Following this is information on the signer (that is, data to
identify the AuthentiCode certificate which signed the whole thing), an
identifier for the hash algorithm used (again, MD5), and some authenticated
attributes.  These contain more MS-defined attributes, typically spcSpOpusInfo
and spcStatementType which are used to provide information on the signer (eg
whether they're using an individual or commercial signing certificate).  Also
included is a messageDigest attribute which contains the MD5 hash of the
previous spcIndirectDataContext content.  Finally, the authenticated attributes
are hashed and signed, with the signature being included at the end of the
collection of signature information.

To create the signature, you need to hash the entire file (skipping the
checksum and IMAGE_DIRECTORY_ENTRY_SECURITY as explained above) and write the
hash info the spcIndirectDataContext content record.  Then hash this and write
the hash and other attributes into the authenticated attributes.  Finally, hash
the authenticated attributes and append the signature to the end of the
signature record.  This means that each collection of data is covered by its
own hash, which is then passed up the chain to the next level until it reaches
the signature.

Reply via email to