Vincenzo Ciancia

84 papers B 8C 6Journal 33Unranked 35
YearRankTypeTitle / Venue / Authors
2026 B conf
FASE
Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2026 J jnl
Log. Methods Comput. Sci.
Nick Bezhanishvili, Laura Bussi, Vincenzo Ciancia, David Gabelaia, Mamuka Jibladze, Diego Latella, Mieke Massink, Erik P. de Vink
2025 J jnl
CoRR
Manuela Imbriani, Gina Belmonte, Mieke Massink, Alessandro Tofani, Vincenzo Ciancia
2025 J jnl
Log. Methods Comput. Sci.
Vincenzo Ciancia, Diego Latella, Mieke Massink, Erik P. de Vink
2025 J jnl
CoRR
Yuri Andriaccio, Vincenzo Ciancia, Diego Latella, Mieke Massink
2025 J jnl
Artif. Intell. Medicine
Gina Belmonte, Vincenzo Ciancia, Mieke Massink
2025 conf
Rebeca for Actor Analysis in Action
Vincenzo Ciancia, Diego Latella, Mieke Massink
2024 B conf
AiML
Nick Bezhanishvili, Laura Bussi, Vincenzo Ciancia, David Fernández-Duque, David Gabelaia
2024 J jnl
CoRR
Nick Bezhanishvili, Laura Bussi, Vincenzo Ciancia, David Fernández-Duque, David Gabelaia
2024 conf
ISoLA (4)
Gina Belmonte, Laura Bussi, Vincenzo Ciancia, Diego Latella, Mieke Massink
2024 J jnl
CoRR
Nick Bezhanishvili, Laura Bussi, Vincenzo Ciancia, David Gabelaia, Mamuka Jibladze, Diego Latella, Mieke Massink, Erik P. de Vink
2024 C conf
FORTE
Nick Bezhanishvili, Vincenzo Ciancia, David Gabelaia, Mamuka Jibladze, Diego Latella, Mieke Massink, Erik P. de Vink
2024 J jnl
CoRR
Nick Bezhanishvili, Vincenzo Ciancia, David Gabelaia, Mamuka Jibladze, Diego Latella, Mieke Massink, Erik P. de Vink
2023 conf
DaLí
Laura Bussi, Vincenzo Ciancia, Fabio Gadducci
2023 J jnl
Int. J. Softw. Tools Technol. Transf.
Davide Basile, Maurice H. ter Beek, Laura Bussi, Vincenzo Ciancia
2023 B conf
FM
Vincenzo Ciancia, Jan Friso Groote, Diego Latella, Mieke Massink, Erik P. de Vink
2023 C conf
FORTE
Vincenzo Ciancia, David Gabelaia, Diego Latella, Mieke Massink, Erik P. de Vink
2023 J jnl
CoRR
Vincenzo Ciancia, Diego Latella, Mieke Massink, Erik P. de Vink
2022 conf
ISoLA (3)
Davide Basile, Maurice H. ter Beek, Vincenzo Ciancia
2022 conf
A Journey from Process Algebra via Timed Automata to Model Learning
Vincenzo Ciancia, Diego Latella, Mieke Massink, Erik P. de Vink
2022 J jnl
Log. Methods Comput. Sci.
Nick Bezhanishvili, Vincenzo Ciancia, David Gabelaia, Gianluca Grilletti, Diego Latella, Mieke Massink
2022 conf
ISoLA (1)
Laura Bussi, Vincenzo Ciancia, Fabio Gadducci, Diego Latella, Mieke Massink
2022 conf
HCI (38)
Giovanna Broccia, Vincenzo Ciancia, Diego Latella, Mieke Massink
2021 conf
SPIN
Vincenzo Ciancia, Gina Belmonte, Diego Latella, Mieke Massink
2021 conf
FormaliSE@ICSE
Gina Belmonte, Giovanna Broccia, Vincenzo Ciancia, Diego Latella, Mieke Massink
2021 J jnl
CoRR
Nick Bezhanishvili, Vincenzo Ciancia, David Gabelaia, Gianluca Grilletti, Diego Latella, Mieke Massink
2021 J jnl
CoRR
Vincenzo Ciancia, Diego Latella, Mieke Massink, Erik P. de Vink
2021 conf
MEDI Workshops
Gina Belmonte, Giovanna Broccia, Laura Bussi, Vincenzo Ciancia, Diego Latella, Mieke Massink
2021 C conf
FMICS
Maurice H. ter Beek, Vincenzo Ciancia, Diego Latella, Mieke Massink, Giorgio Oronzo Spagnolo
2021 conf
DataMod
Laura Bussi, Vincenzo Ciancia, Fabio Gadducci, Diego Latella, Mieke Massink
2021 C conf
FORTE
Laura Bussi, Vincenzo Ciancia, Fabio Gadducci
2020 J jnl
CoRR
Laura Bussi, Vincenzo Ciancia, Fabio Gadducci
2020 J jnl
Int. J. Softw. Tools Technol. Transf.
Fabrizio Banci Buonamici, Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2020 J jnl
CoRR
Vincenzo Ciancia, Diego Latella, Mieke Massink, Erik P. de Vink
2020 J jnl
CoRR
Gina Belmonte, Giovanna Broccia, Vincenzo Ciancia, Diego Latella, Mieke Massink
2019 conf
Models, Languages, and Tools for Concurrent and Distributed Programming
Vincenzo Ciancia, Diego Latella, Mieke Massink
2019 conf
From Software Engineering to Formal Methods and Tools, and Back
Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2019 B conf
CALCO
Vincenzo Ciancia, Yde Venema
2019 conf
TACAS (1)
Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2019 J jnl
ERCIM News
Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2018 J jnl
Log. Methods Comput. Sci.
Laura Nenzi, Luca Bortolussi, Vincenzo Ciancia, Michele Loreti, Mieke Massink
2018 J jnl
CoRR
Fabrizio Banci Buonamici, Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2018 J jnl
Int. J. Softw. Tools Technol. Transf.
Vincenzo Ciancia, Stephen Gilmore, Gianluca Grilletti, Diego Latella, Michele Loreti, Mieke Massink
2018 conf
ISoLA (2)
Davide Basile, Maurice H. ter Beek, Vincenzo Ciancia
2018 J jnl
CoRR
Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2017 J jnl
J. Log. Algebraic Methods Program.
Tommaso Bolognesi, Vincenzo Ciancia
2017 J jnl
CoRR
Laura Nenzi, Luca Bortolussi, Vincenzo Ciancia, Michele Loreti, Mieke Massink
2016 conf
ISoLA (1)
Vincenzo Ciancia, Diego Latella, Mieke Massink, Rytis Paskauskas, Andrea Vandin
2016 conf
FORECAST@STAF
Gina Belmonte, Vincenzo Ciancia, Diego Latella, Mieke Massink
2016 J jnl
Log. Methods Comput. Sci.
Vincenzo Ciancia, Diego Latella, Michele Loreti, Mieke Massink
2016 conf
ICE
Tommaso Bolognesi, Vincenzo Ciancia
2016 C conf
COORDINATION
Vincenzo Ciancia, Diego Latella, Mieke Massink
2016 conf
SFM
Vincenzo Ciancia, Diego Latella, Michele Loreti, Mieke Massink
2015 conf
SEFM Workshops
Vincenzo Ciancia, Gianluca Grilletti, Diego Latella, Michele Loreti, Mieke Massink
2015 conf
SASO Workshops
Vincenzo Ciancia, Diego Latella, Mieke Massink, Rytis Paskauskas
2015 conf
HaPoC
Vincenzo Ciancia
2015 B conf
RV
Laura Nenzi, Luca Bortolussi, Vincenzo Ciancia, Michele Loreti, Mieke Massink
2014 conf
TGC
Vincenzo Ciancia, Matteo Sammartino
2014 J jnl
ERCIM News
Maurice H. ter Beek, Luca Bortolussi, Vincenzo Ciancia, Stefania Gnesi, Jane Hillston, Diego Latella, Mieke Massink
2014 J jnl
Int. J. Secur. Softw. Eng.
Vincenzo Ciancia, José Antonio Martín, Fabio Martinelli, Ilaria Matteucci, Marinella Petrocchi, Ernesto Pimentel
2014 conf
SASO Workshops
Vincenzo Ciancia, Stephen Gilmore, Diego Latella, Michele Loreti, Mieke Massink
2014 J jnl
CoRR
Vincenzo Ciancia, Diego Latella, Michele Loreti, Mieke Massink
2014 conf
IFIP TCS
Vincenzo Ciancia, Diego Latella, Michele Loreti, Mieke Massink
2013 J jnl
CoRR
Vincenzo Ciancia, Matteo Sammartino
2013 B conf
ARES
Vincenzo Ciancia, Fabio Martinelli, Ilaria Matteucci, Marinella Petrocchi, José Antonio Martín, Ernesto Pimentel
2013 B conf
CALCO
Vincenzo Ciancia
2013 conf
FPS
Vincenzo Ciancia, Fabio Martinelli, Ilaria Matteucci, Charles Morisset
2012 J jnl
J. Autom. Reason.
Filippo Bonchi, Maria Grazia Buscemi, Vincenzo Ciancia, Fabio Gadducci
2012 conf
MDsec@MoDELS
Vincenzo Ciancia, Fabio Martinelli, Ilaria Matteucci, Marinella Petrocchi, José Antonio Martín, Ernesto Pimentel
2012 J jnl
CoRR
Vincenzo Ciancia
2012 conf
CMCS
Vincenzo Ciancia, Yde Venema
2011 B conf
FoSSaCS
Murdoch James Gabbay, Vincenzo Ciancia
2011 conf
ICE
Vincenzo Ciancia
2011 ch.
Results of the SENSORIA Project
Vincenzo Ciancia, Gian-Luigi Ferrari, Roberto Guanciale, Daniele Strollo, Emilio Tuosto
2010 J jnl
Sci. Comput. Program.
Vincenzo Ciancia, Gian-Luigi Ferrari, Roberto Guanciale, Daniele Strollo
2010 conf
CMCS@ETAPS
Vincenzo Ciancia, Alexander Kurz, Ugo Montanari
2010 J jnl
Inf. Comput.
Vincenzo Ciancia, Ugo Montanari
2008 conf
Concurrency, Graphs and Models
Filippo Bonchi, Maria Grazia Buscemi, Vincenzo Ciancia, Fabio Gadducci
2008 conf
CMCS
Vincenzo Ciancia, Ugo Montanari
2008
Vincenzo Ciancia
2008 C conf
FORTE
Vincenzo Ciancia, Gian-Luigi Ferrari, Roberto Guanciale, Daniele Strollo
2008 conf
FACS
Vincenzo Ciancia, Gian-Luigi Ferrari, Roberto Guanciale, Daniele Strollo
2008 conf
Concurrency, Graphs and Models
Vincenzo Ciancia, Gian-Luigi Ferrari, Marco Pistore, Emilio Tuosto
2007 conf
QAPL
Vincenzo Ciancia, Gian-Luigi Ferrari
redb/extractors/pe_extractors/pe_signature.py
← Index redb/extractors/pe_extractors/pe_signature.py python
import inspect
import yara_x
from datetime import datetime, timezone
from signify.authenticode import SignedPEFile
from typing import Any, Dict, List, Tuple

