-
Notifications
You must be signed in to change notification settings - Fork 17
SigStash Payload Embedding
A signed PE stores its signature in a PKCS#7 blob near the end of the file. SigStash hides extra data inside that blob, not after it. Windows still sees a valid signature because the hidden data sits in an unsigned attribute field.
- PKCS#7
SignerInfoholds both authenticated and unauthenticated attributes. - RFC 5652 section 5.3 leaves
unsignedAttrsoutside the signature check. - SigStash writes payload bytes there, so Authenticode stays valid.
- OID:
1.3.6.1.4.1.311.99.1 - Shape:
SET { OCTET STRING <payload> } - Result: the payload sits under a custom unsigned attribute.
- OID:
1.3.6.1.4.1.311.2.4.1 - Wrapper: fake
SPC_NESTED_SIGNATURE - Reason: this matches the OID that
signtooluses on dual-signed PEs, so the blob blends into a normal Authenticode pattern.
- SigFlip, CVE-2013-3900, writes data into certificate table padding after the DER blob.
-
EnableCertPaddingCheckrejects that padding. - SigStash writes data inside the DER structure itself.
- Result:
EnableCertPaddingCheckdoes not break SigStash.
DER length encoding supports payloads up to 4 GB in theory. Lab tests round-tripped the following sizes without breaking the signature.
| Payload size | Roundtrip | Signature status |
|---|---|---|
| 24 bytes | success | valid |
| 64 KB | success | valid |
| 1 MB | success | valid |
| 8 MB | success | valid |
| 16 MB | success | valid |
- Direct mode adds about 15 bytes for the OID,
SET, andOCTET STRINGheaders. - Camouflage mode adds about 58 bytes for the
ContentInfoandSignedDatawrapper.
The wrapper cost is negligible next to the tested payload sizes.
signtool verify /pa ignores nested signatures. signtool verify /all walks them and reports each one separately. In kernel mode, ci.dll iterates nested signatures by hash strength. The camouflage wrapper uses empty signerInfos, which lines up with the cases the kernel skips.
Dual-signed PEs carry two WIN_CERTIFICATE entries. The embed tool preserves both entries. --signer-index selects which entry receives the payload. Default -1 targets the last entry, which is usually the SHA-256 signature.