4
0
mirror of https://github.com/QuasarApp/LIEF.git synced 2025-04-28 13:24:32 +00:00
2021-01-16 09:44:51 +01:00

307 lines
13 KiB
Python

#!/usr/bin/env python
import lief
from lief.PE import oid_to_string
import argparse
import json
import sys
import string
import argparse
import traceback
import pathlib
try:
from prettyprinter import pprint
except ImportError:
from pprint import pprint
HAS_EXCEPTION = False
class exceptions_handler(object):
func = None
def __init__(self, exceptions, on_except_callback=None):
self.exceptions = exceptions
self.on_except_callback = on_except_callback
def __call__(self, *args, **kwargs):
if self.func is None:
self.func = args[0]
return self
try:
return self.func(*args, **kwargs)
except self.exceptions as e:
HAS_EXCEPTION = True
if self.on_except_callback is not None:
self.on_except_callback(e)
else:
print("-" * 60, file=sys.stderr)
print("Exception in {}: {}".format(self.func.__name__, e))
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_tb(exc_traceback)
print("-" * 60, file=sys.stderr)
@exceptions_handler(Exception)
def print_attr(indent: int, auth: lief.PE.Attribute):
if auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.CONTENT_TYPE:
print_content_type(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_SIGNING_TIME:
print_signing_time(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.MS_SPC_STATEMENT_TYPE:
print_ms_statement_type(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_MESSAGE_DIGEST:
print_pkcs_msg_dg(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_COUNTER_SIGNATURE:
print_pkcs_counter_sig(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.GENERIC_TYPE:
print_generic_type(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.SPC_SP_OPUS_INFO:
print_spc_sp_opus_info(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.MS_SPC_NESTED_SIGN:
print_ms_nested_sig(indent, auth)
elif auth.type == lief.PE.SIG_ATTRIBUTE_TYPES.PKCS9_AT_SEQUENCE_NUMBER:
print_pkcs9_at_seq_number(indent, auth)
else:
print(" " * indent, type(auth), auth)
@exceptions_handler(Exception)
def print_pkcs9_at_seq_number(indent: int, auth: lief.PE.PKCS9AtSequenceNumber):
print("{} PKCS #9 sequence number: {}".format(" " * indent, auth.number))
@exceptions_handler(Exception)
def print_ms_nested_sig(indent: int, auth: lief.PE.MsSpcNestedSignature):
print("{} MS Nested Signature:".format(" " * indent))
print_all(auth.signature, indent + 2)
@exceptions_handler(Exception)
def print_spc_sp_opus_info(indent: int, auth: lief.PE.SpcSpOpusInfo):
if len(auth.program_name) > 0 and len(auth.more_info) > 0:
print("{} Info: {} {}".format(" " * indent, auth.program_name, auth.more_info))
elif len(auth.program_name) > 0 and len(auth.more_info) == 0:
print("{} Info: {}".format(" " * indent, auth.program_name))
elif len(auth.program_name) == 0 and len(auth.more_info) > 0:
print("{} Info: {}".format(" " * indent, auth.more_info))
else:
print("{} Info: <empty>".format(" " * indent))
@exceptions_handler(Exception)
def print_generic_type(indent: int, auth: lief.PE.GenericType):
print("{} Generic Type {} ({})".format(" " * indent, auth.oid, lief.PE.oid_to_string(auth.oid)))
@exceptions_handler(Exception)
def print_content_type(indent: int, auth: lief.PE.ContentType):
print("{} Content Type OID: {} ({})".format(" " * indent, auth.oid, lief.PE.oid_to_string(auth.oid)))
@exceptions_handler(Exception)
def print_signing_time(indent: int, auth: lief.PE.PKCS9SigningTime):
print("{} Signing Time: {}/{:02}/{:02} - {:02}:{:02}:{:02}".format(" " * indent, *auth.time))
@exceptions_handler(Exception)
def print_ms_statement_type(indent: int, auth: lief.PE.MsSpcStatementType):
print("{} MS Statement type OID: {} ({})".format(" " * indent, auth.oid, lief.PE.oid_to_string(auth.oid)))
@exceptions_handler(Exception)
def print_pkcs_msg_dg(indent: int, auth: lief.PE.PKCS9MessageDigest):
print("{} PKCS9 Message Digest: {}".format(" " * indent, auth.digest.hex()))
@exceptions_handler(Exception)
def print_crt(indent: int, crt: lief.PE.x509):
print("{} Version : {:d}".format(" " * indent, crt.version))
print("{} Issuer : {}".format(" " * indent, crt.issuer))
print("{} Subject : {}".format(" " * indent, crt.subject))
print("{} Serial Number : {}".format(" " * indent, crt.serial_number.hex()))
print("{} Signature Algorithm: {}".format(" " * indent, lief.PE.oid_to_string(crt.signature_algorithm)))
print("{} Valid from : {}/{:02d}/{:02d} - {:02d}:{:02d}:{:02d}".format(" " * indent, *crt.valid_from))
print("{} Valid to : {}/{:02d}/{:02d} - {:02d}:{:02d}:{:02d}".format(" " * indent, *crt.valid_to))
if len(crt.key_usage) > 0:
print("{} Key usage : {}".format(" " * indent, " - ".join(str(e).split(".")[-1] for e in crt.key_usage)))
if len(crt.ext_key_usage) > 0:
print("{} Ext key usage : {}".format(" " * indent, " - ".join(lief.PE.oid_to_string(e) for e in crt.ext_key_usage)))
if crt.rsa_info is not None:
rsa_info = crt.rsa_info
print("{} RSA key size : {}".format(" " * indent, rsa_info.key_size))
print("{} ===========================================".format(" " * indent))
@exceptions_handler(Exception)
def print_pkcs_counter_sig(indent: int, auth: lief.PE.PKCS9CounterSignature):
print("{} PKCS9 counter signature".format(" " * indent))
signer = auth.signer
print("{} Version : {:d}".format(" " * indent, signer.version))
print("{} Serial Number : {}".format(" " * indent, signer.serial_number.hex()))
print("{} Issuer : {}".format(" " * indent, signer.issuer))
print("{} Digest Algorithm : {}".format(" " * indent, signer.digest_algorithm))
print("{} Encryption Algorithm: {}".format(" " * indent, signer.encryption_algorithm))
print("{} Encrypted Digest : {} ...".format(" " * indent, signer.encrypted_digest.hex()[:20]))
if len(signer.authenticated_attributes) > 0:
print("{} Authenticated attributes:".format(" " * indent))
for auth in signer.authenticated_attributes:
print_attr(indent + 4, auth)
if len(signer.unauthenticated_attributes) > 0:
print("{} Un-Authenticated attributes:".format(" " * indent))
for auth in signer.unauthenticated_attributes:
print_attr(indent + 4, auth)
@exceptions_handler(Exception)
def print_all(sig: lief.PE.Signature, indent: int = 2):
ci: lief.PE.ContentInfo = sig.content_info
print("{}Signature version : {}".format(" " * indent, sig.version))
print("{}Digest Algorithm : {!s}".format(" " * indent, sig.digest_algorithm))
print("{}Content Info:".format(" " * indent))
print("{} Content Type : {!s} ({})".format(" " * indent, ci.content_type, lief.PE.oid_to_string(ci.content_type)))
print("{} Digest Algorithm: {!s}".format(" " * indent, ci.digest_algorithm))
print("{} Digest : {!s}".format(" " * indent, ci.digest.hex()))
print("{}Certificates".format(" " * indent))
for crt in sig.certificates:
print_crt(indent, crt)
print("{}Signer(s)".format(" " * indent))
for signer in sig.signers:
print("{} Version : {:d}".format(" " * indent, signer.version))
print("{} Serial Number : {}".format(" " * indent, signer.serial_number.hex()))
print("{} Issuer : {}".format(" " * indent, signer.issuer))
print("{} Digest Algorithm : {}".format(" " * indent, signer.digest_algorithm))
print("{} Encryption Algorithm: {}".format(" " * indent, signer.encryption_algorithm))
print("{} Encrypted Digest : {} ...".format(" " * indent, signer.encrypted_digest.hex()[:20]))
if len(signer.authenticated_attributes) > 0:
print("{} Authenticated attributes:".format(" " * indent))
for auth in signer.authenticated_attributes:
print_attr(indent + 4, auth)
if len(signer.unauthenticated_attributes) > 0:
print("{} Un-authenticated attributes:".format(" " * indent))
for auth in signer.unauthenticated_attributes:
print_attr(indent + 4, auth)
@exceptions_handler(Exception)
def show_crts(sig: lief.PE.Signature, args):
for crt in sig.certificates:
print_crt(0, crt)
@exceptions_handler(Exception)
def process_signature(sig: lief.PE.Signature, args):
if args.show_all:
print_all(sig)
if args.show_crt:
show_crts(sig, args)
if args.show_hash:
print("Authentihash: {}".format(sig.content_info.digest.hex()))
def main():
parser = argparse.ArgumentParser()
parser.add_argument("file")
parser.add_argument('-a', '--all',
action='store_true', dest='show_all',
help='Show all information')
parser.add_argument('-c', '--crt',
action='store_true', dest='show_crt',
help='Show embedded x509 certificates')
parser.add_argument('-H', '--hash',
action='store_true', dest='show_hash',
help='Show the autentihash value')
parser.add_argument('-C', '--check',
action='store_true', dest='check_sig',
help='Check the signature')
parser.add_argument('-D', '--allow-expired',
action='store_true', dest='allow_expired',
help='Allow expired certificates')
parser.add_argument('-s', '--save',
dest='ext_file_path',
help='Extract and save the PKCS #7')
# Logging setup
logger_group = parser.add_argument_group('Logger')
verbosity = logger_group.add_mutually_exclusive_group()
verbosity.add_argument('--debug',
dest='main_verbosity',
action='store_const',
const=lief.logging.LOGGING_LEVEL.DEBUG)
verbosity.add_argument('--trace',
dest='main_verbosity',
action='store_const',
const=lief.logging.LOGGING_LEVEL.TRACE)
verbosity.add_argument('--info',
dest='main_verbosity',
action='store_const',
const=lief.logging.LOGGING_LEVEL.INFO)
verbosity.add_argument('--warn',
dest='main_verbosity',
action='store_const',
const=lief.logging.LOGGING_LEVEL.WARNING)
verbosity.add_argument('--err',
dest='main_verbosity',
action='store_const',
const=lief.logging.LOGGING_LEVEL.ERROR)
verbosity.add_argument('--critical',
dest='main_verbosity',
action='store_const',
const=lief.logging.LOGGING_LEVEL.CRITICAL)
parser.set_defaults(main_verbosity=lief.logging.LOGGING_LEVEL.WARNING)
args = parser.parse_args()
lief.logging.set_level(args.main_verbosity)
if lief.PE.is_pe(args.file):
binary = None
try:
binary: lief.PE.Binary = lief.PE.parse(args.file)
if binary is None:
print("Error while parsing {}".format(args.file))
sys.exit(1)
except lief.exception as e:
print(e)
sys.exit(1)
if args.check_sig:
flags = lief.PE.Signature.VERIFICATION_CHECKS.DEFAULT
if args.allow_expired:
flags = lief.PE.Signature.VERIFICATION_CHECKS.SKIP_CERT_TIME
res = binary.verify_signature(flags)
print(res)
if args.show_hash:
print("Binary MD5 authentihash: {}".format(binary.authentihash_md5.hex()))
print("Binary SHA-1 authentihash: {}".format(binary.authentihash_sha1.hex()))
print("Binary SHA-256 authentihash: {}".format(binary.authentihash_sha256.hex()))
for idx, sig in enumerate(binary.signatures):
process_signature(sig, args)
if args.ext_file_path:
path = args.ext_file_path
if idx > 0:
path += str(idx)
if not path.endswith(".p7b"):
path += ".p7b"
outpath = pathlib.Path(path)
outpath.write_bytes(sig.raw_der)
print("Signature saved to {}".format(outpath))
else:
# Try as a regular p7b signature
sig = lief.PE.Signature.parse(args.file)
if sig is None:
print("Fail to parse the signature")
sys.exit(1)
process_signature(sig, args)
if __name__ == "__main__":
main()
if HAS_EXCEPTION:
sys.exit(1)