Cezary Biele

43 papers A* 2Journal 10Unranked 26
YearRankTypeTitle / Venue / Authors
2026 A* conf
CHI
Kinga H. Skorupska, Tomasz Omelan, Aleksander Hamerlik, Agata Kopacz, Daniel Cnotkowski, Jaroslaw Kowalski, Bartosz Muczynski, Radoslaw Nielek, Adam Wierzbicki, Cezary Biele
2025 J jnl
CoRR
Wieslaw Kopec, Jaroslaw Kowalski, Aleksander Majda, Anna Duszyk-Bogorodzka, Anna Jaskulska, Cezary Biele
2025 conf
INTERACT (4)
Jarosaw Kowalski, Kinga Skorupska, Bartosz Muczynski, Maciej Grzeszczuk, Zbigniew Bohdanowicz, Cezary Biele, Wieslaw Kopec
2024 ed.
MIDI
Cezary Biele, Janusz Kacprzyk, Wieslaw Kopec, Jakub Mozaryn, Jan W. Owsinski, Andrzej Romanowski, Marcin Sikorski
2024 J jnl
CoRR
Wieslaw Kopec, Grzegorz Pochwatko, Monika Kornacka, Wiktor Stawski, Maciej Grzeszczuk, Kinga Skorupska, Barbara Karpowicz, Rafal Maslyk, Pavlo Zinevych, Stanislaw Knapinski, Steven Barnes, Cezary Biele
2024 conf
CHIRA (2)
Jaroslaw Kowalski, Cezary Biele, Zbigniew Bohdanowicz
2023 conf
INTERACT (4)
Wieslaw Kopec, Monika Kornacka, Grzegorz Pochwatko, Cezary Biele, Anna Jaskulska, Kinga Skorupska, Steven Barnes, Maciej Grzeszczuk, Tommy Nilsson, Wladyslaw Fuchs, Jagoda Lazarek, Krzysztof Pijarski, Gabriel G. De la Torre
2023 ed.
MIDI
Cezary Biele, Janusz Kacprzyk, Wieslaw Kopec, Jan W. Owsinski, Andrzej Romanowski, Marcin Sikorski
2023 conf
CHI Extended Abstracts
Jaroslaw Kowalski, Kinga H. Skorupska, Agata Kopacz, Bartosz Muczynski, Wieslaw Kopec, Zbigniew Bohdanowicz, Gabriela Górska, Cezary Biele
2023 J jnl
CoRR
Jaroslaw Kowalski, Kinga Skorupska, Agata Kopacz, Bartosz Muczynski, Wieslaw Kopec, Zbigniew Bohdanowicz, Gabriela Górska, Cezary Biele
2023 conf
MIDI
Wieslaw Kopec, Grzegorz Pochwatko, Monika Kornacka, Wiktor Stawski, Maciej Grzeszczuk, Kinga Skorupska, Barbara Karpowicz, Rafal Maslyk, Pavlo Zinevych, Stanislaw Knapinski, Steven Barnes, Cezary Biele
2023 conf
MIDI
Grzegorz Banerski, Cezary Biele, Bartosz Muczynski, Daniel Cnotkowski
2023 conf
INTERACT (4)
Bartosz Muczynski, Kinga Skorupska, Katarzyna Abramczuk, Cezary Biele, Zbigniew Bohdanowicz, Daniel Cnotkowski, Jazmin Collins, Wieslaw Kopec, Jaroslaw Kowalski, Grzegorz Pochwatko, Thomas Logan
2023 J jnl
CoRR
Bartosz Muczynski, Kinga Skorupska, Katarzyna Abramczuk, Cezary Biele, Zbigniew Bohdanowicz, Daniel Cnotkowski, Jazmin Collins, Wieslaw Kopec, Jaroslaw Kowalski, Grzegorz Pochwatko, Thomas Logan
2022 ed.
MIDI
Cezary Biele, Janusz Kacprzyk, Wieslaw Kopec, Jan W. Owsinski, Andrzej Romanowski, Marcin Sikorski
2022 book
Cezary Biele
2022 J jnl
CoRR
Wieslaw Kopec, Cezary Biele, Monika Kornacka, Grzegorz Pochwatko, Anna Jaskulska, Kinga Skorupska, Julia Paluch, Piotr Gago, Barbara Karpowicz, Marcin Niewinski, Rafal Maslyk
2021 ed.
MIDI
Cezary Biele, Janusz Kacprzyk, Jan W. Owsinski, Andrzej Romanowski, Marcin Sikorski
2021 conf
MIDI
Piotr Toczyski, Grzegorz Banerski, Cezary Biele, Jaroslaw Kowalski, Michal B. Paradowski
2021 conf
CHI Extended Abstracts
Wieslaw Kopec, Jaroslaw Kowalski, Julia Paluch, Anna Jaskulska, Kinga H. Skorupska, Marcin Niewinski, Maciej Krzywicki, Cezary Biele
2021 J jnl
CoRR
Wieslaw Kopec, Jaroslaw Kowalski, Julia Paluch, Anna Jaskulska, Kinga Skorupska, Marcin Niewinski, Maciej Krzywicki, Cezary Biele
2021 conf
INTERACT (5)
Wieslaw Kopec, Cezary Biele, Monika Kornacka, Grzegorz Pochwatko, Anna Jaskulska, Kinga Skorupska, Julia Paluch, Piotr Gago, Barbara Karpowicz, Marcin Niewinski, Rafal Maslyk
2021 conf
INTERACT (5)
Julio Abascal, Cezary Biele, Daniel Cnotkowski, Gabriela Górska, Jaroslaw Kowalski, Effie Lai-Chong Law, Bartosz Muczynski, Abiodun Afolayan Ogunyemi, Mariusz Wierzbowski, Aldona Zdrodowska
2020 conf
MIDI
Anna Jaskulska, Kinga Skorupska, Barbara Karpowicz, Cezary Biele, Jaroslaw Kowalski, Wieslaw Kopec
2020 J jnl
CoRR
Anna Jaskulska, Kinga Skorupska, Barbara Karpowicz, Cezary Biele, Jaroslaw Kowalski, Wieslaw Kopec
2020 conf
MIDI
Zbigniew Bohdanowicz, Jaroslaw Kowalski, Daniel Cnotkowski, Agata Kopacz, Cezary Biele
2019 conf
IHSI
Cezary Biele, Anna Jaskulska, Wieslaw Kopec, Jaroslaw Kowalski, Kinga Skorupska, Aldona Zdrodowska
2019 conf
IHSED
Zbigniew Bohdanowicz, Jaroslaw Kowalski, Katarzyna Abramczuk, Grzegorz Banerski, Daniel Cnotkowski, Agata Kopacz, Pawel Kobylinski, Aldona Zdrodowska, Cezary Biele
2019 conf
CHI Extended Abstracts
Jaroslaw Kowalski, Anna Jaskulska, Kinga Skorupska, Katarzyna Abramczuk, Cezary Biele, Wieslaw Kopec, Krzysztof Marasek
2019 J jnl
CoRR
Jaroslaw Kowalski, Anna Jaskulska, Kinga Skorupska, Katarzyna Abramczuk, Cezary Biele, Wieslaw Kopec, Krzysztof Marasek
2019 conf
IHSI
Jaroslaw Kowalski, Cezary Biele, Kazimierz Krzysztofek
2019 conf
IHSI
Pawel Kobylinski, Grzegorz Pochwatko, Cezary Biele
2019 J jnl
CoRR
Wieslaw Kopec, Marcin Wichrowski, Krzysztof Kalinowski, Anna Jaskulska, Kinga Skorupska, Daniel Cnotkowski, Jakub Tyszka, Agata Popieluch, Anna Voitenkova, Rafal Maslyk, Piotr Gago, Maciej Krzywicki, Monika Kornacka, Cezary Biele, Pawel Kobylinski, Jaroslaw Kowalski, Katarzyna Abramczuk, Aldona Zdrodowska, Grzegorz Pochwatko, Jakub Mozaryn, Krzysztof Marasek
2018 J jnl
CoRR
Wieslaw Kopec, Marcin Skibinski, Cezary Biele, Kinga Skorupska, Dominika Tkaczyk, Anna Jaskulska, Katarzyna Abramczuk, Piotr Gago, Krzysztof Marasek
2018 conf
IHSI
Pawel Kobylinski, Mariusz Wierzbowski, Cezary Biele
2018 conf
IHSED
Katarzyna Abramczuk, Michal Kakol, Radoslaw Nielek, Cezary Biele
2018 conf
FedCSIS (Position Papers)
Jaroslaw Kowalski, Piotr Toczyski, Cezary Biele, Aldona Zdrodowska
2018 conf
IHSI
Jaroslaw Kowalski, Cezary Biele, Marek Mlodozeniec, Marcel Geers
2018 conf
IHSI
Cezary Biele, Pawel Kobylinski
2018 A* conf
CHI
Andrew T. Duchowski, Krzysztof Krejtz, Izabela Krejtz, Cezary Biele, Anna Niedzielska, Peter Kiefer, Martin Raubal, Ioannis Giannopoulos
2017 conf
KES-IDT (2)
Cezary Biele, Dominik Chrzastowski-Wachtel, Marek Mlodozeniec, Anna Niedzielska, Jaroslaw Kowalski, Pawel Kobylinski, Krzysztof Krejtz, Andrew T. Duchowski
2014 conf
UbiComp Adjunct
Krzysztof Krejtz, Cezary Biele, Dominik Chrzastowski, Agata Kopacz, Anna Niedzielska, Piotr Toczyski, Andrew T. Duchowski
2013 conf
MIDI
Cezary Biele, Agata Kopacz, Krzysztof Krejtz
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'
        }