From 77376026088678de4555620094df1d10e67a17dc Mon Sep 17 00:00:00 2001 From: Jeremy Compostella Date: Tue, 23 Jun 2026 09:43:03 -0700 Subject: [PATCH] scripts: fix compute_authenticode_hash for unsigned PEs When the PE has no attached certificate the security data directory fields VirtualAddress and Size are both 0. The previous unconditional slicing: pe_data[certificate_table_offset + 0x08 : 0] # -> empty + pe_data[0 + 0 :] # -> whole file re-appended produced a wrong digest for unsigned images. Add an explicit branch: when VirtualAddress == 0, hash only the bytes that follow the 8-byte cert-dir data-directory entry, which is the correct tail of an unsigned PE image. Signed-off-by: Jeremy Compostella --- scripts/authenticode_transplant.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/authenticode_transplant.py b/scripts/authenticode_transplant.py index 901bcb1..e46fffc 100644 --- a/scripts/authenticode_transplant.py +++ b/scripts/authenticode_transplant.py @@ -447,10 +447,17 @@ def compute_authenticode_hash(pe_data: bytes, hash_algorithm: Optional[object] = hash_data = ( pe_data[:checksum_offset] + pe_data[checksum_offset + 0x04 : certificate_table_offset] ) - hash_data += ( - pe_data[certificate_table_offset + 0x08 : certificate_virtual_addr] - + pe_data[certificate_virtual_addr + certificate_size :] - ) + if certificate_virtual_addr == 0: + # Unsigned PE: the security data directory is empty (VirtualAddress == 0, + # Size == 0). The naive slice pe_data[0 + 0:] would re-append the entire + # file, producing a wrong digest. Instead, hash only the bytes that follow + # the 8-byte cert-dir data-directory entry. + hash_data += pe_data[certificate_table_offset + 0x08 :] + else: + hash_data += ( + pe_data[certificate_table_offset + 0x08 : certificate_virtual_addr] + + pe_data[certificate_virtual_addr + certificate_size :] + ) # Map cryptography hash algorithm to hashlib if isinstance(hash_algorithm, crypto_hashes.SHA256):