Hamid Mcheick

119 papers B 4C 22Misc 1Journal 35Unranked 53
YearRankTypeTitle / Venue / Authors
2026 J jnl
Netw. Model. Anal. Health Informatics Bioinform.
Mohammad Ali Saberi, Hamid Mcheick, Mehdi Adda
2026 J jnl
IEEE Access
Ahmad Merei, Hamid Mcheick, Alia Ghaddar, Giovanni Beltrame
2026 J jnl
Neurocomputing
Wissam Salhab, Fehmi Jaafar, Hamid Mcheick, Darine Ameyed
2025 J jnl
Mach. Learn. Knowl. Extr.
Mohammad Ennab, Hamid Mcheick
2025 conf
SERP4IoT
Hamid Mcheick, Pamela Achouh
2025 J jnl
IEEE Open J. Comput. Soc.
Mohammad Ennab, Hamid Mcheick
2025 J jnl
Inf.
Mohammad Ali Saberi, Hamid Mcheick, Mehdi Adda
2025 J jnl
CoRR
Wissam Salhab, Darine Ameyed, Hamid Mcheick, Fehmi Jaafar
2025 conf
ARES (Workshops 1)
Wissam Salhab, Darine Ameyed, Hamid Mcheick, Fehmi Jaafar
2024 J jnl
IEEE Access
Wissam Salhab, Darine Ameyed, Fehmi Jaafar, Hamid Mcheick
2024 J jnl
Frontiers Robotics AI
Mohammad Ennab, Hamid Mcheick
2024 J jnl
Int. J. Perform. Eng.
Sahil Sikarwar, N. Jeyanthi, R. Thandeeswaran, Hamid Mcheick
2024 J jnl
Inf.
Batoul Msheik, Mehdi Adda, Hamid Mcheick, Mohamed Dbouk
2023 conf
SmartNets
Mohamad Ghandour, Hamid Mcheick, Mohamed Dbouk
2023 J jnl
J. Medical Syst.
Ahmad Merei, Hamid Mcheick, Alia Ghaddar
2022 conf
FNC/MobiSPC/SEIT
Hamid Mcheick, Fawzi Al Mestrah, Fatima Shbib, Zeinab Koteiche
2022 C conf
ICOST
Hamid Mcheick, Youmna Nasser, Farah Al Wardani, Batoul Msheik
2022 J jnl
Future Internet
Hicham Ajami, Hamid Mcheick, Catherine Laprise
2022 J jnl
IEEE Access
Zayan El Khaled, Wessam Ajib, Hamid Mcheick
2022 J jnl
Wirel. Networks
Zayan El Khaled, Hamid Mcheick, Wessam Ajib
2022 J jnl
Sensors
Mohamed Dhiaeddine Messaoudi, Bob-Antoine Jerry Ménélas, Hamid Mcheick
2022 conf
IntelliSys (3)
Hamid Mcheick, Fatima Ezzeddine, Fatima Lakkis, Batoul Msheik, Mariam Ezzeddine
2021 J jnl
Informatics
Hamid Mcheick, John Sayegh
2021 conf
EUSPN/ICTH
Mohammad Ali Saberi, Mehdi Adda, Hamid Mcheick
2021 conf
SmartNets
Hamid Mcheick, Houssam Hajj Hassan, Hanane Kteich
2021 ed.
ICDEc
Rim Jallouli, Mohamed Anis Bach Tobji, Hamid Mcheick, Gunnar Piho
2021 conf
ICDH
Mohammad Ali Saberi, Mehdi Adda, Hamid Mcheick
2020 J jnl
Symmetry
Konan-Marcelin Kouamé, Hamid Mcheick, Hicham Ajami
2020 J jnl
IEEE Access
Zayan El Khaled, Wessam Ajib, Hamid Mcheick
2020 C conf
ICOST
Hamid Mcheick, John Sayegh, Hicham Ajami
2020 J jnl
Concurr. Comput. Pract. Exp.
Ali Assi, Hamid Mcheick, Wajdi Dhifli
2020 C conf
ISNCC
Ghassan Fadlallah, Hamid Mcheick, Djamal Rebaine
2020 J jnl
Future Internet
Alia Ghaddar, Monah Bou Hatoum, Ghassan Fadlallah, Hamid Mcheick
2019 J jnl
CoRR
Youness Dendane, Fábio Petrillo, Hamid Mcheick, Souhail Ben Ali
2019 conf
IEEE BigData
Ali Assi, Hamid Mcheick, Wajdi Dhifli
2019 C conf
AICCSA
Hamid Mcheick, Monah Shouki Bou Hatoum, Alia Ghaddar
2019 J jnl
Int. J. Distributed Sens. Networks
Zayan Elkhaled, Hamid Mcheick
2019 C conf
IEA/AIE
Ali Assi, Hamid Mcheick, Wajdi Dhifli
2019 J jnl
Knowl. Based Syst.
Ali Assi, Hamid Mcheick, Ahmad Karawash, Wajdi Dhifli
2019 C conf
AICCSA
Hamid Mcheick, Youness Dendane, Fábio Petrillo, Souhail Ben Ali
2019 C conf
ICOST
Hicham Ajami, Hamid Mcheick, Karam Mustapha
2019 conf
SERP4IoT@ICSE
Zayan El Khaled, Hamid Mcheick, Fábio Petrillo
2018 J jnl
J. Ubiquitous Syst. Pervasive Networks
Jabril Abdelaziz, Mehdi Adda, Hamid Mcheick
2018 C conf
ICOST
Hicham Ajami, Hamid Mcheick, Lokman Saleh, Rania Taleb
2018 conf
ICSENT
Hamid Mcheick, Steve Godmaire
2018 conf
ICCA
Konan-Marcelin Kouamé, Hamid Mcheick
2018 conf
ICSENT
Ghassan Fadlallah, Hamid Mcheick, Djamal Rebaine, Mehdi Adda
2017 J jnl
Int. J. Big Data Intell.
Mohamed Dbouk, Hamid Mcheick, Ihab Sbeity
2017 C conf
ICOST
Lokman Saleh, Hamid Mcheick, Hicham Ajami, Hafedh Mili, Joumana Dargham
2017 J jnl
Sensors
Hamid Mcheick, Lokman Saleh, Hicham Ajami, Hafedh Mili
2017 conf
IML
Hamid Mcheick, Lokman Saleh, Hicham Ajami, Hafedh Mili
2017 ed.
ICC
Hani Hamdan, Djallel Eddine Boubiche, Homero Toral-Cruz, Sedat Akleylek, Hamid Mcheick
2016 conf
SummerSim
Zayan Elkhaled, Hamid Mcheick, Hicham Ajami
2016 C conf
ICMLA
Amel Hannech, Mehdi Adda, Hamid Mcheick
2016 B conf
CHASE
Hamid Mcheick, Hoda Nasser, Mohamed Dbouk, Ahmad Nasser
2016 conf
SummerSim
Hamid Mcheick, Hicham Ajami, Zayan Elkhaled
2016 conf
FNC/MobiSPC
Jabril Abdelaziz, Mehdi Adda, Hamid Mcheick
2016 B conf
CHASE
Hamid Mcheick
2015 conf
DEXA Workshops
Amel Hannech, Mehdi Adda, Hamid Mcheick
2015 conf
MCETECH
Hamid Mcheick, Malak Khreiss, Hala Sweidan, Iyad Zaarour
2015 conf
ANT/SEIT
Mehdi Adda, Jabril Abdelaziz, Hamid Mcheick, Rabeb Saad
2015 ch.
Computational Intelligence Applications in Modeling and Control
Ahmad Karawash, Hamid Mcheick, Mohamed Dbouk
2014 conf
DIVANet
Atif Farid Mohammad, Hamid Mcheick, Emanuel S. Grant
2014 conf
UKSim
Hamid Mcheick, Malak Khreis, Mohammad Al Kalla, Hala Sweidan
2014 conf
EUSPN/ICTH
Mohamad Dbouk, Hamid Mcheick, Ihab Sbeity
2014 conf
HCI (21)
Hamid Mcheick, Raef Mousheimish, Ali Masri, Youssef Dergham
2014 conf
IHTC
Hamid Mcheick, Hassan Sbeity, Hussein Hazimeh, Jihad Naim, Mohamad Alameh
2014 conf
FNC/MobiSPC
Hamid Mcheick, Alexandre Poirrier, Jabril Abdelaziz, Abbass Lakiss
2014 conf
CCECE
Mohammed Anouar Naoui, Hamid Mcheick, Okba Kazar
2014 conf
EUSPN/ICTH
Hamid Mcheick
2014 C conf
ISNCC
N. Jeyanthi, R. Thandeeswaran, Hamid Mcheick
2014 ch.
Big Data and Internet of Things
Ahmad Karawash, Hamid Mcheick, Mohamed Dbouk
2014 B conf
SERVICES
Khalid Elgazzar, Hanan Lutfiyya, Hamid Mcheick
2014 conf
CCECE
Hamid Mcheick, Atif Farid Mohammad
2014 conf
FNC/MobiSPC
Hamid Mcheick, Louis Deladiennee, Mickael Wajnberg, Benoit Martin, Marc Abi-Khalil
2014 J jnl
J. Softw.
Mohamed Dbouk, Ihab Sbeity, Hamid Mcheick, Haytham Douaihy
2013 conf
EUSPN/ICTH
Karam Mustapha, Hamid Mcheick, Sehl Mellouli
2013 conf
PM2HW2N@MSWiM
Karam Mustapha, Hamid Mcheick, Sehl Mellouli
2013 conf
ICAT
Mehdi Adda, Amel Hannech, Hamid Mcheick
2013 conf
ANT/SEIT
Atif Farid Mohammad, Joumana Dargham, Hamid Mcheick, Attia T. Noor
2013 conf
RACS
Hamid Mcheick, Karam Mustapha, Sehl Mellouli
2013 conf
RACS
Hamid Mcheick, Youcef Baghdadi, Naoufel Kraïem
2012 J jnl
Int. J. Bus. Data Commun. Netw.
Hamid Mcheick
2012 conf
ANT/MobiWIS
Hamid Mcheick, Ahmad Karawash
2012 conf
ICCIT
Hamid Mcheick, Yan Qi
2012 J jnl
Int. J. Web Eng. Technol.
Joumana Dargham, Rima Semaan, Hamid Mcheick
2012 conf
ICCIT
Hamid Mcheick, Shalom Dodge, Marcel Karam
2011 conf
ICCIT
Haïdar Safa, Marcel Karam, Rawad Abou Assi, Hamid Mcheick
2011 conf
ANT/MobiWIS
Atif Farid Mohammad, Hamid Mcheick
2011 conf
CCECE
Hamid Mcheick, Yan Qi
2011 conf
ICCIT
Hamid Mcheick, Yan Qi, Haïdar Safa, Marcel Karam
2011 conf
ICSOFT (1)
Hamid Mcheick, Yan Qi, Hani Charara
2011 C conf
ISADS
Hamid Mcheick, Farzad Amirjavid
2011 C conf
SERA
Hamid Mcheick, Ziad Rajih Mohammed, Abbass Lakiss
2011 J jnl
Int. J. Commun. Networks Distributed Syst.
Farzad Amirjavid, Hamid Mcheick, Mohamed Dbouk
2011 C conf
DeSE
Hamid Mcheick, Ahmad Karawash, Taha Baba
2011 conf
CCECE
Hamid Mcheick, Joumana Dargham
2011 conf
ICITCS
Hamid Mcheick, Mohamad Dbouk, Fady Dagher
2011 conf
AAL
Hamid Mcheick, Abdelali Goundafi
2011 J jnl
Int. J. Commun. Networks Distributed Syst.
Mohamed Dbouk, Ihab Sbeity, Hamid Mcheick
2011 conf
ICCIT
Marcel Karam, Haïdar Safa, Hanan Mneimneh, Joumana Dargham, Hamid Mcheick
2010 C conf
AICCSA
Hamid Mcheick, Heni Dhiab, Mohamad Dbouk, Rakan Mcheik
2010 Misc conf
PDPTA
Farzad Amirjavid, Hamid Mcheick
2010 C conf
AICCSA
Mehdi Adda, Hamid Mcheick
2010 J jnl
J. Object Technol.
Mehdi Adda, Hamid Mcheick, Hafedh Mili
2009 C conf
AICCSA
Hamid Mcheick, Aymen Sioud
2009 conf
Software Engineering Research and Practice
Hamid Mcheick, Mehdi Adda, Hafedh Mili, Mourad Badri
2009 C conf
AICCSA
Hamid Mcheick, Eric Dallaire, Hafedh Mili
2008 conf
Software Engineering Research and Practice
Hamid Mcheick, Aymen Sioud, Abdenour Bouzouane, Rakan Mcheik
2008 C conf
ICSEA
Hamid Mcheick, Aymen Sioud, Joumana Dargham
2008 C conf
AICCSA
Hamid Mcheick, Hafedh Mili, Eric Dallaire, Rakan Mcheik
2007 conf
ICSOFT (SE)
Hamid Mcheick, Hafedh Mili, Rakan Mcheik
2006 C conf
AICCSA
Hamdan Msheik, Alain Abran, Hamid Mcheick, Dimitrios Touloumis, Adel Khelifi
2006 B conf
FASE
Hafedh Mili, Houari A. Sahraoui, Hakim Lounis, Hamid Mcheick, Amal Elkharraz
2003 J jnl
Inf. Softw. Technol.
Hafedh Mili, Estelle Ah-Ki, Robert Godin, Hamid Mcheick
2002 J jnl
J. Object Technol.
Hafedh Mili, Hamid Mcheick, Salah Sadou
2002 conf
ICDCS Workshops
Hafedh Mili, Hamid Mcheick, Salah Sadou
2001 C conf
AICCSA
Hafedh Mili, Hamid Mcheick, Joumana Dargham, Salah Sadou
1997 conf
SSR
Hafedh Mili, Estelle Ah-Ki, Robert Godin, Hamid Mcheick
redb/extractors/decompiler/_archive/DecompileBinja-archive.py
← Index redb/extractors/decompiler/_archive/DecompileBinja-archive.py python
import hashlib
import inspect
import json
import os
import time
import threading
from datetime import datetime, timezone
from typing import Dict, Any, Optional

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

