Hai Yu

90 papers A* 7C 2Journal 72Unranked 8
YearRankTypeTitle / Venue / Authors
2026 J jnl
Knowl. Based Syst.
Yingli Hou, Zhiliang Zhu, Wei Zhang, Hai Yu
2026 J jnl
Autom. Softw. Eng.
Haitao Sun, Ying Wang, Hai Yu, Zhiliang Zhu
2026 J jnl
Expert Syst. Appl.
Jingjing Yang, Zhiliang Zhu, Wei Zhang, Meng Xing, Hai Yu
2026 J jnl
Neurocomputing
Hao Xu, Xiaohu Song, Haitao Sun, Hai Yu, Zhiliang Zhu
2025 J jnl
IEEE Trans. Netw. Serv. Manag.
Donglei Yuan, Chi Jiang, Yuli Zhao, Hai Yu, Zhiliang Zhu
2025 J jnl
Eng. Appl. Artif. Intell.
Yiru Wei, Zhiliang Zhu, Hai Yu, Wei Zhang
2025 J jnl
IEEE Commun. Lett.
Yin Zhang, Liqun Zhao, Yuli Zhao, Francis C. M. Lau, Hai Yu, Zhiliang Zhu, Bin Zhang
2025 J jnl
IEEE Trans. Multim.
Yingli Hou, Wei Zhang, Zhiliang Zhu, Hai Yu
2025 J jnl
Entropy
Wei Zhang, Xue Zheng, Meng Xing, Jingjing Yang, Hai Yu, Zhiliang Zhu
2025 J jnl
Softw. Pract. Exp.
Xiaohu Song, Hai Yu, Ying Wang, Zhiliang Zhu
2025 A* conf
ASE
Meiqiu Xu, Ying Wang, Wei Tang, Xian Zhan, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2025 A* conf
ASE
Fanyi Meng, Ying Wang, Chun Yong Chong, Hai Yu, Zhiliang Zhu
2025 J jnl
Appl. Intell.
Yiru Wei, Zhiliang Zhu, Hai Yu, Wei Zhang
2025 J jnl
Int. J. Softw. Informatics
Yibo Wang, Ying Wang, Yue Yu, Chang Xu, Hai Yu, Zhiliang Zhu
2025 A* conf
ASE
Yibo Wang, Zhihao Peng, Ying Wang, Zhao Wei, Hai Yu, Zhiliang Zhu
2025 J jnl
CoRR
Yibo Wang, Zhihao Peng, Ying Wang, Zhao Wei, Hai Yu, Zhiliang Zhu
2025 book
Ying Wang, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2025 J jnl
Proc. ACM Softw. Eng.
Bo Zhou, Jiaqi Shi, Ying Wang, Li Li, Tsz On Li, Hai Yu, Zhiliang Zhu
2025 J jnl
Appl. Soft Comput.
Yingli Hou, Wei Zhang, Zhiliang Zhu, Hai Yu
2024 J jnl
Int. J. Bifurc. Chaos
Meng Xing, Hai Yu, Wei Zhang, Zhiliang Zhu
2024 J jnl
Entropy
Wei Zhang, Guangdong Zhu, Meng Xing, Jingjing Yang, Hai Yu, Zhiliang Zhu
2024 J jnl
J. Softw. Evol. Process.
Fanyi Meng, Hai Yu, Chun Yong Chong, Ying Wang, Zhiliang Zhu
2024 conf
Internetware
Fanyi Meng, Ying Wang, Chun Yong Chong, Hai Yu, Zhiliang Zhu
2024 J jnl
ACM Trans. Softw. Eng. Methodol.
Fanyi Meng, Ying Wang, Chun Yong Chong, Hai Yu, Zhiliang Zhu
2024 J jnl
ACM Trans. Multim. Comput. Commun. Appl.
Yuli Zhao, Yin Zhang, Francis C. M. Lau, Hai Yu, Zhiliang Zhu, Bin Zhang
2024 J jnl
Expert Syst. Appl.
Yingli Hou, Wei Zhang, Zhiliang Zhu, Hai Yu
2024 J jnl
IET Commun.
Yin Zhang, Zhen Zhen, Yuli Zhao, Francis C. M. Lau, Bochang Ma, Bin Zhang, Hai Yu, Zhiliang Zhu
2024 J jnl
Int. J. Bifurc. Chaos
Meng Xing, Hai Yu, Wei Zhang, Zhiliang Zhu
2023 J jnl
CoRR
Md Mahir Asef Kabir, Sk Adnan Hassan, Xiaoyin Wang, Ying Wang, Hai Yu, Na Meng
2023 conf
ESEC/SIGSOFT FSE
Yibo Wang, Ying Wang, Tingwei Zhang, Yue Yu, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2023 J jnl
IEEE Trans. Software Eng.
Ying Wang, Peng Sun, Lin Pei, Yue Yu, Chang Xu, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2023 J jnl
IEEE Trans. Software Eng.
Ying Wang, Yibo Wang, Sinan Wang, Yepang Liu, Chang Xu, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2022 J jnl
J. Real Time Image Process.
Yiru Wei, Zhiliang Zhu, Hai Yu, Wei Zhang
2022 J jnl
Frontiers Inf. Technol. Electron. Eng.
Fanyi Meng, Ying Wang, Hai Yu, Zhiliang Zhu
2022 J jnl
Comput. Commun.
Yuli Zhao, Yin Zhang, Francis C. M. Lau, Zhiliang Zhu, Hai Yu
2022 A* conf
ASE
Meiqiu Xu, Ying Wang, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2022 J jnl
Symmetry
Li Guo, Zhiliang Zhu, Francis C. M. Lau, Yuli Zhao, Hai Yu
2022 J jnl
IET Commun.
Yin Zhang, Yuli Zhao, Francis C. M. Lau, Bin Zhang, Zhiliang Zhu, Hai Yu
2022 J jnl
IEEE Trans. Software Eng.
Ying Wang, Rongxin Wu, Chao Wang, Ming Wen, Yepang Liu, Shing-Chi Cheung, Hai Yu, Chang Xu, Zhiliang Zhu
2021 J jnl
J. Real Time Image Process.
Yiru Wei, Zhiliang Zhu, Hai Yu, Wei Zhang
2021 J jnl
J. Real Time Image Process.
Yiru Wei, Zhiliang Zhu, Hai Yu, Wei Zhang
2021 J jnl
Multim. Tools Appl.
Wei Zhang, Weijie Han, Zhiliang Zhu, Hai Yu
2021 A* conf
ICSE
Ying Wang, Liang Qiao, Chang Xu, Yepang Liu, Shing-Chi Cheung, Na Meng, Hai Yu, Zhiliang Zhu
2021 J jnl
CoRR
Ying Wang, Liang Qiao, Chang Xu, Yepang Liu, Shing-Chi Cheung, Na Meng, Hai Yu, Zhiliang Zhu
2021 J jnl
CoRR
Ying Wang, Yibo Wang, Sinan Wang, Yepang Liu, Chang Xu, Shing-Chi Cheung, Hai Yu, Zhiliang Zhu
2021 J jnl
IEEE Trans. Image Process.
Ye Yuan, Wei Zhang, Hai Yu, Zhiliang Zhu
2020 J jnl
Complex.
Xue Yang, Zhiliang Zhu, Hai Yu, Yuli Zhao
2020 J jnl
Multim. Tools Appl.
Zhiliang Zhu, Yanjie Song, Wei Zhang, Hai Yu, Yuli Zhao
2020 J jnl
Entropy
Wei Zhang, Shuwen Wang, Weijie Han, Hai Yu, Zhiliang Zhu
2020 A* conf
ICSE
Ying Wang, Ming Wen, Yepang Liu, Yibo Wang, ZhenMing Li, Chao Wang, Hai Yu, Shing-Chi Cheung, Chang Xu, Zhiliang Zhu
2020 J jnl
IEEE Trans. Image Process.
Ye Yuan, Zhiliang Zhu, Hai Yu, Wei Zhang
2020 J jnl
CoRR
Ying Wang, Rongxin Wu, Chao Wang, Ming Wen, Yepang Liu, Shing-Chi Cheung, Hai Yu, Chang Xu, Zhiliang Zhu
2019 J jnl
Entropy
Wei Zhang, Zhiliang Zhu, Hai Yu
2019 A* conf
ICSE
Ying Wang, Ming Wen, Rongxin Wu, Zhenwei Liu, Shin Hwei Tan, Zhiliang Zhu, Hai Yu, Shing-Chi Cheung
2019 J jnl
IEEE Access
Yanjie Song, Zhiliang Zhu, Wei Zhang, Hai Yu, Yuli Zhao
2019 J jnl
Multim. Tools Appl.
Yanjie Song, Zhiliang Zhu, Wei Zhang, Hai Yu
2019 J jnl
Complex.
Xue Yang, Zhiliang Zhu, Hai Yu, Yuli Zhao, Li Guo
2019 J jnl
IEEE Access
Zhiliang Zhu, Jie Liang, Deyang Li, Hai Yu, Guoqi Liu
2018 J jnl
IEEE Access
Zhiliang Zhu, Deyang Li, Jie Liang, Guoqi Liu, Hai Yu
2018 J jnl
Signal Process.
Dong-dai Liu, Wei Zhang, Hai Yu, Zhiliang Zhu
2018 J jnl
IEEE Trans. Software Eng.
Ying Wang, Hai Yu, Zhiliang Zhu, Wei Zhang, Yuli Zhao
2018 conf
ESEC/SIGSOFT FSE
Ying Wang, Ming Wen, Zhenwei Liu, Rongxin Wu, Rui Wang, Bo Yang, Hai Yu, Zhiliang Zhu, Shing-Chi Cheung
2018 J jnl
Comput. Medical Imaging Graph.
Ye Yuan, Yen-Wei Chen, Chunhua Dong, Hai Yu, Zhiliang Zhu
2018 J jnl
IET Commun.
Yuli Zhao, Yin Zhang, Francis C. M. Lau, Hai Yu, Zhiliang Zhu
2018 J jnl
Entropy
Guanrong Chen, Marius-F. Danca, Xiaosong Yang, Genaro J. Martínez, Hai Yu
2018 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Ying Wang, Zhiliang Zhu, Hai Yu, Bo Yang
2018 J jnl
Comput. Commun.
Li Guo, Zhiliang Zhu, Francis C. M. Lau, Yuli Zhao, Hai Yu
2018 J jnl
Appl. Netw. Sci.
Zhiliang Zhu, Zejun Ke, Jiayin Cui, Hai Yu, Guoqi Liu
2018 J jnl
J. Syst. Softw.
Ying Wang, Zhiliang Zhu, Bo Yang, Fangda Guo, Hai Yu
2017 C conf
IECON
Yuli Zhao, Hai Yu, Zhiliang Zhu, Yin Zhang
2017 J jnl
Sci. Program.
Hong-Jian Yin, Hai Yu, Yuli Zhao, Zhiliang Zhu, Wei Zhang
2017 conf
ACIIDS (2)
Kai Shi, Hai Yu, Zhiliang Zhu, Jingde Cheng
2017 C conf
IECON
Xiwei Liu, Kai Shi, Hai Yu, Zhiliang Zhu
2016 J jnl
Entropy
Hegui Zhu, Xiangde Zhang, Hai Yu, Cheng Zhao, Zhiliang Zhu
2016 J jnl
Int. J. Comput. Sci. Eng.
Chong Fu, Zhan-kao Wen, Zhiliang Zhu, Hai Yu
2016 conf
ISCID (1)
Kai Shi, Hang Song, Hai Yu, Zhiliang Zhu
2016 J jnl
Signal Process.
Wei Zhang, Hai Yu, Yuli Zhao, Zhiliang Zhu
2015 J jnl
Commun. Nonlinear Sci. Numer. Simul.
Junxin Chen, Zhiliang Zhu, Chong Fu, Hai Yu, Li-bo Zhang
2015 J jnl
Signal Process.
Junxin Chen, Zhiliang Zhu, Chong Fu, Hai Yu, Yushu Zhang
2014 J jnl
Int. J. Bifurc. Chaos
Zhiliang Zhu, Jingping Song, Yanjie Song, Hai Yu
2014 J jnl
IEEE Trans. Multim.
Zhiliang Zhu, Fangda Guo, Hai Yu, Chen Chen
2013 J jnl
Commun. Nonlinear Sci. Numer. Simul.
Wei Zhang, Kwok-Wo Wong, Hai Yu, Zhiliang Zhu
2013 J jnl
Commun. Nonlinear Sci. Numer. Simul.
Wei Zhang, Kwok-Wo Wong, Hai Yu, Zhiliang Zhu
2013 J jnl
Int. J. Control
Tao Ren, Zhiliang Zhu, Hai Yu, Georgi M. Dimirovski
2012 J jnl
Int. J. Bifurc. Chaos
Yuli Zhao, Francis Chung-Ming Lau, Zhiliang Zhu, Hai Yu
2011 J jnl
Inf. Sci.
Zhiliang Zhu, Wei Zhang, Kwok-Wo Wong, Hai Yu
2009 conf
HIS (2)
Jingping Song, Zhiliang Zhu, Ye Yang, Hai Yu, Mengmeng Li
2008 J jnl
Kybernetika
Zhiliang Zhu, Shuping Li, Hai Yu
2008 conf
ICYCS
Zhen Qin, Hai Yu, Jinling Ju
2008 conf
ICYCS
Zhiliang Zhu, Jingping Song, Dong Aoshuang, Hai Yu, Ye Yang
redb/extractors/decompiler/_archive/DecompileGhidra.py
← Index redb/extractors/decompiler/_archive/DecompileGhidra.py python
from hashlib import sha256, md5
import inspect
import subprocess
import json
import os
import time
from datetime import datetime, timezone
from typing import Dict, List, Any, Optional

