Xiaohan Sun

79 papers A 1C 4Journal 57Unranked 17
YearRankTypeTitle / Venue / Authors
2026 J jnl
IACR Cryptol. ePrint Arch.
Xiaohan Sun, Hao Lei, Longxiang Wei, Xiaokang Qi, Kai Hu, Meiqin Wang, Wei Wang
2026 J jnl
IACR Cryptol. ePrint Arch.
Xiaokang Qi, Hao Lei, Longxiang Wei, Xiaohan Sun, Meiqin Wang
2026 J jnl
IACR Trans. Symmetric Cryptol.
Xiaokang Qi, Hao Lei, Longxiang Wei, Xiaohan Sun, Meiqin Wang
2026 J jnl
IACR Cryptol. ePrint Arch.
Longxiang Wei, Hao Lei, Xiaokang Qi, Xiaohan Sun, Lei Gao, Kai Hu, Wei Wang, Meiqin Wang
2026 J jnl
Comput. Biol. Chem.
Dongmei Yu, Jiajia Li, Wenjing Ma, Yue Pei, Yingchao Qi, Tong Yu, Wenkai Li, Xiaohan Sun, Jingyan Zhang, Xuantonghe Li, Longyan Liang, Yunen Liu, Yichen Wang
2025 J jnl
CoRR
Xiaohan Sun, Yinghan Xu, John Dingliana, Carol O'Sullivan
2025 conf
VR Workshops
Xiaohan Sun, Yinghan Xu, John Dingliana, Carol O'Sullivan
2025 J jnl
CoRR
Xiaohan Sun, Yinghan Xu, John Dingliana, Carol O'Sullivan
2025 J jnl
Entropy
Xiaohan Sun, Shaoxiang Zhu, Anlin Li
2025 A conf
ECAI
Zheng Jiang, Haonan Kang, Zifeng Wu, Wei Wang, Gaowei Zhang, Eerdun Hasi, Xiaohan Sun, Yi Wang
2025 J jnl
CoRR
Xiaohan Sun, Carol O'Sullivan
2024 J jnl
Sensors
Xiaohan Sun, Yuan Ren, Linghui Yu
2024 J jnl
IEEE Access
Na Dong, Emily Johnson, Rolando Berlinguer Palmini, Hongze Zhong, Fahimeh Dehkhoda, Ahmed Soltan, Konstantin Nikolic, Nir Grossman, Johannes Gausden, Richard Bailey, Anthony O'Neill, Andrew Jackson, Andrew J. Trevelyan, Patrick Degenaar, Xiaohan Sun
2024 J jnl
J. Chem. Inf. Model.
Fangrui Hu, Fubin Chang, Lianci Tao, Xiaohan Sun, Lamei Liu, Yingchun Zhao, Zhongjie Han, Chunhua Li
2024 J jnl
J. Chem. Inf. Model.
Fubin Chang, Lamei Liu, Fangrui Hu, Xiaohan Sun, Yingchun Zhao, Na Zhang, Chunhua Li
2024 J jnl
Entropy
Xiaohan Sun, Anlin Li, Shaoxiang Zhu, Feng Zhu
2023 conf
CNS
Xiaokai Ye, Tao Lv, Xiaohan Sun
2023 J jnl
IEEE Access
Yang Xie, Ningfeng Bai, Changsheng Shen, Hehong Fan, Zhaofu Chen, Xiaohan Sun
2023 J jnl
J. Chem. Inf. Model.
Zhixiang Wu, Zhongjie Han, Lianci Tao, Xiaohan Sun, Jingjie Su, Jianping Hu, Chunhua Li
2023 J jnl
Inf. Sci.
Zhenlong Man, Jinqing Li, Xiaoqiang Di, Ripei Zhang, Xusheng Li, Xiaohan Sun
2023 J jnl
IEEE Trans. Instrum. Meas.
Jun Zhao, Min Yan, Xi Luo, Zhan Gan, Hong Cao, Jiarui Chang, Yichen Wen, Xiaohan Sun
2023 J jnl
IEEE Access
Jing Zhang, Jiting Zhou, Jinyang Guo, Xiaohan Sun
2023 J jnl
Briefings Bioinform.
Shuang Yang, Weikang Gong, Tong Zhou, Xiaohan Sun, Lei Chen, Wenxue Zhou, Chunhua Li
2022 conf
ICSCA
Xiaohan Sun, Ning Li, Lin Zhang
2022 J jnl
IEEE Access
Xiaohan Sun, Jiting Zhou
2022 J jnl
J. High Speed Networks
Ronghua Chi, Leilei Li, Sang Gui, Fei Wang, Zijian Mao, Xiaohan Sun, Ning Cao
2022 conf
ICBBT
Xiaohan Sun
2022 conf
IVSP
Nuo Shen, Borui Zhou, Junlin Xie, Xiaohan Sun
2022 J jnl
Digit. Signal Process.
Xiaohan Sun, Li Zhang
2022 J jnl
Briefings Bioinform.
Weikang Gong, Junjie Wee, Min-Chun Wu, Xiaohan Sun, Chunhua Li, Kelin Xia
2022 J jnl
IEEE Trans. Instrum. Meas.
Jun Zhao, Min Yan, Shenguo Xu, Xiaohan Sun
2022 C conf
CIS
Xiaohan Sun, Yanju Zhang, Xiaobin Huang, Fangzhou Wang, Zugang Mo
2021 J jnl
IEEE Trans. Instrum. Meas.
Jun Zhao, Lei Shi, Xiaohan Sun
2021 J jnl
Appl. Intell.
Li Zhang, Zepeng Li, Xiaohan Sun
2021 J jnl
Comput. Animat. Virtual Worlds
Chi Zhou, Zhangjiong Lai, Suzhen Wang, Lincheng Li, Xiaohan Sun, Yu Ding
2021 C conf
ISCAS
Kuihe Yang, Ziying Song, Yingchao Zhang, Yufan Zhou, Xiaohan Sun, Jianxuan Wang
2021 J jnl
Aslib J. Inf. Manag.
Man Xu, Dan Gan, Ting Pan, Xiaohan Sun
2020 conf
UCET
Xiaotao Zhu, Wei Hong, Ningfeng Bai, Xiaohan Sun
2020 J jnl
IEEE Trans. Ind. Electron.
Shuying Yang, Xiaohan Sun, Mingyao Ma, Xing Zhang, Liuchen Chang
2020 J jnl
Opt. Switch. Netw.
Yu Zheng, Zhiqun Ge, Xiaolu Zhang, Jian Xu, Xiaohan Sun
2020 J jnl
IEEE Access
Zhiqun Ge, Xiaohan Sun
2020 conf
NCAA
Li Zhang, Xiaohan Sun, Jiangfei Cheng, Zepeng Li
2019 conf
CinC
Xiaohan Sun, Qince Li, Kuanquan Wang, Runnan He, Henggui Zhang
2019 J jnl
Sensors
Lin Xiong, Guoquan Wang, Yan Bao, Xin Zhou, Kuan Wang, Hanlin Liu, Xiaohan Sun, Ruibin Zhao
2019 J jnl
Remote. Sens.
Yuhao Liu, Xiaohan Sun, Guoquan Wang, Michael J. Turco, Gonzalo Agudelo, Yan Bao, Ruibin Zhao, Shuilong Shen
2019 conf
FNSS
Xiaokai Ye, Xiaohan Sun
2018 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Hubin Zhao, Ahmed Soltan, Pleun Maaskant, Na Dong, Xiaohan Sun, Patrick Degenaar
2018 J jnl
Photonic Netw. Commun.
Xiaobo Zeng, Min Zhu, Lu Wang, Xiaohan Sun
2017 conf
iThings/GreenCom/CPSCom/SmartData
Yan Ding, Chao Xu, Hua Li, Xiaohan Sun, Yunbo Yang
2017 J jnl
JOCN
Min Zhu, Xiaobo Zeng, Yang Lin, Xiaohan Sun
2017 J jnl
IEEE Trans. Biomed. Circuits Syst.
Junwen Luo, Konstantin Nikolic, Benjamin D. Evans, Na Dong, Xiaohan Sun, Peter Andras, Alex Yakovlev, Patrick Degenaar
2017 J jnl
J. Inf. Process. Syst.
Xiaohan Sun, Junying Zhang
2016 J jnl
Photonic Netw. Commun.
Dongpeng Wang, Min Zhu, Jiao Zhang, Xiaohan Sun
2016 conf
SmartGridComm
Yu Zheng, Zijian Mao, Shijie Ma, Xiaohan Sun
2016 J jnl
JOCN
Min Zhu, Jiao Zhang, Dongpeng Wang, Xiaohan Sun
2015 conf
WOCC
Min Zhu, Dongpeng Wang, Jiao Zhang, Yu Zheng, Hehong Fan, Xiaohan Sun, Junmin Wu, Xiaojian Zhang, Gang Zhang, Peng Wu
2015 conf
ICTON
Min Zhu, Jiao Zhang, Dongpeng Wang, Xiaohan Sun
2015 C conf
ICICS
Min Zhu, Jiao Zhang, Xiaohan Sun
2014 conf
OFC
Chao Pan, Hongliang Ye, Mingming Li, Shuhui Zhao, Xiaohan Sun
2014 J jnl
BMC Bioinform.
Xiaohan Sun, Junying Zhang
2014 J jnl
Microelectron. Reliab.
Yuanyuan Chen, Bin Sun, Tianhe Ma, Xiaohan Sun
2013 J jnl
IEEE Commun. Lett.
Xu Zhou, Fuding Zhang, Mingming Sun, Chao Pan, Xiaohan Sun
2013 J jnl
J. Supercomput.
Jian Cao, Jie Wang, Haiyan Zhao, Xiaohan Sun
2013 J jnl
JOCN
Hehong Fan, Jianqing Li, Xiaohan Sun
2013 J jnl
Digit. Signal Process.
Xiaohan Sun, Junying Zhang, Aimin Li, Xiguo Yuan
2011 J jnl
Photonic Netw. Commun.
Jun Zhao, Xiaohan Sun
2011 conf
ICAIC (1)
Xiaohan Sun
2010 J jnl
Reliab. Eng. Syst. Saf.
Hehong Fan, Xiaohan Sun
2010 J jnl
J. Supercomput.
Jun Zhao, Xiaohan Sun
2009 C conf
ISPA
Haiyan Zhao, Jian Cao, Xiaohan Sun
2007 J jnl
Photonic Netw. Commun.
Chenhui Ge, Zhihong Lian, Xiaohan Sun, Mingde Zhang
2006 conf
Wireless and Optical Communications
Chuanqi Li, Delin Zhao, Yulin Chen, Xiaohan Sun, Je-Myung Jeong
2006 J jnl
Sci. China Ser. F Inf. Sci.
Jinbiao Xiao, Xu Liu, Chun Cai, Hehong Fan, Xiaohan Sun
2006 J jnl
Photonic Netw. Commun.
Lei Li, Mingde Zhang, Xiaohan Sun
2005 J jnl
Sci. China Ser. F Inf. Sci.
Yong Tang, Min Rao, Lei Li, Yu Chen, Jianfeng Jiang, Mingde Zhang, Xiaohan Sun
2005 conf
ICETE
Hehong Fan, Mingde Zhang, Xiaohan Sun
2004 J jnl
Photonic Netw. Commun.
Min Rao, Lei Li, Yong Tang, Mingde Zhang, Xiaohan Sun
2004 J jnl
Sci. China Ser. F Inf. Sci.
Jinbiao Xiao, Xiaohan Sun, Mingde Zhang
2002 J jnl
Sci. China Ser. F Inf. Sci.
Chaoqin Gan, Xiaohan Sun, Mingde Zhang
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'
        }