Karol Desnos

73 papers A 2B 2C 8Misc 3Journal 18Unranked 38
YearRankTypeTitle / Venue / Authors
2025 conf
ICC Workshops
Alice Chillet, Robin Gerzaguet, Karol Desnos, Paul Bazerque, Erwan Nogues, Matthieu Gautier
2025 conf
AICAS
Mewe-Hezoudah Kahanam, Karol Desnos, Guillaume Fortier, Maxime Pelcat
2025 conf
SiPS
Jarlath Warner, John McAllister, Karol Desnos
2025 A conf
GECCO
Quentin Vacher, Stephen Kelly, Ali Naqvi, Nicolas Beuve, Tanya Djavaherpour, Mickaël Dardaillon, Karol Desnos
2024 J jnl
EURASIP J. Image Video Process.
Alban Marie, Karol Desnos, Alexandre Mercat, Luce Morin, Jarno Vanne, Lu Zhang
2024 conf
DASIP
Sunrise Wang, Nicolas Gac, Hugo Miomandre, Jean-François Nezan, Karol Desnos, François Orieux
2024 J jnl
J. Syst. Archit.
Ophélie Renaud, Hugo Miomandre, Karol Desnos, Jean-François Nezan
2024 book
Karol Desnos
2024 conf
ICC
Alice Chillet, Robin Gerzaguet, Karol Desnos, Matthieu Gautier, Elena Simona Lohan, Erwan Nogues, Mikko Valkama
2024 C conf
IJCCI
Quentin Vacher, Nicolas Beuve, Paul Allaire, Thibaut Marty, Mickaël Dardaillon, Karol Desnos
2024 conf
EUSIPCO
Ophélie Renaud, Karol Desnos, Erwan Raffin, Jean-François Nezan
2024 conf
SPA
Hubert Szolc, Karol Desnos, Tomasz Kryjak
2024 J jnl
CoRR
Hubert Szolc, Karol Desnos, Tomasz Kryjak
2024 J jnl
IEEE Open J. Commun. Soc.
Alice Chillet, Robin Gerzaguet, Karol Desnos, Matthieu Gautier, Elena Simona Lohan, Erwan Nogues, Mikko Valkama
2023 conf
EUSIPCO
Ophélie Renaud, Naouel Haggui, Karol Desnos, Jean-François Nezan
2023 B conf
QoMEX
Alban Marie, Karol Desnos, Luce Morin, Lu Zhang
2023 conf
DASIP
Ophélie Renaud, Dylan Gageot, Karol Desnos, Jean-François Nezan
2023 B conf
PIMRC
Alice Chillet, Baptiste Boyer, Robin Gerzaguet, Karol Desnos, Matthieu Gautier
2023 C conf
MMSP
Alban Marie, Karol Desnos, Chen Fu, Jinjia Zhou, Luce Morin, Lu Zhang
2022 ed.
DASIP
Karol Desnos, Sergio A. Pertuz
2022 conf
Image Processing: Algorithms and Systems
Alban Marie, Karol Desnos, Luce Morin, Lu Zhang
2022 conf
DASIP
Alexandre Honorat, Thomas Bourgoin, Hugo Miomandre, Karol Desnos, Daniel Ménard, Jean-François Nezan
2022 J jnl
J. Signal Process. Syst.
Nicolas Sourbier, Karol Desnos, Thomas Guyet, Frédéric Majorczyk, Olivier Gesny, Maxime Pelcat
2022 conf
SiPS
Karol Desnos, Thomas Bourgoin, Mickaël Dardaillon, Nicolas Sourbier, Olivier Gesny, Maxime Pelcat
2022 C conf
MMSP
Alban Marie, Karol Desnos, Luce Morin, Lu Zhang
2021 conf
DASIP
Karol Desnos, Nicolas Sourbier, Pierre-Yves Raumer, Olivier Gesny, Maxime Pelcat
2020 conf
SAMOS
Alexandre Honorat, Karol Desnos, Mickaël Dardaillon, Jean-François Nezan
2020 A conf
DATE
Justine Bonnot, Daniel Ménard, Karol Desnos
2020 J jnl
CoRR
Karol Desnos, Nicolas Sourbier, Pierre-Yves Raumer, Olivier Gesny, Maxime Pelcat
2020 J jnl
J. Signal Process. Syst.
Yaesop Lee, Yanzhou Liu, Karol Desnos, Lee Barford, Shuvra S. Bhattacharyya
2020 Misc conf
RTNS
Alexandre Honorat, Karol Desnos, Shuvra S. Bhattacharyya, Jean-François Nezan
2019 Misc conf
ICASSP
Justine Bonnot, Karol Desnos, Daniel Ménard
2019 conf
CF
Francesca Palumbo, Tiziana Fanni, Carlo Sau, Luca Pulina, Luigi Raffo, Michael Masin, Evgeny Shindin, Pablo Sanchez de Rojas, Karol Desnos, Maxime Pelcat, Alfonso Rodríguez, Eduardo Juárez, Francesco Regazzoni, Giuseppe Meloni, Katiuscia Zedda, Hans Myrhaug, Leszek Kaliciak, Joost Adriaanse, Julio de Oliveira Filho, Pablo Muñoz, Antonella Toffetti
2019 J jnl
Microprocess. Microsystems
Leonardo Suriano, Florian Arrestier, Alfonso Rodríguez, Julien Heulot, Karol Desnos, Maxime Pelcat, Eduardo de la Torre
2019 J jnl
IEEE Embed. Syst. Lett.
Claudio Rubattu, Francesca Palumbo, Carlo Sau, Rubén Salvador, Jocelyn Sérot, Karol Desnos, Luigi Raffo, Maxime Pelcat
2019 conf
SAMOS
Francesca Palumbo, Tiziana Fanni, Carlo Sau, Alfonso Rodríguez, Daniel Madroñal, Karol Desnos, Antoine Morvan, Maxime Pelcat, Claudio Rubattu, Raquel Lazcano, Luigi Raffo, Eduardo de la Torre, Eduardo Juárez, César Sanz, Pablo Sanchez de Rojas
2019 conf
SAMOS
Alexandre Honorat, Karol Desnos, Maxime Pelcat, Jean-François Nezan
2019 J jnl
ACM Trans. Embed. Comput. Syst.
Florian Arrestier, Karol Desnos, Eduardo Juárez, Daniel Ménard
2019 J jnl
IEEE Access
Daniel Madroñal, Florian Arrestier, Jaime Sancho, Antoine Morvan, Raquel Lazcano, Karol Desnos, Rubén Salvador, Daniel Ménard, Eduardo Juárez Martínez, César Sanz
2018 conf
HPEC
Julien Hascoet, Benoît Dupont de Dinechin, Karol Desnos, Jean-François Nezan
2018 conf
ACM Great Lakes Symposium on VLSI
Justine Bonnot, Karol Desnos, Maxime Pelcat, Daniel Ménard
2018 conf
SAMOS
Justine Bonnot, Karol Desnos, Daniel Ménard
2018 conf
CF
Daniel Madroñal, Antoine Morvan, Raquel Lazcano, Rubén Salvador, Karol Desnos, Eduardo Juárez Martínez, César Sanz
2018 conf
EUSIPCO
Justine Bonnot, Vincent Camus, Karol Desnos, Daniel Ménard
2018 J jnl
J. Signal Process. Syst.
Manel Ammar, Mouna Baklouti, Maxime Pelcat, Karol Desnos, Mohamed Abid
2018 conf
SAMOS
Florian Arrestier, Karol Desnos, Maxime Pelcat, Julien Heulot, Eduardo Juárez, Daniel Ménard
2018 conf
PARMA-DITAM@HiPEAC
Hugo Miomandre, Julien Hascoët, Karol Desnos, Kevin J. M. Martin, Benoît Dupont de Dinechin, Jean-François Nezan
2018 C conf
PDP
Hergys Rexha, Sébastien Lafond, Karol Desnos
2018 conf
MODELSWARD (Revised Selected Papers)
Andrea Enrici, Julien Lallet, Renaud Pacalet, Ludovic Apvrille, Karol Desnos, Imran Latif
2018 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Maxime Pelcat, Alexandre Mercat, Karol Desnos, Luca Maggiani, Yanzhou Liu, Julien Heulot, Jean-François Nezan, Wassim Hamidouche, Daniel Ménard, Shuvra S. Bhattacharyya
2018 C conf
ISCAS
Justine Bonnot, Karol Desnos, Daniel Ménard
2017 conf
ReCoSoC
Leonardo Suriano, Alfonso Rodríguez, Karol Desnos, Maxime Pelcat, Eduardo de la Torre
2017 conf
ASAP
Julien Hascoet, Karol Desnos, Jean-François Nezan, Benoît Dupont de Dinechin
2017 J jnl
J. Syst. Archit.
Raquel Lazcano, Daniel Madroñal, Rubén Salvador, Karol Desnos, Maxime Pelcat, Raúl Guerra, Himar Fabelo, Samuel Ortega, Sebastián López, Gustavo M. Callicó, Eduardo Juárez Martínez, César Sanz
2017 conf
SAMOS
Hamza Deroui, Karol Desnos, Jean-François Nezan, Alix Munier Kordon
2017 J jnl
J. Syst. Archit.
Alexandre Mercat, Justine Bonnot, Maxime Pelcat, Karol Desnos, Wassim Hamidouche, Daniel Ménard
2017 conf
SiPS
Georgios Georgakarakos, Sudeep Kanur, Johan Lilius, Karol Desnos
2017 C conf
ISCAS
Hamza Deroui, Karol Desnos, Jean-François Nezan, Alix Munier Kordon
2016 conf
SiPS
Karol Desnos, Maxime Pelcat, Jean-François Nezan, Slaheddine Aridhi
2016 conf
SiPS
Maxime Pelcat, Karol Desnos, Luca Maggiani, Yanzhou Liu, Julien Heulot, Jean-François Nezan, Shuvra S. Bhattacharyya
2016 C conf
WETICE
Manel Ammar, Mouna Baklouti, Maxime Pelcat, Karol Desnos, Mohamed Abid
2016 C conf
PDP
Manel Ammar, Mouna Baklouti, Maxime Pelcat, Karol Desnos, Mohamed Abid
2016 J jnl
ACM Trans. Embed. Comput. Syst.
Karol Desnos, Maxime Pelcat, Jean-François Nezan, Slaheddine Aridhi
2016 J jnl
J. Signal Process. Syst.
Zheng Zhou, William Plishker, Shuvra S. Bhattacharyya, Karol Desnos, Maxime Pelcat, Jean-François Nezan
2015 conf
SNPD (revised selected papers)
Manel Ammar, Mouna Baklouti, Maxime Pelcat, Karol Desnos, Mohamed Abid
2015 Misc conf
ICASSP
Karol Desnos, Maxime Pelcat, Jean-François Nezan, Slaheddine Aridhi
2015 J jnl
J. Signal Process. Syst.
Karol Desnos, Maxime Pelcat, Jean-François Nezan, Slaheddine Aridhi
2014 conf
ICITST
Karol Desnos, Safwan El Assad, Aurore Arlicot, Maxime Pelcat, Daniel Ménard
2014 conf
DASIP
Manel Ammar, Mouna Baklouti, Maxime Pelcat, Karol Desnos, Mohamed Abid
2013 conf
ICSAMOS
Karol Desnos, Maxime Pelcat, Jean-François Nezan, Shuvra S. Bhattacharyya, Slaheddine Aridhi
2013 conf
ISSoC
Zheng Zhou, Karol Desnos, Maxime Pelcat, Jean-François Nezan, William Plishker, Shuvra S. Bhattacharyya
2012 conf
DASIP
Julien Heulot, Karol Desnos, Jean-François Nezan, Maxime Pelcat, Mickaël Raulet, Hervé Yviquel, P.-L. Lagalaye, Jean-Christophe Le Lann
2012 conf
ICSAMOS
Karol Desnos, Maxime Pelcat, Jean-François Nezan, Slaheddine Aridhi
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'
        }