from dotenv import load_dotenv
from redb.extractors.enum import Tag
from redb.extractors.extractor import Extractor
import magic
import pefile
import ppdeep
import tlsh


class DecompileGhidra(Extractor):
    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        filetype=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious,
        )
        self.log.debug(inspect.currentframe().f_code.co_name)
        self.ghidra_path = os.getenv("GHIDRA_PATH", "/opt/ghidra")
        self.java_script_path = os.getenv(
            "GHIDRA_SCRIPT_PATH",
            "/opt/ghidra/Ghidra/Features/Base/ghidra_scripts/GhidraDecompilerScript.java",
        )
        self.analysis_results = None
        self.ghidra_process = None  # Track the current process
        self.project_path = None
        self.filetype = filetype

        # Convert TIMEOUT to integer with a default of 1200 seconds (20 minutes)
        try:
            self.TIMEOUT = int(os.getenv("GHIDRA_TIMEOUT", "1200"))
        except ValueError:
            self.log.warning(
                "Invalid GHIDRA_TIMEOUT value, using default of 1200 seconds"
            )
            self.TIMEOUT = 1200

        self.initialize_project()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cleanup_run()

    def is_dotnet(self):
        try:
            if self.filetype == "pebin":
                file_type = magic.from_buffer(self.binary)
                if ".Net" in file_type:
                    return True
                pe = pefile.PE(self.filepath)
                for entry in pe.OPTIONAL_HEADER.DATA_DIRECTORY:
                    # IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR is typically 14
                    if (
                        entry.name == "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR"
                        and entry.Size > 0
                    ):
                        return True
                return False
        except AttributeError as e:
            self.log.error(
                f"AttributeError error dotnet file {self.hash.sha256} Full error : {e}"
            )
            return False

    def cleanup_run(self):
        """Clean up after analysis."""
        try:
            if self.ghidra_process and self.ghidra_process.poll() is None:
                self.ghidra_process.terminate()
                try:
                    self.ghidra_process.wait(timeout=5)
                except subprocess.TimeoutExpired:
                    self.ghidra_process.kill()

            # Clean up project directory
            if self.project_path and os.path.exists(self.project_path):
                import shutil

                shutil.rmtree(self.project_path)
                self.log.debug(f"Cleaned up project directory: {self.project_path}")

            # Force garbage collection
            import gc

            gc.collect()
        except Exception as e:
            self.log.error(f"Error in cleanup: {e}")

    # @classmethod
    # def cleanup_batch(cls):
    #     """Clean up the persistent project at the end of a batch."""
    #     print(f"Cleaning up Ghidra project for batch")
    #     if cls._project_path and os.path.exists(cls._project_path):
    #         try:
    #             import shutil
    #             shutil.rmtree(cls._project_path)
    #             cls._project_initialized = False
    #             cls._project_path = None
    #         except Exception as e:
    #             print(f"Error cleaning up project: {e}")

    def _get_environment(self):
        """Setup and return the environment for Ghidra."""
        env = os.environ.copy()
        java_home = os.getenv("GHIDRA_JAVA_HOME", "/usr/lib/jvm/java-17-openjdk-amd64")
        env.update(
            {
                "JAVA_HOME": java_home,
                "PATH": f"{java_home}/bin:{env['PATH']}",
                "LD_LIBRARY_PATH": f"{java_home}/lib:{env.get('LD_LIBRARY_PATH', '')}",
            }
        )
        # Print environment variables for debugging
        self.log.debug(f"JAVA_HOME: {env['JAVA_HOME']}")
        self.log.debug(f"PATH: {env['PATH']}")
        self.log.debug(f"LD_LIBRARY_PATH: {env['LD_LIBRARY_PATH']}")

        return env

    def initialize_project(self):
        """Initialize a temporary Ghidra project for this file."""
        # Create unique project directory
        self.project_path = f"/tmp/ghidra_{os.path.basename(self.filepath)}_{str(int(time.time()))}_{os.getpid()}"
        os.makedirs(self.project_path, exist_ok=True)
        self.log.debug(f"Created temporary project at {self.project_path}")

        # Create a minimal initialization file
        init_file = os.path.join(self.project_path, ".init")
        with open(init_file, "wb") as f:
            f.write(bytes([0x7F, 0x45, 0x4C, 0x46]))  # Valid ELF header magic bytes

        # Initialize project with minimal file
        env = self._get_environment()
        cmd = [
            f"{self.ghidra_path}/support/analyzeHeadless",
            self.project_path,
            "TempProject",
            "-import",
            init_file,
        ]

        try:
            result = subprocess.run(cmd, env=env, capture_output=True, text=True)
            if result.returncode != 0:
                self.log.error(f"Failed to initialize project: {result.stderr}")
                raise RuntimeError("Project initialization failed")

            # Clean up initialization file
            os.remove(init_file)
            self.log.debug("Project initialized successfully")

        except Exception as e:
            self.log.error(f"Error initializing project: {e}")
            raise

    def analyze_binary(self) -> Optional[Dict[str, Any]]:
        """Run Ghidra analysis and return results."""
        self.log.debug("Starting binary analysis")

        # # Check if packed
        # if self.check_binary_protection():
        #     self.log.warning("Skipping protected binary")
        #     return None

        # Check for .NET only if needed
        # if self.is_dotnet():
        #     self.MAX_NAMED_ARG_WARNINGS = 10000  # Higher threshold for .NET
        #     self.log.info("Adjusting parameters for .NET binary")
        # else:
        #     self.MAX_NAMED_ARG_WARNINGS = 1000  # Normal threshold

        if not os.path.exists(self.java_script_path):
            self.log.error(f"Java script not found: {self.java_script_path}")
            return None

        env = self._get_environment()

        try:
            base_cmd = [
                f"{self.ghidra_path}/support/analyzeHeadless",
                self.project_path,
                "TempProject",
                "-import",
                self.filepath,
                "-scriptPath",
                os.path.dirname(self.java_script_path),
                "-postScript",
                self.java_script_path,
                self.sha256,
                self.filepath,
            ]
            return self.run_ghidra(base_cmd, env)

        except Exception as e:
            self.log.error(f"Error in Ghidra analysis: {e}")
            return None

        finally:
            self.cleanup_run()

    def run_ghidra(
        self, cmd: list, env: Optional[Dict[str, str]] = None
    ) -> Optional[Dict[str, Any]]:
        """Run Ghidra process and capture JSON output with improved logging separation."""
        process = None
        try:
            self.log.info(f"Starting Ghidra analysis: {' '.join(cmd)}")
            start_time = time.time()

            process = subprocess.Popen(
                cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
            )
            self.ghidra_process = process

            warning_counter = 0
            named_arg_counter = 0
            # Read all output lines
            json_output = None
            while True:
                line = process.stdout.readline()
                if not line and process.poll() is not None:
                    break

                stripped_line = line.strip()
                if not stripped_line:
                    continue

                # if 'Invalid FieldOrProp value in NamedArg' in stripped_line:
                #     named_arg_counter += 1
                #     if named_arg_counter > self.MAX_NAMED_ARG_WARNINGS:
                #         self.log.error(f"Too many NamedArg warnings ({named_arg_counter}), possible protected file.")
                #         self.ghidra_process.kill()
                #         return None
                if (
                    stripped_line.startswith("{")
                    and '"sha256"' in stripped_line
                    and '"decompiled"' in stripped_line
                ):
                    # This is our actual JSON output from GhidraDecompilerScript
                    json_output = stripped_line
                elif any(level in stripped_line for level in ["INFO", "WARN", "ERROR"]):
                    # Ghidra framework logging
                    log_level = (
                        "debug"
                        if "INFO" in stripped_line
                        else "warning"
                        if "WARN" in stripped_line
                        else "error"
                    )
                    if log_level == "warning" and any(
                        expected in stripped_line
                        for expected in [
                            "Unable to disassemble EXTERNAL block",
                            "Failed to markup ELF Note",
                            "Invalid FieldOrProp value in NamedArg",
                            "Unable to resolve constructor",
                            "Could not follow disassembly flow into non-existing memory",
                            "Unable to read bytes at ram",
                        ]
                    ):
                        # Skip expected warnings
                        continue

                    getattr(self.log, log_level)(f"Ghidra info: {stripped_line}")

            # Process completion and stderr
            try:
                stderr = process.stderr.read()
                process.wait(timeout=self.TIMEOUT)

                if stderr:
                    for line in stderr.splitlines():
                        stripped_line = line.strip()
                        if not stripped_line:
                            continue
                        if "ERROR" in stripped_line:
                            self.log.error(f"Ghidra stderr: {stripped_line}")
                        elif "WARN" in stripped_line:
                            self.log.warning(f"Ghidra stderr: {stripped_line}")
                        else:
                            self.log.debug(f"Ghidra stderr: {stripped_line}")

            except subprocess.TimeoutExpired:
                process.kill()
                self.log.error("Ghidra analysis timed out")
                return None

            elapsed_time = time.time() - start_time
            self.log.debug(f"Ghidra analysis completed in {elapsed_time:.2f}s")

            # Parse JSON output if we found it
            if json_output:
                try:
                    result = json.loads(json_output)
                    # Validate the required structure
                    if not isinstance(result, dict) or not all(
                        k in result
                        for k in ["sha256", "decompiled", "disassembled", "cfg"]
                    ):
                        self.log.error("Invalid JSON structure from Ghidra")
                        return None
                    return result
                except json.JSONDecodeError as e:
                    self.log.error(f"Failed to parse Ghidra JSON output: {e}")
                    return None
            else:
                self.log.error("No JSON output received from Ghidra")
                return None

        except Exception as e:
            self.log.error(f"Error running Ghidra: {str(e)}")
            if hasattr(e, "__traceback__"):
                import traceback

                self.log.debug(
                    f"Traceback: {''.join(traceback.format_tb(e.__traceback__))}"
                )
            return None

        finally:
            if process:
                try:
                    # Ensure pipes are closed
                    if process.stdout:
                        process.stdout.close()
                    if process.stderr:
                        process.stderr.close()
                    # Terminate process if still running
                    if process.poll() is None:
                        process.terminate()
                        try:
                            process.wait(timeout=5)
                        except subprocess.TimeoutExpired:
                            process.kill()
                except Exception as e:
                    self.log.error(f"Error cleaning up Ghidra process: {e}")

    def extract(self) -> bool:
        """Extract and process all analysis results."""
        self.log.debug(inspect.currentframe().f_code.co_name)
        try:
            results = self.analyze_binary()
            if not results:
                return False

            self.analysis_results = results
            return True

        except Exception as e:
            self.log.error(f"Error in extraction: {e}")
            return False

    def prepare_export_data(self, exporter_type: str) -> Any:
        """Prepare data for database export."""
        self.log.debug(inspect.currentframe().f_code.co_name)
        if not self.analysis_results:
            return None

        if exporter_type == "ClickHouseExporter":
            now = datetime.now(timezone.utc)

            def prepare_array_field(value, array_type):
                """Helper to prepare array fields with proper null handling"""
                if value is None:
                    return []
                return value

            def ssdeep_disassembly(func):
                try:
                    if len(func) > 1:
                        return ppdeep.hash(func)
                    return ""
                except Exception as e:
                    self.log.error(f"Error in disassembly ssdeep hash calculation: {e}")
                    return ""

            def tlsh_disassembly(func):
                try:
                    if len(func) >= 50:
                        return tlsh.hash(func.encode("utf-8"))
                    return ""
                except Exception as e:
                    self.log.error(f"Error in disassembly tlsh hash calculation: {e}")
                    return ""

            return {
                "multi_table": True,
                "decompiled_content": {
                    "table": "decompiled_functions_content",
                    "data": [
                        [
                            f["decompiled_content_hash"],
                            f["decompiled_function"],
                            f["function_type"],
                            now,
                        ]
                        for f in self.analysis_results["decompiled"]
                    ],
                    "column_names": [
                        "decompiled_content_hash",
                        "decompiled_function",
                        "function_type",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'THUNK'=3, 'EXTERNAL'=4, 'UNKNOWN'=5)",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "decompiled_refs": {
                    "table": "decompiled_functions_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["decompiled_content_hash"],
                            f["decompiled_function_name"],
                            f["decompiled_function_address"],
                            now,
                        ]
                        for f in self.analysis_results["decompiled"]
                    ],
                    "column_names": [
                        "sha256",
                        "decompiled_content_hash",
                        "decompiled_function_name",
                        "decompiled_function_address",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "LowCardinality(String)",
                        "String",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "disassembled_content": {
                    "table": "disassembled_functions_content",
                    "data": [
                        [
                            f["disassembled_content_hash"],
                            f["fully_normalized_content_hash"],
                            f["api_normalized_content_hash"],
                            f["category_normalized_content_hash"],
                            f.get("disassembled_function", ""),
                            f.get("fully_normalized_disassembly", ""),
                            f.get("api_normalized_disassembly", ""),
                            f.get("category_normalized_disassembly", ""),
                            ssdeep_disassembly(f.get("disassembled_function", "")),
                            tlsh_disassembly(f.get("disassembled_function", "")),
                            ssdeep_disassembly(
                                f.get("fully_normalized_disassembly", "")
                            ),
                            tlsh_disassembly(f.get("fully_normalized_disassembly", "")),
                            f.get("function_type", "UNKNOWN"),
                            f.get("instruction_count", 0),
                            prepare_array_field(
                                f.get("instruction_types"), "LowCardinality(String)"
                            ),
                            f.get("control_flow_count", 0),
                            prepare_array_field(
                                f.get("memory_access_pattern"), "LowCardinality(String)"
                            ),
                            prepare_array_field(
                                f.get("register_usage"), "LowCardinality(String)"
                            ),
                            f.get("data_references_count", 0),
                            # prepare_array_field(f.get('opcode_frequency_vector'), 'Float32'),
                            # prepare_array_field(f.get('api_calls_vector'), 'Float32'),
                            # prepare_array_field(f.get('minhash_signature'), 'UInt64'),
                            # f.get('pic_hash', ''),
                            f.get("max_block_size", 0),
                            f.get("num_calls", 0),
                            f.get("stack_size", 0),
                            # prepare_array_field(f.get('instruction_type_ratios'), 'Float32'),
                            # prepare_array_field(f.get('instruction_embedding'), 'Float32'),
                            now,
                        ]
                        for f in self.analysis_results["disassembled"]
                    ],
                    "column_names": [
                        "disassembled_content_hash",
                        "fully_normalized_content_hash",
                        "api_normalized_content_hash",
                        "category_normalized_content_hash",
                        "disassembled_function",
                        "fully_normalized_disassembly",
                        "api_normalized_disassembly",
                        "category_normalized_disassembly",
                        "ssdeep_disassembly",
                        "tlsh_disassembly",
                        "ssdeep_fully_normalized",
                        "tlsh_fully_normalized",
                        "function_type",
                        "instruction_count",
                        "instruction_types",
                        "control_flow_count",
                        "memory_access_pattern",
                        "register_usage",
                        "data_references_count",
                        # 'opcode_frequency_vector',
                        # 'api_calls_vector',
                        # 'minhash_signature',
                        # 'pic_hash',
                        "max_block_size",
                        "num_calls",
                        "stack_size",
                        # 'instruction_type_ratios',
                        # 'instruction_embedding',
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "FixedString(64)",
                        "FixedString(64)",
                        "String",
                        "String",
                        "String",
                        "String",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'THUNK'=3, 'EXTERNAL'=4, 'UNKNOWN'=5)",
                        "UInt32",
                        "Array(LowCardinality(String))",
                        "UInt32",
                        "Array(LowCardinality(String))",
                        "Array(LowCardinality(String))",
                        "UInt32",
                        # 'Array(Float32)',
                        # 'Array(Float32)',
                        # 'Array(UInt64)',
                        # 'Nullable(FixedString(16))',
                        "Nullable(UInt32)",
                        "Nullable(UInt32)",
                        "Nullable(Int32)",
                        # 'Array(Float32)',
                        # 'Array(Float32)',
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "disassembled_refs": {
                    "table": "disassembled_functions_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["disassembled_content_hash"],
                            f["fully_normalized_content_hash"],
                            f["api_normalized_content_hash"],
                            f["category_normalized_content_hash"],
                            f["disassembled_function_name"],
                            f["disassembled_function_address"],
                            now,
                        ]
                        for f in self.analysis_results["disassembled"]
                    ],
                    "column_names": [
                        "sha256",
                        "disassembled_content_hash",
                        "fully_normalized_content_hash",
                        "api_normalized_content_hash",
                        "category_normalized_content_hash",
                        "disassembled_function_name",
                        "disassembled_function_address",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "FixedString(64)",
                        "FixedString(64)",
                        "FixedString(64)",
                        "LowCardinality(String)",
                        "String",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "cfg_blocks": {
                    "table": "cfg_blocks",
                    "data": [
                        [
                            b["block_id"],
                            self.analysis_results["sha256"],
                            b["function_address"],
                            b["block_start_address"],
                            b["block_end_address"],
                            b["block_size"],
                            b["block_instructions"],
                            b["fully_normalized_instructions"],
                            b["api_normalized_instructions"],
                            b["category_normalized_instructions"],
                            b.get("predecessor_blocks", []),
                            b.get("successor_blocks", []),  # Use empty array as default
                            b.get("is_entry_block", False),
                            b.get("is_exit_block", False),
                            b.get("branch_type", "UNKNOWN"),
                            b.get("referenced_constants", []),
                            b.get("sign", 1),  # Use 1 as default for sign
                            now,
                        ]
                        for b in self.analysis_results["cfg"]
                    ],
                    "column_names": [
                        "block_id",
                        "sha256",
                        "function_address",
                        "block_start_address",
                        "block_end_address",
                        "block_size",
                        "block_instructions",
                        "fully_normalized_instructions",
                        "api_normalized_instructions",
                        "category_normalized_instructions",
                        "predecessor_blocks",
                        "successor_blocks",
                        "is_entry_block",
                        "is_exit_block",
                        "branch_type",
                        "referenced_constants",
                        "sign",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "String",
                        "String",
                        "String",
                        "UInt32",
                        "String",
                        "Nullable(String)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "Array(String)",
                        "Array(String)",
                        "Bool",
                        "Bool",
                        "Enum8('DIRECT'=1, 'CONDITIONAL'=2, 'CALL'=3, 'RETURN'=4, 'FALLTHROUGH'=5, 'UNKNOWN'=6)",
                        "Array(String)",
                        "Int8",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "function_analysis_errors": {
                    "table": "function_analysis_errors",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["function_name"],
                            f["function_address"],
                            f["error_location"],
                            f.get(
                                "error_message", ""
                            ),  # it could be empty, how to handle it?
                            f.get("error_details", ""),
                            f.get("error_type", "unknown"),
                            md5(
                                f"{f['error_message']}{f['function_name']}{f['function_address']}{f['error_location']}".encode()
                            ).hexdigest(),
                            "new",
                            now,
                        ]
                        for f in self.analysis_results["errors"]
                    ],
                    "column_names": [
                        "sha256",
                        "function_name",
                        "function_address",
                        "error_location",
                        "error_message",
                        "error_details",
                        "error_type",
                        "error_hash",
                        "status",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Nullable(String)",
                        "String",
                        "LowCardinality(String)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "FixedString(32)",
                        "Enum8('new'=1, 'investigating'=2, 'fixed'=3, 'wontfix'=4)",
                        "DateTime64(3, 'UTC')",
                    ],
                },
            }

    def tag(self) -> str:
        """Return the tag for this extractor."""
        return Tag.DECOMPILED.value

    def get_clickhouse_table(self) -> str:
        """Not used directly as we're handling multiple tables."""
        pass