Skip to content

Commit 600df89

Browse files
committed
Fix resource leak and improve type safety
- Add try-finally block in compute_authenticode_hash to ensure PE object is properly closed - Add cryptography==43.0.0 to pip-requirements.txt (missing dependency) - Improve type annotations: change dict to Dict[str, Any] for _verify_pkcs7_signature - Enhance docstring to document return dictionary structure
1 parent 0cee114 commit 600df89

2 files changed

Lines changed: 37 additions & 30 deletions

File tree

pip-requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ ruff==0.14.5
44
pytest==9.0.1
55
pefile==2024.8.26
66
pyasn1==0.6.1
7-
pyasn1_modules==0.4.2
7+
pyasn1_modules==0.4.2
8+
cryptography==43.0.0

scripts/authenticode_transplant.py

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import os
3434
import struct
3535
import sys
36-
from typing import Dict, List, Optional, Protocol, Tuple, runtime_checkable
36+
from typing import Any, Dict, List, Optional, Protocol, Tuple, runtime_checkable
3737

3838
import pefile
3939
from cryptography import x509
@@ -218,7 +218,7 @@ def _extract_certificates_from_pkcs7(pkcs7_data: bytes) -> List[x509.Certificate
218218
return certificates
219219

220220

221-
def _verify_pkcs7_signature(pkcs7_data: bytes, pe_data: bytes) -> dict:
221+
def _verify_pkcs7_signature(pkcs7_data: bytes, pe_data: bytes) -> Dict[str, Any]:
222222
"""Verify PKCS7 Authenticode signature against PE file.
223223
224224
This function:
@@ -232,7 +232,10 @@ def _verify_pkcs7_signature(pkcs7_data: bytes, pe_data: bytes) -> dict:
232232
pe_data: The full PE file data
233233
234234
Returns:
235-
dict: Verification results with 'verified' boolean and list of 'signers'
235+
Dict[str, Any]: Verification results with keys:
236+
- 'verified' (bool): Overall verification status
237+
- 'signers' (List[Dict]): List of signer verification results
238+
- 'errors' (List[str]): List of error messages
236239
"""
237240
results = {
238241
'verified': False,
@@ -432,33 +435,36 @@ def compute_authenticode_hash(pe_data: bytes, hash_algorithm: Optional[object] =
432435

433436
pe = pefile.PE(data=pe_data, fast_load=True)
434437

435-
security_directory = pe.OPTIONAL_HEADER.DATA_DIRECTORY[
436-
pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"]
437-
]
438-
checksum_offset = pe.OPTIONAL_HEADER.dump_dict()["CheckSum"]["FileOffset"]
439-
certificate_table_offset = security_directory.dump_dict()["VirtualAddress"]["FileOffset"]
440-
certificate_virtual_addr = security_directory.VirtualAddress
441-
certificate_size = security_directory.Size
442-
443-
hash_data = (
444-
pe_data[:checksum_offset] + pe_data[checksum_offset + 0x04 : certificate_table_offset]
445-
)
446-
hash_data += (
447-
pe_data[certificate_table_offset + 0x08 : certificate_virtual_addr]
448-
+ pe_data[certificate_virtual_addr + certificate_size :]
449-
)
438+
try:
439+
security_directory = pe.OPTIONAL_HEADER.DATA_DIRECTORY[
440+
pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"]
441+
]
442+
checksum_offset = pe.OPTIONAL_HEADER.dump_dict()["CheckSum"]["FileOffset"]
443+
certificate_table_offset = security_directory.dump_dict()["VirtualAddress"]["FileOffset"]
444+
certificate_virtual_addr = security_directory.VirtualAddress
445+
certificate_size = security_directory.Size
446+
447+
hash_data = (
448+
pe_data[:checksum_offset] + pe_data[checksum_offset + 0x04 : certificate_table_offset]
449+
)
450+
hash_data += (
451+
pe_data[certificate_table_offset + 0x08 : certificate_virtual_addr]
452+
+ pe_data[certificate_virtual_addr + certificate_size :]
453+
)
450454

451-
# Map cryptography hash algorithm to hashlib
452-
if isinstance(hash_algorithm, crypto_hashes.SHA256):
453-
return hashlib.sha256(hash_data).digest()
454-
elif isinstance(hash_algorithm, crypto_hashes.SHA1):
455-
return hashlib.sha1(hash_data).digest()
456-
elif isinstance(hash_algorithm, crypto_hashes.SHA384):
457-
return hashlib.sha384(hash_data).digest()
458-
elif isinstance(hash_algorithm, crypto_hashes.SHA512):
459-
return hashlib.sha512(hash_data).digest()
460-
else:
461-
raise ValueError(f"Unsupported hash algorithm: {hash_algorithm}")
455+
# Map cryptography hash algorithm to hashlib
456+
if isinstance(hash_algorithm, crypto_hashes.SHA256):
457+
return hashlib.sha256(hash_data).digest()
458+
elif isinstance(hash_algorithm, crypto_hashes.SHA1):
459+
return hashlib.sha1(hash_data).digest()
460+
elif isinstance(hash_algorithm, crypto_hashes.SHA384):
461+
return hashlib.sha384(hash_data).digest()
462+
elif isinstance(hash_algorithm, crypto_hashes.SHA512):
463+
return hashlib.sha512(hash_data).digest()
464+
else:
465+
raise ValueError(f"Unsupported hash algorithm: {hash_algorithm}")
466+
finally:
467+
pe.close()
462468

463469

464470
def get_authenticode_hash(pe_path: str, fs: FileSystemInterface = None) -> str:

0 commit comments

Comments
 (0)