# Import our BinjaDecompiler (conditional)
from redb.extractors.decompiler.bninja.decompiler import BinaryNinjaDecompiler

class DecompileBinja(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)

        # Check if Binary Ninja is available
       # if not BINARYNINJA_AVAILABLE:
        #     self.log.error("Binary Ninja is not available in this container")
        #    raise ImportError(
        #        "Binary Ninja module not found - not available in feature extraction container"
        #    )
        self.analysis_results = None
        self.binja_decompiler = None
        self.filetype = filetype

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

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

    def __enter__(self):
        return self

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

    def calculate_md5(self, input_str):
        """Calculate MD5 hash of a string."""
        return hashlib.md5(input_str.encode("utf-8")).hexdigest()

    def is_dotnet(self):
        """Check if the binary is a .NET assembly.

        Returns:
            bool: True if the file is a .NET assembly, False otherwise
        """
        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:
            # BinaryNinjaDecompiler uses context manager pattern (__enter__/__exit__)
            # Cleanup happens automatically when exiting the 'with' block
            self.binja_decompiler = None

            # Force garbage collection
            import gc

            gc.collect()

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

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

        try:
            # Use BinaryNinjaDecompiler as a context manager to ensure proper setup/cleanup
            with BinaryNinjaDecompiler(
                filepath=self.filepath,
                timeout=self.BINJA_TIMEOUT,
                log=self.log,
                exporters=self.exporters,
                index_prefix=self.index_prefix,
                filetype=self.filetype,
            ) as decompiler:
                self.binja_decompiler = decompiler

                if decompiler.extract():
                    # Store results before context manager exits
                    results = decompiler.analysis_results
                    return results
                else:
                    self.log.error("BinaryNinjaDecompiler extraction failed")
                    return None

        except Exception as e:
            self.log.error(f"Error in Binary Ninja analysis: {e}")
            import traceback
            self.log.error(f"Traceback: {traceback.format_exc()}")
            return None

        finally:
            self.cleanup_run()

    def extract(self):
        """Extract and process all analysis results."""
        self.log.debug(inspect.currentframe().f_code.co_name)

        # Create a flag to track if extraction completed
        extraction_completed = False
        extraction_result = False
        extraction_error = None

        # Define the extraction process as a separate function
        def do_extraction():
            nonlocal extraction_completed, extraction_result, extraction_error
            try:
                results = self.analyze_binary()
                if not results:
                    extraction_result = False
                else:
                    self.analysis_results = results
                    extraction_result = True
            except Exception as e:
                extraction_error = e
                extraction_result = False
            finally:
                extraction_completed = True

        # Start extraction in a separate thread
        extraction_thread = threading.Thread(target=do_extraction)
        extraction_thread.daemon = True
        extraction_thread.start()

        # Wait for the extraction to complete or timeout
        start_time = time.time()
        while (
            not extraction_completed
            and (time.time() - start_time) < self.DECOMPILE_EXTRACTOR_TIMEOUT
        ):
            time.sleep(1)

        if not extraction_completed:
            self.log.error(
                f"Extraction timed out after {self.DECOMPILE_EXTRACTOR_TIMEOUT} seconds"
            )
            # Force cleanup
            self.cleanup_run()
            return None

        if extraction_error:
            self.log.error(f"Error in extraction: {extraction_error}")
            return None

        # Return the actual analysis results, not just a boolean
        return self.analysis_results if extraction_result else None

    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

        # # Delegate to the BinjaDecompiler for consistent export formatting
        # if self.binja_decompiler:
        #     return self.binja_decompiler.prepare_export_data(exporter_type)
        # else:
        #     self.log.error("BinjaDecompiler not available for export preparation")
        #     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

            # Add a helper function to handle empty strings
            def ensure_not_empty(value, default="UNKNOWN"):
                """Ensure a string value is not empty"""
                if value is None or value == "":
                    return default
                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": "code_binja_decompiled_functions_content",
                    "data": [
                        [
                            f["decompiled_function_hash"],
                            f["decompiled_function"],
                            f["function_type"],
                            now,
                        ]
                        for f in self.analysis_results["decompiled"]
                    ],
                    "column_names": [
                        "decompiled_function_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": "code_binja_decompiled_functions_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            self.analysis_results["sha1"],
                            self.analysis_results["md5"],
                            f["decompiled_function_hash"],
                            f["disassembled_function_hash"],  # New linking field
                            f["decompiled_function_name"],
                            f["decompiled_function_prototype"],
                            f["decompiled_function_address"],
                            now,
                        ]
                        for f in self.analysis_results["decompiled"]
                    ],
                    "column_names": [
                        "sha256",
                        "sha1",
                        "md5",
                        "decompiled_function_hash",
                        "disassembled_function_hash",  # New linking field
                        "decompiled_function_name",
                        "decompiled_function_prototype",
                        "decompiled_function_address",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(40)",
                        "FixedString(32)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",  # New linking field
                        "LowCardinality(String)",
                        "LowCardinality(String)",
                        "UInt64",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "disassembled_content": {
                    "table": "code_binja_disassembled_functions_content",
                    "data": [
                        [
                            f["disassembled_function_hash"],
                            f.get("disassembled_function", ""),
                            f.get("disassembled_function_no_addresses", ""),
                            f.get("function_type", "UNKNOWN"),
                            f.get("instructions_count", 0),
                            prepare_array_field(
                                f.get("instructions_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),
                            f.get("max_block_size", 0),
                            f.get("num_calls", 0),
                            f.get("stack_size", 0),
                            now,
                        ]
                        for f in self.analysis_results["disassembled"]
                    ],
                    "column_names": [
                        "disassembled_function_hash",
                        "disassembled_function",
                        "disassembled_function_no_addresses",
                        "function_type",
                        "instructions_count",
                        "instructions_types",
                        "control_flow_count",
                        "memory_access_pattern",
                        "register_usage",
                        "data_references_count",
                        "max_block_size",
                        "num_calls",
                        "stack_size",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'THUNK'=3, 'EXTERNAL'=4, 'UNKNOWN'=5)",
                        "UInt32",
                        "Array(LowCardinality(String))",
                        "UInt32",
                        "Array(LowCardinality(String))",
                        "Array(LowCardinality(String))",
                        "UInt32",
                        "Nullable(UInt32)",
                        "Nullable(UInt32)",
                        "Nullable(Int32)",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "disassembled_refs": {
                    "table": "code_binja_disassembled_functions_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            self.analysis_results["sha1"],
                            self.analysis_results["md5"],
                            f["disassembled_function_hash"],
                            f["decompiled_function_hash"],
                            f["disassembled_function_name"],
                            f["disassembled_function_address"],
                            ssdeep_disassembly(
                                f.get("disassembled_function_no_addresses", "")
                            ),
                            tlsh_disassembly(
                                f.get("disassembled_function_no_addresses", "")
                            ),
                            now,
                        ]
                        for f in self.analysis_results["disassembled"]
                    ],
                    "column_names": [
                        "sha256",
                        "sha1",
                        "md5",
                        "disassembled_function_hash",
                        "decompiled_function_hash",
                        "disassembled_function_name",
                        "disassembled_function_address",
                        "ssdeep_disassembly",
                        "tlsh_disassembly",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(40)",
                        "FixedString(32)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "UInt64",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "DateTime64(3, 'UTC')",
                    ],
                },
                "cfg_blocks": {
                    "table": "code_binja_cfg_blocks",
                    "data": [
                        [
                            b["block_id"],
                            self.analysis_results["sha256"],
                            self.analysis_results["sha1"],
                            self.analysis_results["md5"],
                            b["function_address"],
                            b["block_start_address"],
                            b["block_end_address"],
                            b["block_size"],
                            b["instructions_count"],
                            b["block_instructions"],  # MD5 hash of instructions
                            b["predecessor_blocks"],
                            b["successor_blocks"],
                            b["depth"],
                            b["position"],
                            b["branch_type"],
                            b["block_type"],
                            b["flags"],
                            b["dominators"],
                            b["post_dominators"],
                            now,
                        ]
                        # Flatten: iterate through all functions, then all blocks in each function
                        for func_cfg in self.analysis_results["cfg"]
                        if func_cfg is not None  # Handle None from failed extractions
                        for b in func_cfg["blocks"]
                    ],
                    "column_names": [
                        "block_id",
                        "sha256",
                        "sha1",
                        "md5",
                        "function_address",
                        "block_start_address",
                        "block_end_address",
                        "block_size",
                        "instructions_count",
                        "block_instructions_hash",
                        "predecessor_blocks",
                        "successor_blocks",
                        "depth",
                        "position",
                        "branch_type",
                        "block_type",
                        "flags",
                        "dominators",
                        "post_dominators",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",  # block_id (SHA256)
                        "FixedString(64)",  # sha256
                        "FixedString(40)",  # sha1
                        "FixedString(32)",  # md5
                        "UInt64",  # function_address
                        "UInt64",  # block_start_address
                        "UInt64",  # block_end_address
                        "UInt32",  # block_size
                        "UInt16",  # instructions_count
                        "FixedString(32)",  # block_instructions_hash (MD5)
                        "Array(UInt64)",  # predecessor_blocks
                        "Array(UInt64)",  # successor_blocks
                        "UInt16",  # depth
                        "UInt16",  # position
                        "Enum8('DIRECT'=1, 'CONDITIONAL'=2, 'CALL'=3, 'RETURN'=4, 'FALLTHROUGH'=5, 'INDIRECT'=6, 'UNKNOWN'=7)",  # branch_type
                        "Enum8('CODE'=1, 'DATA'=2, 'THUNK'=3)",  # block_type
                        "Array(String)",  # flags (EntryBlock, ExitBlock, LoopBlock)
                        "Array(UInt16)",  # dominators
                        "Array(UInt16)",  # post_dominators
                        "DateTime64(3, 'UTC')",  # analysis_date
                    ],
                },
                "function_analysis_errors": {
                    "table": "function_analysis_errors_binja",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["function_name"],
                            f["function_address"],
                            f.get("error_location", "unknown"),
                            f.get("error_message", ""),
                            f.get("error_details", ""),
                            f.get("error_type", "unknown"),
                            self.calculate_md5(
                                f"{f['error_message']}{f['function_name']}{f['function_address']}{f['error_location']}"
                            ),
                            "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)",
                        "UInt64",
                        "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


if __name__ == "__main__":
    # Setup basic logging
    import logging

    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger("DecompileBinja")

    # Parse command line arguments
    import argparse

    parser = argparse.ArgumentParser(description="Binary Ninja Decompiler Wrapper")
    parser.add_argument("filepath", help="Path to the binary file to analyze")
    parser.add_argument(
        "--output", "-o", help="Output JSON file path (default: stdout)"
    )
    parser.add_argument(
        "--timeout",
        "-t",
        type=int,
        default=1200,
        help="Analysis timeout in seconds (default: 1200)",
    )
    args = parser.parse_args()

    # Create and run the extractor
    with DecompileBinja(args.filepath, logger) as extractor:
        success = extractor.extract()

        if not success:
            logger.error("Analysis failed")
            exit(1)

        # Output results
        if args.output:
            with open(args.output, "w") as f:
                json.dump(extractor.analysis_results, f)
            logger.info(f"Results written to {args.output}")
        else:
            print(json.dumps(extractor.analysis_results))