from redb.extractors.enum import Tag
from redb.extractors.pe_extractor import PEExtractor
from redb.models.dataclasses import PECertificate, PESigner, PECodeSigningInfo


class PESignatureExtractor(PEExtractor):
    """
    RFC 3161 - Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)
    Section 2.4.2 defines the TSTInfo structure.
    https://tools.ietf.org/html/rfc3161#section-2.4.2

    Microsoft Authenticode Time Stamping Specification
    https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
    """

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        pe=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious,
            pe,
        )
        self.elastic_index = self.index_prefix + "-pe_signature"
        self.log.debug(inspect.currentframe().f_code.co_name)
        self.code_signing_info = None

    def tag(self):
        return [Tag.PE_CERTIFICATE.value, Tag.PE_SIGNER.value, Tag.PE_SIGNATURE.value]

    def _extract_certificate_info(self, certificate):
        self.log.debug(inspect.currentframe().f_code.co_name)

        # YARA-X returns datetime objects directly, not Unix timestamps
        not_before = certificate["not_before"]
        not_after = certificate["not_after"]

        # Handle both datetime objects and Unix timestamps for compatibility
        if isinstance(not_before, datetime):
            valid_from = not_before.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_from = datetime.fromtimestamp(int(not_before), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        if isinstance(not_after, datetime):
            valid_to = not_after.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_to = datetime.fromtimestamp(int(not_after), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        return PECertificate(
            certificate_serial_number=certificate["serial"],
            certificate_subject=certificate["subject"],
            certificate_issuer=certificate["issuer"],
            certificate_valid_from=valid_from,
            certificate_valid_to=valid_to,
            certificate_thumbprint=certificate["thumbprint"].upper(),
            certificate_algorithm=certificate["algorithm"],
        )

    def _extract_signer_info(self, signer):
        self.log.debug(inspect.currentframe().f_code.co_name)

        # YARA-X returns datetime objects directly, not Unix timestamps
        not_before = signer["not_before"]
        not_after = signer["not_after"]

        # Handle both datetime objects and Unix timestamps for compatibility
        if isinstance(not_before, datetime):
            valid_from = not_before.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_from = datetime.fromtimestamp(int(not_before), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        if isinstance(not_after, datetime):
            valid_to = not_after.strftime("%Y-%m-%d %H:%M:%S")
        else:
            valid_to = datetime.fromtimestamp(int(not_after), timezone.utc).strftime("%Y-%m-%d %H:%M:%S")

        return PESigner(
            signer_serial_number=signer["serial"],
            signer_subject=signer["subject"],
            signer_issuer=signer["issuer"],
            signer_valid_from=valid_from,
            signer_valid_to=valid_to,
            signer_thumbprint=signer["thumbprint"].upper(),
            signer_algorithm=signer["algorithm"],
        )

    def _extract_signature_info(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        pe_rules = """
            import "pe"
            rule is_pe {
                condition: 
                    pe.is_pe
            }
        """
        rule = yara_x.compile(pe_rules)
        results = rule.scan(self.binary)
        yara_output = results.module_outputs

        signature_info = yara_output["pe"]["signatures"][0]
        number_of_certificates = signature_info["number_of_certificates"]
        signature_verified = signature_info["verified"]
        self.code_signing_info = PECodeSigningInfo(
            _id=self.sha256,
            signature_verified=signature_verified,
            number_of_certificates=int(number_of_certificates),
        )

        keys = signature_info.keys()
        if "certificates" in keys:
            self.log.debug("Extracting PE Signing Certificates")
            certificates = signature_info["certificates"]
            certificates_list = []
            for cert in certificates:
                cert_info = self._extract_certificate_info(cert)
                certificates_list.append(cert_info)
            self.code_signing_info.x509_certificates = certificates_list

        if "signer_info" in keys:
            self.log.debug("Extracting PE Signing Signer Info")
            signers = signature_info["signer_info"]["chain"]
            signers_list = []
            for signer in signers:
                sig = self._extract_signer_info(signer)
                signers_list.append(sig)
            self.code_signing_info.signers = signers_list

        if "countersignatures" in keys:
            self.log.debug("Extracting PE Signing Countersignatures")
            countersignatures = signature_info["countersignatures"][0]["chain"]
            countersigners_list = []
            for csigner in countersignatures:
                csig = self._extract_signer_info(csigner)
                countersigners_list.append(csig)
            self.code_signing_info.countersigners = countersigners_list

        with open(self.filepath, "rb") as f:
            self.log.debug("Extracting PE Signing spcSpOpusInfo")
            sig_pefile = SignedPEFile(f)
            try:
                spc_opusinfo = {}
                for signed_data in sig_pefile.signed_datas:
                    spc_opusinfo["ProgramName"] = signed_data.signer_info.program_name
                    spc_opusinfo["MoreInfo"] = signed_data.signer_info.more_info
                    self.code_signing_info.spcSpOpusInfo = spc_opusinfo

                    if signed_data.signer_info.countersigner is not None:
                        stime = signed_data.signer_info.countersigner.signing_time
                        self.code_signing_info.date_signed = stime.strftime(
                            "%Y-%m-%d %H:%M:%S"
                        )
            except Exception as e:
                self.log.error(
                    f"Error while extracting spcSpOpusInfo or signing date: {e}"
                )

    def extract(self):
        try:
            self.log.debug(inspect.currentframe().f_code.co_name)
            if self._is_signed():
                self._extract_signature_info()
                # self.export_to_elastic([self.code_signing_info])
                return self.code_signing_info
            return None
        except Exception as e:
            self.log.error(f"Error extracting PE Signature: {e}")
            return None

    # def prepare_export_data(self, exporter_type: str) -> Any:
    #     self.log.debug(inspect.currentframe().f_code.co_name)
    #     if exporter_type == "ElasticsearchExporter":
    #         return self.extract()
    #     elif exporter_type == "ClickHouseExporter":
    #         signing_info = self.extract()
    #         if signing_info is None:
    #             return None
                
    #         current_time = datetime.now(timezone.utc)
            
    #         # Prepare data for redb_pe_signatures table
    #         signatures_data = [[
    #             self.sha256,                                    # sha256
    #             self.md5,                                       # md5
    #             self.sha1,                                      # sha1
    #             signing_info.signature_verified,                # signature_verified
    #             datetime.strptime(signing_info.date_signed, "%Y-%m-%d %H:%M:%S") if signing_info.date_signed else None,  # date_signed
    #             signing_info.number_of_certificates,            # number_of_certificates
    #             signing_info.spcSpOpusInfo.get('ProgramName', None) if signing_info.spcSpOpusInfo else None,  # program_name
    #             signing_info.spcSpOpusInfo.get('MoreInfo', None) if signing_info.spcSpOpusInfo else None,    # more_info
    #             current_time                                    # analysis_date
    #         ]]

    #         certificates_data = []
            
    #         # Process signers
    #         if signing_info.signers:
    #             for signer in signing_info.signers:
    #                 certificates_data.append(self._prepare_certificate_data(signer, 'signer', current_time))
            
    #         # Process countersigners
    #         if signing_info.countersigners:
    #             for csigner in signing_info.countersigners:
    #                 certificates_data.append(self._prepare_certificate_data(csigner, 'countersigner', current_time))
            
    #         # Process x509 certificates
    #         if signing_info.x509_certificates:
    #             for cert in signing_info.x509_certificates:
    #                 certificates_data.append(self._prepare_certificate_data(cert, 'chain', current_time))
            
    #         return {
    #             'multi_table': True,
    #             'signatures': {
    #                 'table': 'redb_pe_signatures',
    #                 'data': signatures_data,
    #                 'column_names': [
    #                     'sha256', 'md5', 'sha1', 'signature_verified', 'date_signed',
    #                     'number_of_certificates', 'spcSpOpusInfo_program_name', 'spcSpOpusInfo_more_info', 'analysis_date'
    #                 ],
    #                 'column_type_names': [
    #                     'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
    #                     'Boolean', 'DateTime64(3, \'UTC\')', 'UInt8',
    #                     'Nullable(String)', 'Nullable(String)', 'DateTime64(3, \'UTC\')'
    #                 ]
    #             },
    #             'certificates': {
    #                 'table': 'redb_pe_certificates',
    #                 'data': certificates_data,
    #                 'column_names': [
    #                     'sha256', 'md5', 'sha1', 'certificate_type', 'certificate_algorithm',
    #                     'certificate_issuer', 'certificate_subject', 'certificate_serial_number',
    #                     'certificate_thumbprint', 'certificate_valid_from', 'certificate_valid_to',
    #                     'analysis_date'
    #                 ],
    #                 'column_type_names': [
    #                     'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
    #                     'Enum(\'signer\', \'countersigner\', \'chain\')', 'LowCardinality(String)',
    #                     'LowCardinality(String)', 'LowCardinality(String)', 'String',
    #                     'String', 'DateTime64(3, \'UTC\')', 'DateTime64(3, \'UTC\')',
    #                     'DateTime64(3, \'UTC\')'
    #                 ]
    #             }
    #         }

    # def _prepare_certificate_data(self, cert, cert_type: str, analysis_time: datetime) -> List:
    #     """Helper method to prepare certificate data for ClickHouse"""
    #     self.log.debug(inspect.currentframe().f_code.co_name)
    #     prefix = "certificate_" if hasattr(cert, "certificate_algorithm") else "signer_"
        
    #     # Get serial number and clean it up
    #     serial_number = getattr(cert, f"{prefix}serial_number")
    #     if serial_number:
    #         serial_number = serial_number.replace(':', '')
        
    #     return [
    #         self.sha256,                          # sha256
    #         self.md5,                             # md5
    #         self.sha1,                            # sha1
    #         cert_type,                            # certificate_type
    #         getattr(cert, f"{prefix}algorithm"),   # certificate_algorithm
    #         getattr(cert, f"{prefix}issuer"),     # certificate_issuer
    #         getattr(cert, f"{prefix}subject"),    # certificate_subject
    #         serial_number,                        # certificate_serial_number
    #         getattr(cert, f"{prefix}thumbprint"),  # certificate_thumbprint
    #         datetime.strptime(getattr(cert, f"{prefix}valid_from"), "%Y-%m-%d %H:%M:%S"),  # certificate_valid_from
    #         datetime.strptime(getattr(cert, f"{prefix}valid_to"), "%Y-%m-%d %H:%M:%S"),    # certificate_valid_to
    #         analysis_time                         # analysis_date
    #     ]
    def prepare_export_data(self, exporter_type: str) -> Any:
        self.log.debug(inspect.currentframe().f_code.co_name)
        if exporter_type == "ElasticsearchExporter":
            return self.extract()
        elif exporter_type == "ClickHouseExporter":
            signing_info = self.extract()
            if signing_info is None:
                return None
                
            current_time = datetime.now(timezone.utc)
            
            # Prepare data for redb_pe_signatures table
            signatures_data = [[
                self.sha256,                                    # sha256
                self.md5,                                       # md5
                self.sha1,                                      # sha1
                signing_info.signature_verified,                # signature_verified
                datetime.strptime(signing_info.date_signed, "%Y-%m-%d %H:%M:%S") if signing_info.date_signed else None,  # date_signed
                signing_info.number_of_certificates,            # number_of_certificates
                signing_info.spcSpOpusInfo.get('ProgramName', None) if signing_info.spcSpOpusInfo else None,  # program_name
                signing_info.spcSpOpusInfo.get('MoreInfo', None) if signing_info.spcSpOpusInfo else None,    # more_info
                current_time                                    # analysis_date
            ]]

            # Prepare data for redb_pe_certificates table
            certificates_data = []
            
            # Process signers
            if signing_info.signers:
                for signer in signing_info.signers:
                    certificates_data.append(self._prepare_certificate_data(signer, 'signer', current_time))
            
            # Process countersigners
            if signing_info.countersigners:
                for csigner in signing_info.countersigners:
                    certificates_data.append(self._prepare_certificate_data(csigner, 'countersigner', current_time))
            
            # Process x509 certificates
            if signing_info.x509_certificates:
                for cert in signing_info.x509_certificates:
                    certificates_data.append(self._prepare_certificate_data(cert, 'chain', current_time))
            
            return {
                'multi_table': True,
                'signatures': {
                    'table': 'redb_pe_signatures',
                    'data': signatures_data,
                    'column_names': [
                        'sha256', 'md5', 'sha1', 'signature_verified', 'date_signed',
                        'number_of_certificates', 'spcSpOpusInfo_program_name', 'spcSpOpusInfo_more_info', 'analysis_date'
                    ],
                    'column_type_names': [
                        'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
                        'Boolean', 'DateTime64(3, \'UTC\')', 'UInt8',
                        'Nullable(String)', 'Nullable(String)', 'DateTime64(3, \'UTC\')'
                    ]
                },
                'certificates': {
                    'table': 'redb_pe_certificates',
                    'data': certificates_data,
                    'column_names': [
                        'sha256', 'md5', 'sha1', 'certificate_type', 'certificate_algorithm',
                        'certificate_issuer', 'certificate_subject', 'certificate_serial_number',
                        'certificate_thumbprint', 'certificate_valid_from', 'certificate_valid_to',
                        'analysis_date'
                    ],
                    'column_type_names': [
                        'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
                        'Enum8(\'signer\' = 1, \'countersigner\' = 2, \'chain\' = 3)', 'LowCardinality(String)',
                        'LowCardinality(String)', 'LowCardinality(String)', 'String',
                        'String', 'DateTime64(3, \'UTC\')', 'DateTime64(3, \'UTC\')',
                        'DateTime64(3, \'UTC\')'
                    ]
                }
            }

    # def _prepare_certificate_data(self, cert, cert_type: str, analysis_time: datetime) -> List:
    #     """Helper method to prepare certificate data for ClickHouse"""
    #     self.log.debug(inspect.currentframe().f_code.co_name)
    #     prefix = "certificate_" if hasattr(cert, "certificate_algorithm") else "signer_"
        
    #     # Get serial number and clean it up - with strict handling
    #     serial_number = getattr(cert, f"{prefix}serial_number", "UNKNOWN")
    #     if not serial_number or not str(serial_number).strip():
    #         serial_number = "UNKNOWN"
    #     else:
    #         serial_number = serial_number.replace(':', '')
    #         if not serial_number.strip():  # Double check after cleaning
    #             serial_number = "UNKNOWN"
        
    #     return [
    #         self.sha256,                          # sha256
    #         self.md5,                             # md5
    #         self.sha1,                            # sha1
    #         cert_type,                            # certificate_type
    #         getattr(cert, f"{prefix}algorithm"),   # certificate_algorithm
    #         getattr(cert, f"{prefix}issuer"),     # certificate_issuer
    #         getattr(cert, f"{prefix}subject"),    # certificate_subject
    #         serial_number,                        # certificate_serial_number
    #         getattr(cert, f"{prefix}thumbprint"),  # certificate_thumbprint
    #         datetime.strptime(getattr(cert, f"{prefix}valid_from"), "%Y-%m-%d %H:%M:%S"),  # certificate_valid_from
    #         datetime.strptime(getattr(cert, f"{prefix}valid_to"), "%Y-%m-%d %H:%M:%S"),    # certificate_valid_to
    #         analysis_time                         # analysis_date
    #     ]

    def _prepare_certificate_data(self, cert, cert_type: str, analysis_time: datetime) -> List:
        """Helper method to prepare certificate data for ClickHouse"""
        self.log.debug(inspect.currentframe().f_code.co_name)
        prefix = "certificate_" if hasattr(cert, "certificate_algorithm") else "signer_"
        
        def clean_string(value, field_name):
            if value is None or (isinstance(value, str) and not value.strip()):
                self.log.warning(f"Empty or None value found for {field_name}")
                return "UNKNOWN"
            return str(value).strip()
        
        try:
            serial_number = getattr(cert, f"{prefix}serial_number", "UNKNOWN")
            serial_number = clean_string(serial_number, "serial_number")
            if serial_number != "UNKNOWN":
                serial_number = serial_number.replace(':', '')
        
            return [
                clean_string(self.sha256, "sha256"),
                clean_string(self.md5, "md5"),
                clean_string(self.sha1, "sha1"),
                cert_type,
                clean_string(getattr(cert, f"{prefix}algorithm"), "algorithm"),
                clean_string(getattr(cert, f"{prefix}issuer"), "issuer"),
                clean_string(getattr(cert, f"{prefix}subject"), "subject"),
                serial_number,
                clean_string(getattr(cert, f"{prefix}thumbprint"), "thumbprint"),
                datetime.strptime(getattr(cert, f"{prefix}valid_from"), "%Y-%m-%d %H:%M:%S"),
                datetime.strptime(getattr(cert, f"{prefix}valid_to"), "%Y-%m-%d %H:%M:%S"),
                analysis_time
            ]
        except Exception as e:
            self.log.error(f"Error preparing certificate data: {str(e)}")
            self.log.error(f"Certificate data that caused error: {cert}")
            raise

    def get_clickhouse_table(self) -> str:
        """Required by PEExtractor abstract base class"""
        return "redb_pe_signatures"  # Return the primary table

    def get_clickhouse_tables(self) -> Dict[str, str]:
        """Additional method for multi-table support"""
        return {
            'signatures': 'redb_pe_signatures',
            'certificates': 'redb_pe_certificates'
        }