Karl N. Levitt

129 papers A* 8A 17B 6C 15Journal 31Unranked 51
YearRankTypeTitle / Venue / Authors
2024 conf
JOWO
Richard Hull, Matt Bishop, Joseph Gendreau, Karl N. Levitt, Mohammad Sadoghi, Matthew Lange
2022 C conf
NSPW
Michael Clifford, Miriam Heller, Karl N. Levitt, Matt Bishop
2022 J jnl
CoRR
Nidhi Rastogi, Sara Rampazzi, Michael Clifford, Miriam Heller, Matt Bishop, Karl N. Levitt
2018 C conf
NSPW
Matt Bishop, Carrie Gates, Karl N. Levitt
2016 conf
CNS
Azeem Aqil, Ahmed Osama Fathy Atya, Srikanth V. Krishnamurthy, Paul L. Yu, Ananthram Swami, Jeff Rowe, Karl N. Levitt, Alexander Poylisher, Constantin Serban, Ritu Chadha
2016 B conf
NCA
Sisi Duan, Yun Li, Karl N. Levitt
2016 J jnl
Argument Comput.
Andy Applebaum, Zimi Li, Karl N. Levitt, Simon Parsons, Jeff Rowe, Elizabeth I. Sklar
2016 conf
IEEE Symposium on Security and Privacy Workshops
Bogdan Copos, Karl N. Levitt, Matt Bishop, Jeff Rowe
2016 conf
MILCOM
Z. Berkay Celik, Nan Hu, Yun Li, Nicolas Papernot, Patrick D. McDaniel, Robert J. Walls, Jeff Rowe, Karl N. Levitt, Novella Bartolini, Thomas F. La Porta, Ritu Chadha
2016 conf
INFOCOM Workshops
Parisa Kianmajd, Jeff Rowe, Karl N. Levitt
2016 conf
IoTBD
Bogdan Copos, Karl N. Levitt, Jeff Rowe, Parisa Kianmajd, Chen-Nee Chuah, George Kesidis
2015 conf
MILCOM
Conner Jackson, Karl N. Levitt, Jeff Rowe, Srikanth V. Krishnamurthy, Trent Jaeger, Ananthram Swami
2015 conf
MILCOM
Andy Applebaum, Karl N. Levitt, Zimi Li, Simon Parsons, Jeff Rowe, Elizabeth Sklar
2015 conf
MILCOM
Azeem Aqil, Ahmed Osama Fathy Atya, Trent Jaeger, Srikanth V. Krishnamurthy, Karl N. Levitt, Patrick D. McDaniel, Jeff Rowe, Ananthram Swami
2015 J jnl
EURASIP J. Adv. Signal Process.
Yuquan Shan, Jayaram Raghuram, George Kesidis, David J. Miller, Anna Scaglione, Jeff Rowe, Karl N. Levitt
2015 J jnl
IEEE Commun. Mag.
Mani Amoozadeh, Arun Raghuramu, Chen-Nee Chuah, Dipak Ghosal, H. Michael Zhang, Jeff Rowe, Karl N. Levitt
2015 J jnl
IEEE Trans. Dependable Secur. Comput.
Sisi Duan, Sean Peisert, Karl N. Levitt
2014 conf
Feedback Computing
Jayaram Raghuram, George Kesidis, Christopher Griffin, Karl N. Levitt, David J. Miller, Jeff Rowe, Anna Scaglione
2014 J jnl
Argument Comput.
Simon Parsons, Katie Atkinson, Zimi Li, Peter McBurney, Elizabeth Sklar, Munindar P. Singh, Karen Zita Haigh, Karl N. Levitt, Jeff Rowe
2014 B conf
SRDS
Sisi Duan, Karl N. Levitt, Hein Meling, Sean Peisert, Haibin Zhang
2014 J jnl
CoRR
Yuquan Shan, Jayaram Raghuram, George Kesidis, Christopher Griffin, Karl N. Levitt, David J. Miller, Jeff Rowe, Anna Scaglione
2014 J jnl
CoRR
Mahnoosh Alizadeh, Anna Scaglione, Andy Applebaum, George Kesidis, Karl N. Levitt
2013 conf
AAAI Spring Symposium: Trust and Autonomous Systems
Simon Parsons, Elizabeth Sklar, Munindar P. Singh, Karl N. Levitt, Jeff Rowe
2013 C conf
NSPW
Jeff Rowe, Karl N. Levitt, Mike Hogarth
2012 C conf
COMMA
Andy Applebaum, Karl N. Levitt, Jeff Rowe, Simon Parsons
2012 C conf
COMMA
Simon Parsons, Katie Atkinson, Karen Zita Haigh, Karl N. Levitt, Peter McBurney, Jeff Rowe, Munindar P. Singh, Elizabeth Sklar
2012 C conf
NSPW
Jeff Rowe, Karl N. Levitt, Simon Parsons, Elizabeth Sklar, Andy Applebaum, Sharmin Jalal
2011 B conf
ASONAM
Ruaylong Lee, Roozbeh Nia, Jason Hsu, Karl N. Levitt, Jeff Rowe, Shyhtsun Felix Wu, Shaozhi Ye
2008 conf
SECURWARE
Xiaoming Lu, Matt Spear, Karl N. Levitt, Norman S. Matloff, Shyhtsun Felix Wu
2008 A conf
RAID
Senthilkumar G. Cheetancheri, John Mark Agosta, Karl N. Levitt, Shyhtsun Felix Wu, Jeff Rowe
2008 conf
ICC
Xiaoming Lu, Matt Spear, Karl N. Levitt, Norman S. Matloff, Shyhtsun Felix Wu
2008 A* conf
INFOCOM
Xiaoming Lu, Matt Spear, Karl N. Levitt, Shyhtsun Felix Wu
2007 A conf
AsiaCCS
Lynette Qu Nguyen, Tufan Demir, Jeff Rowe, Francis Hsu, Karl N. Levitt
2007 A conf
RAID
Shiau-Huey Wang, Chinyang Henry Tseng, Karl N. Levitt, Matt Bishop
2007 A conf
AsiaCCS
Chinyang Henry Tseng, Shiau-Huey Wang, Karl N. Levitt
2007 A* conf
DAC
Cynthia E. Irvine, Karl N. Levitt
2006 conf
LSAD@SIGCOMM
Senthilkumar G. Cheetancheri, John Mark Agosta, Denver Dash, Karl N. Levitt, Jeff Rowe, Eve M. Schooler
2006 A conf
RAID
Chinyang Henry Tseng, Shiau-Huey Wang, Calvin Ko, Karl N. Levitt
2006 C conf
NSPW
Rick Crawford, Matt Bishop, Bhume Bhumiratana, Lisa Clark, Karl N. Levitt
2006 C conf
WETICE
Matt Bishop, Rick Crawford, Bhume Bhumiratana, Lisa Clark, Karl N. Levitt
2006 C conf
IPCCC
Senthilkumar G. Cheetancheri, Denys L. Ma, Karl N. Levitt, Todd L. Heberlein
2006 B conf
DIMVA
Ebrima N. Ceesay, Jingmin Zhou, Michael Gertz, Karl N. Levitt, Matt Bishop
2005 conf
IWIA
Daniel F. Sterne, Poornima Balasubramanyam, David Carman, Brett Wilson, Rajesh Talpade, Calvin Ko, Ravindra Balupari, Chinyang Henry Tseng, Thomas F. Bowen, Karl N. Levitt, Jeff Rowe
2005 conf
IWAN
Marcus Tylutki, Karl N. Levitt
2005 A conf
RAID
Chinyang Henry Tseng, Tao Song, Poornima Balasubramanyam, Calvin Ko, Karl N. Levitt
2005 conf
Formal Aspects in Security and Trust
Tao Song, Calvin Ko, Chinyang Henry Tseng, Poornima Balasubramanyam, Anant Chaudhary, Karl N. Levitt
2004 conf
WORM
Phillip A. Porras, Linda Briesemeister, Keith Skinner, Karl N. Levitt, Jeff Rowe, Yu-Cheng Allen Ting
2004 conf
NOMS (1)
Archana Pasupulati, Jason Coit, Karl N. Levitt, Shyhtsun Felix Wu, S. H. Li, J. C. Kuo, K. P. Fan
2004 J jnl
Commun. ACM
Ruzena Bajcsy, Terry Benzel, Matt Bishop, Robert Braden, Carla E. Brodley, Sonia Fahmy, Sally Floyd, Wes Hardaker, Anthony D. Joseph, George Kesidis, Karl N. Levitt, Robert Lindell, Peng Liu, David J. Miller, Russ Mundy, Clifford Neuman, Ron Ostrenga, Vern Paxson, Phillip A. Porras, Catherine Rosenberg, J. Doug Tygar, Shankar Sastry, Daniel F. Sterne, Shyhtsun Felix Wu
2004 A conf
RAID
Tao Song, Calvin Ko, Jim Alves-Foss, Cui Zhang, Karl N. Levitt
2004 C conf
WETICE
Matt Bishop, Bhume Bhumiratana, Rick Crawford, Karl N. Levitt
2003 conf
SASN
Chinyang Henry Tseng, Poornima Balasubramanyam, Calvin Ko, Rattapon Limprasittiporn, Jeff Rowe, Karl N. Levitt
2003 A conf
ACSAC
Tye Stallard, Karl N. Levitt
2003 conf
DISCEX (1)
D. Nojiri, Jeff Rowe, Karl N. Levitt
2003 C conf
ICMLA
Melissa Danforth, Karl N. Levitt
2003 A conf
RAID
Marcus Tylutki, Karl N. Levitt
2003 conf
DISCEX (2)
Calvin Ko, Karl N. Levitt
2003 A conf
RAID
Ivan Balepin, Sergei Maltsev, Jeff Rowe, Karl N. Levitt
2002 A conf
ACSAC
Dustin Lee, Jeff Rowe, Calvin Ko, Karl N. Levitt
2002 A conf
ACSAC
Karl N. Levitt
2002 A conf
RAID
James E. Just, James C. Reynolds, Larry A. Clough, Melissa Danforth, Karl N. Levitt, Ryan Maglich, Jeff Rowe
2002 A conf
DSN
James C. Reynolds, James E. Just, Ed Lawson, Larry A. Clough, Ryan Maglich, Karl N. Levitt
2001 conf
Recent Advances in Intrusion Detection
Calvin Ko, Paul Brutch, Jeff Rowe, Guy Tsafnat, Karl N. Levitt
2000 A conf
DSN
Steven Cheung, Karl N. Levitt
2000 B conf
DBSec
Christina Yip Chung, Michael Gertz, Karl N. Levitt
2000 J jnl
Comput. Networks
Richard J. Feiertag, Stuart Staniford-Chen, Karl N. Levitt, Mark R. Heckman, Dave Peticolas, Rick Crawford, Lee A. Benzinger, Sue Rho, Stephen Wu
1999 conf
IICIS
Christina Yip Chung, Michael Gertz, Karl N. Levitt
1999 J jnl
Theor. Comput. Sci.
Cui Zhang, Ronald A. Olsson, Karl N. Levitt
1999 conf
Recent Advances in Intrusion Detection
Richard J. Feiertag, Stuart Staniford-Chen, Karl N. Levitt, Mark R. Heckman, Dave Peticolas, Rick Crawford, Lee A. Benzinger, Sue Rho, Stephen Wu
1999 J jnl
Softw. Test. Verification Reliab.
Cui Zhang, Brian R. Becker, Dave Peticolas, Ronald A. Olsson, Karl N. Levitt
1999 conf
Recent Advances in Intrusion Detection
Christina Yip Chung, Michael Gertz, Karl N. Levitt
1998 conf
HICSS (3)
Mark R. Heckman, Karl N. Levitt
1998 conf
CSFW
Raymond W. Yip, Karl N. Levitt
1998 J jnl
CoRR
James A. Hoagland, Raju Pandey, Karl N. Levitt
1998 B conf
DBSec
Raymond W. Yip, Karl N. Levitt
1997 conf
S&P
Calvin Ko, Manfred Ruschitzka, Karl N. Levitt
1997 C conf
NSPW
Steven Cheung, Karl N. Levitt
1997 J jnl
Softw. Test. Verification Reliab.
Raymond W. Lo, Karl N. Levitt, Ronald A. Olsson
1997 conf
HICSS (5)
Cui Zhang, Brian R. Becker, Dave Peticolas, Mark R. Heckman, Karl N. Levitt, Ronald A. Olsson
1996 A* conf
USENIX Security Symposium
Dan Zerkle, Karl N. Levitt
1996 conf
TPHOLs
Mark R. Heckman, Cui Zhang, Brian R. Becker, Dave Peticolas, Karl N. Levitt, Ronald A. Olsson
1995 conf
TPHOLs
Cui Zhang, Brian R. Becker, Mark R. Heckman, Karl N. Levitt, Ronald A. Olsson
1995 J jnl
Comput. Secur.
Raymond W. Lo, Karl N. Levitt, Ronald A. Olsson
1994 A conf
ACSAC
Calvin Ko, George Fink, Karl N. Levitt
1994 J jnl
IEEE Netw.
Biswanath Mukherjee, Todd L. Heberlein, Karl N. Levitt
1994 A conf
ACSAC
George Fink, Karl N. Levitt
1993 A* conf
CCS
Calvin Ko, Deborah A. Frincke, Terrance Goan, Todd L. Heberlein, Karl N. Levitt, Biswanath Mukherjee, Christopher Wee
1993 conf
HUG
Cui Zhang, Robert J. Shaw, Ronald A. Olsson, Karl N. Levitt, Myla Archer, Mark R. Heckman, Gregory D. Benson
1993 conf
HUG
Tej Arora, Tony Leung, Karl N. Levitt, E. Thomas Schubert, Phillip J. Windley
1992 conf
TPHOLs
William L. Harrison, Myla Archer, Karl N. Levitt
1992 conf
TPHOLs
Saraswati Kalvala, Myla Archer, Karl N. Levitt
1992 ed.
TPHOLs
Myla Archer, Jeffrey J. Joyce, Karl N. Levitt, Phillip J. Windley
1992 conf
TPHOLs
Jing Pan, Karl N. Levitt, Myla Archer, Saraswati Kalvala
1991 conf
Compcon
Steven R. Snapp, James Brentano, Gihan V. Dias, Terrance Goan, Tim Grance, Todd L. Heberlein, Che-Lin Ho, Karl N. Levitt, Biswanath Mukherjee, Douglass L. Mansur, Kenneth L. Pon, Stephen E. Smaha
1991 C conf
RSP
Deborah A. Frincke, Genc L. Fisher, Myla Archer, Karl N. Levitt
1991 conf
KBSE
Deborah A. Frincke, Myla Archer, Karl N. Levitt
1991 C conf
RSP
Myla Archer, James Bock, Deborah A. Frincke, Karl N. Levitt
1991 conf
TPHOLs
Jim Alves-Foss, Karl N. Levitt
1991 conf
TPHOLs
William L. Harrison, Karl N. Levitt
1991 conf
Compcon
Jim Alves-Foss, Karl N. Levitt
1991 conf
Compcon
Raymond W. Lo, P. Kerchen, Richard H. Crawford, W. Wilson Ho, J. Crossley, George Fink, Karl N. Levitt, Ronald A. Olsson, Myla Archer
1991 conf
S&P
Jim Alves-Foss, Karl N. Levitt
1990 conf
S&P
L. Todd Herberlein, Gihan V. Dias, Karl N. Levitt, Biswanath Mukherjee, Jeff Wood, David Wolber
1990 C conf
RSP
Myla Archer, Deborah A. Frincke, Karl N. Levitt
1985 J jnl
ACM SIGSOFT Softw. Eng. Notes
Karl N. Levitt, R. Alan Whitehurst
1981 J jnl
ACM SIGSOFT Softw. Eng. Notes
Karl N. Levitt, Peter G. Neumann
1979 conf
The Use of Formal Specification of Software
Karl N. Levitt, Lawrence Robinson, Brad A. Silverberg
1978 J jnl
Commun. ACM
Jay M. Spitzen, Karl N. Levitt, Lawrence Robinson
1977 J jnl
Commun. ACM
Lawrence Robinson, Karl N. Levitt
1977 A* conf
SOSP
Richard J. Feiertag, Karl N. Levitt, Lawrence Robinson
1976 A* conf
ICSE
Peter G. Neumann, Richard J. Feiertag, Karl N. Levitt, Lawrence Robinson
1976 A* conf
ICSE
John H. Wensley, Milton W. Green, Karl N. Levitt, Robert E. Shostak
1975 conf
Reliable Software
Lawrence Robinson, Karl N. Levitt, Peter G. Neumann, Ashok R. Saxena
1975 conf
Reliable Software
Robert S. Boyer, Bernard Elspas, Karl N. Levitt
1974 J jnl
IEEE Trans. Computers
Jack Goldberg, Karl N. Levitt, John H. Wensley
1974 J jnl
Artif. Intell.
Richard J. Waldinger, Karl N. Levitt
1973 A* conf
POPL
Richard J. Waldinger, Karl N. Levitt
1973 conf
SIGPLAN-SIGOPS Interface Meeting
Karl N. Levitt
1972 J jnl
ACM Comput. Surv.
Bernard Elspas, Karl N. Levitt, Richard J. Waldinger, Abraham Waksman
1972 J jnl
Commun. ACM
Karl N. Levitt, William H. Kautz
1972 conf
AFIPS Fall Joint Computing Conference (1)
Karl N. Levitt
1971 J jnl
Computer
Bernard Elspas, Milton W. Green, Karl N. Levitt
1970 J jnl
IEEE Trans. Computers
Karl N. Levitt
1969 J jnl
IEEE Trans. Inf. Theory
William H. Kautz, Karl N. Levitt
1969 J jnl
IEEE Trans. Inf. Theory
Karl N. Levitt, William H. Kautz
1969 J jnl
IEEE Trans. Computers
Eugene L. Lawler, Karl N. Levitt, James Turner
1968 conf
AFIPS Spring Joint Computing Conference
Karl N. Levitt, Milton W. Green, Jack Goldberg
1968 J jnl
IEEE Trans. Computers
William H. Kautz, Karl N. Levitt, Abraham Waksman
1967 J jnl
IEEE Trans. Inf. Theory
Karl N. Levitt, Jack K. Wolf
redb/extractors/decompiler/DecompileBinja.py
← Index redb/extractors/decompiler/DecompileBinja.py python
import hashlib
import inspect
import json
import logging
import os
import signal
import time
from datetime import datetime, timezone
from typing import Dict, Any, Optional
from pathlib import Path
import subprocess
import sys

from redb.extractors.enum import Tag
from redb.extractors.extractor import Extractor
import magic
import pefile
from elftools.elf.elffile import ELFFile

# 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,
        decompile_modules=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
        self.decompile_modules = decompile_modules or {"all"}
        self.goresym_data = None
        self.goresym_output_path = None

        # 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
            return False
        except AttributeError as e:
            self.log.error(
                f"AttributeError error dotnet file {self.hash.sha256} Full error : {e}"
            )
            return False

    def is_golang(self):
        """Check if the binary is a Go-compiled binary (heuristic).

        Supports PE and ELF binaries.
        """
        try:
            if self.filetype == "pebin":
                pe = pefile.PE(self.filepath)
                signatures = [b"Go build ID:", b"runtime.main", b"main.main"]

                for section in pe.sections:
                    data = section.get_data()
                    if any(sig in data for sig in signatures):
                        return True

                return False

            elif self.filetype == "elf":
                with open(self.filepath, "rb") as f:
                    elf = ELFFile(f)

                    # 1. Section-based checks
                    section_names = [sec.name for sec in elf.iter_sections()]
                    if any(
                        s in section_names
                        for s in (".note.go.buildid", ".gopclntab")
                    ):
                        return True

                    # 2. String scan in loadable sections
                    signatures = [
                        b"Go build ID:",
                        b"runtime.main",
                        b"runtime.goexit",
                        b"runtime.morestack",
                        b"main.main",
                    ]

                    for sec in elf.iter_sections():
                        if sec["sh_flags"] & 0x2:  # SHF_ALLOC
                            data = sec.data()
                            if any(sig in data for sig in signatures):
                                return True

                return False

            return False

        except Exception as e:
            self.log.error(
                f"Golang detection error {self.hash.sha256}: {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

            # Clean up goresym temp file if it exists (keep in debug mode)
            if self.goresym_output_path and os.path.exists(self.goresym_output_path):
                if self.log.isEnabledFor(logging.DEBUG):
                    self.log.debug(f"Debug mode: keeping goresym output at {self.goresym_output_path}")
                else:
                    os.remove(self.goresym_output_path)
                    self.goresym_output_path = None

            # Force garbage collection
            import gc

            gc.collect()

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

    def run_goresym(self, binary_path, output_json_path):
        """
            Run goresym on a Go binary and export its JSON output to a file.
            binary_path: path to the Go binary to analyze
            output_json_path: path where the JSON output will be saved
            """
        binary_path = str(Path(binary_path).resolve())
        output_json_path = str(Path(output_json_path).resolve())
        goresym_path = os.getenv("GORESYM_PATH", "GoReSym")

        try:
            # Example: goresym -t json /path/to/binary
            self.log.info("DEBUG: starting GoReSym")
            result = subprocess.run(
                [goresym_path, binary_path],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
            )
        except FileNotFoundError:
            self.log.error("Error: 'goresym' not found in PATH. Make sure it is installed.")
            raise
        except subprocess.CalledProcessError as e:
            self.log.error("Error during goresym execution:")
            self.log.error(e.stderr)


        # Assuming goresym emits valid JSON to stdout.
        try:
            parsed = json.loads(result.stdout)
            # Store parsed JSON for later export to ClickHouse
            self.goresym_data = parsed
        except json.JSONDecodeError:
            # If it's not valid JSON, save the raw output instead.
            self.log.error("Warning: goresym output is not valid JSON; saving raw.")
            with open(output_json_path, "w", encoding="utf-8") as f:
                f.write(result.stdout)
            return

        # Save pretty-printed JSON for readability and debugging (used by BinaryNinja)
        with open(output_json_path, "w", encoding="utf-8") as f:
            json.dump(parsed, f, ensure_ascii=False, indent=2)
        self.goresym_output_path = output_json_path

        self.log.debug(f"goresym output saved to: {output_json_path}")

    def analyze_binary(self) -> Optional[Dict[str, Any]]:
        """Run Binary Ninja analysis and return results."""
        self.log.debug("Starting binary analysis")
        # if the binary is dotnet (only PE)
        if self.is_dotnet():
            self.log.debug("Skipping .NET binary - decompilation not supported")
            return None

        output_json_path = None
        ## if golang: run goresym
        try:
            if self.is_golang():
                output_json_path = "./goResym.json"
                self.run_goresym(self.filepath, output_json_path)
        except Exception as e:
            self.log.error(f"Error on GoReSym extraction: {e}")

        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,
                goresym=output_json_path,
                decompile_modules=self.decompile_modules,
            ) 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
                    # Add file hashes from parent Extractor class to analysis results
                    self.analysis_results["sha256"] = self.sha256
                    self.analysis_results["sha1"] = self.sha1
                    self.analysis_results["md5"] = self.md5
                    extraction_result = True
            except Exception as e:
                extraction_error = e
                extraction_result = False
            finally:
                extraction_completed = True

        # Run extraction directly with signal-based timeout (no thread overhead).
        # SIGALRM is delivered by the OS, so there's no GIL contention or polling.
        old_handler = signal.getsignal(signal.SIGALRM)
        def _timeout_handler(signum, frame):
            raise TimeoutError("Extraction timed out")

        signal.signal(signal.SIGALRM, _timeout_handler)
        signal.alarm(self.DECOMPILE_EXTRACTOR_TIMEOUT)
        try:
            do_extraction()
        except TimeoutError:
            self.log.error(
                f"Extraction timed out after {self.DECOMPILE_EXTRACTOR_TIMEOUT} seconds"
            )
            self.cleanup_run()
            return None
        finally:
            signal.alarm(0)
            signal.signal(signal.SIGALRM, old_handler)

        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 prepare_register_usage_map(register_dict):
                """Convert register usage dict to Map format with tuples
                Input: {"rbx": {"reads": 3, "writes": 1}, ...}
                Output: {"rbx": (3, 1), ...}
                """
                if not register_dict:
                    return {}
                return {
                    reg: (info.get("reads", 0), info.get("writes", 0))
                    for reg, info in register_dict.items()
                }


            decompile_modules = getattr(self, "decompile_modules", {"all"})
            run_all = "all" in decompile_modules
            run_decompilation = run_all or "decompilation" in decompile_modules
            run_disassembly = run_all or "disassembly" in decompile_modules
            run_llil = run_all or "llil" in decompile_modules
            run_cfg = run_all or "cfg" in decompile_modules
            run_strings = run_all or "strings" in decompile_modules

            export = {"multi_table": True}

            # Decompilation tables
            if run_decompilation:
                export["decompiled_content"] = {
                    "table": "code_binja_decompiled_functions_content",
                    "data": [
                        [
                            f["decompiled_function_hash"],
                            f["decompiled_function"],
                            f["function_type"],
                            f.get("flattened_score"),
                            f.get("mba_score"),
                            now,
                        ]
                        for f in self.analysis_results["decompiled"]
                    ],
                    "column_names": [
                        "decompiled_function_hash",
                        "decompiled_function",
                        "function_type",
                        "flattened_score",
                        "mba_score",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'THUNK'=3, 'EXTERNAL'=4, 'UNKNOWN'=5)",
                        "Nullable(Float64)",
                        "Nullable(Float64)",
                        "DateTime64(3, 'UTC')",
                    ],
                }
                export["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.get("disassembled_function_hash"),
                            f["decompiled_function_name"],
                            f["decompiled_function_prototype"],
                            f["decompiled_function_address"],
                            prepare_array_field(f.get("functions_caller"), "Array(String)"),
                            prepare_array_field(f.get("functions_call"), "Array(String)"),
                            now,
                        ]
                        for f in self.analysis_results["decompiled"]
                    ],
                    "column_names": [
                        "sha256",
                        "sha1",
                        "md5",
                        "decompiled_function_hash",
                        "disassembled_function_hash",
                        "decompiled_function_name",
                        "decompiled_function_prototype",
                        "decompiled_function_address",
                        "functions_caller",
                        "functions_call",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(40)",
                        "FixedString(32)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "LowCardinality(String)",
                        "UInt64",
                        "Array(String)",
                        "Array(String)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Disassembly tables
            if run_disassembly:
                export["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"),
                            f.get("num_calls"),
                            f.get("stack_size"),
                            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')",
                    ],
                }
                export["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.get("decompiled_function_hash"),
                            f["disassembled_function_name"],
                            f["disassembled_function_address"],
                            f.get("tlsh_disassembly"),
                            f.get("tlsh_llil"),
                            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",
                        "tlsh_disassembly",
                        "tlsh_llil",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(40)",
                        "FixedString(32)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "UInt64",
                        "Nullable(FixedString(72))",
                        "Nullable(FixedString(72))",
                        "DateTime64(3, 'UTC')",
                    ],
                }
                # Function similarity metrics table (derived from disassembly data)
                # Lookup maps to join LLIL/MLIL features by disassembled_function_hash
                llil_by_hash = {
                    l.get("disassembled_function_hash"): l
                    for l in self.analysis_results.get("llil", [])
                    if l and l.get("disassembled_function_hash")
                }
                mlil_by_hash = {
                    m.get("disassembled_function_hash"): m
                    for m in self.analysis_results.get("mlil", [])
                    if m and m.get("disassembled_function_hash")
                }

                export["function_similarity_metrics"] = {
                    "table": "code_binja_function_similarity_metrics",
                    "data": [
                        [
                            f["disassembled_function_hash"],
                            f.get("cyclomatic_complexity"),
                            f.get("tlsh_disassembly"),
                            f.get("tlsh_llil"),
                            prepare_array_field(f.get("minhash"), "Array(UInt8)"),
                            (llil_by_hash.get(f["disassembled_function_hash"]) or {}).get("tlsh_llil"),
                            (llil_by_hash.get(f["disassembled_function_hash"]) or {}).get(
                                "tlsh_instruction_typed_llil"),
                            prepare_array_field(
                                (llil_by_hash.get(f["disassembled_function_hash"]) or {}).get("minhash_llil_skeleton"),
                                "Array(UInt8)",
                            ),
                            prepare_array_field(
                                (llil_by_hash.get(f["disassembled_function_hash"]) or {}).get("minhash_llil_typed"),
                                "Array(UInt8)",
                            ),
                            (mlil_by_hash.get(f["disassembled_function_hash"]) or {}).get("tlsh_mlil_skeleton"),
                            (mlil_by_hash.get(f["disassembled_function_hash"]) or {}).get("tlsh_mlil_typed"),
                            prepare_array_field(
                                (mlil_by_hash.get(f["disassembled_function_hash"]) or {}).get("minhash_mlil_skeleton"),
                                "Array(UInt8)",
                            ),
                            prepare_array_field(
                                (mlil_by_hash.get(f["disassembled_function_hash"]) or {}).get("minhash_mlil_typed"),
                                "Array(UInt8)",
                            ),
                            now,
                        ]
                        for f in self.analysis_results.get("disassembled", [])
                    ],
                    "column_names": [
                        "disassembled_function_hash",
                        "cyclomatic_complexity",
                        "tlsh_disassembly",
                        "tlsh_llil",
                        "minhash",
                        "tlsh_llil_new",
                        "tlsh_instruction_typed_llil",
                        "minhash_llil_skeleton",
                        "minhash_llil_typed",
                        "tlsh_mlil_skeleton",
                        "tlsh_mlil_typed",
                        "minhash_mlil_skeleton",
                        "minhash_mlil_typed",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Nullable(UInt16)",
                        "Nullable(FixedString(72))",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        # new
                        "Nullable(FixedString(72))",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "Array(UInt8)",
                        "Nullable(FixedString(72))",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "Array(UInt8)",
                        "DateTime64(3, 'UTC')",
                    ],
                }


            # LLIL tables
            if run_llil:
                export["llil_content"] = {
                    "table": "code_binja_llil_functions_content",
                    "data": [
                        [
                            f["sha256_llil"],
                            f["function_type"],
                            prepare_array_field(
                                f.get("instructions_types_llil"), "LowCardinality(String)"
                            ),
                            f.get("control_flow_count_llil", 0),
                            prepare_array_field(
                                f.get("memory_access_pattern_llil"), "LowCardinality(String)"
                            ),
                            prepare_register_usage_map(f.get("register_usage", {})),
                            f.get("total_reg_reads", 0),
                            f.get("total_reg_written", 0),
                            f.get("data_references_count", 0),
                            f.get("max_block_size"),
                            f.get("num_calls"),
                            f.get("stack_size"),
                            prepare_array_field(f.get("body_llil_vector"), "Array(Tuple(UInt32, Array(UInt16)))"),
                            now,
                        ]
                        for f in self.analysis_results.get("llil", [])
                    ],
                    "column_names": [
                        "llil_function_hash",
                        "function_type",
                        "instructions_types_llil",
                        "control_flow_count_llil",
                        "memory_access_pattern_llil",
                        "register_usage_llil",
                        "total_reg_reads",
                        "total_reg_written",
                        "data_references_count",
                        "max_block_size",
                        "num_calls",
                        "stack_size",
                        "body_llil_vector",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'THUNK'=3, 'EXTERNAL'=4, 'UNKNOWN'=5)",
                        "Array(LowCardinality(String))",
                        "UInt32",
                        "Array(LowCardinality(String))",
                        "Map(LowCardinality(String), Tuple(UInt32, UInt32))",
                        "UInt32",
                        "UInt32",
                        "UInt32",
                        "Nullable(UInt32)",
                        "Nullable(UInt32)",
                        "Nullable(Int32)",
                        "Array(Tuple(UInt32, Array(UInt16)))",
                        "DateTime64(3, 'UTC')",
                    ],
                }
                export["llil_refs"] = {
                    "table": "code_binja_llil_functions_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            self.analysis_results["sha1"],
                            self.analysis_results["md5"],
                            f.get("sha256_llil"),
                            f.get("disassembled_function_hash"),
                            f.get("function_address"),
                            f.get("tlsh_disassembly"),
                            f.get("tlsh_llil"),
                            now,
                        ]
                        for f in self.analysis_results.get("llil", [])
                    ],
                    "column_names": [
                        "sha256",
                        "sha1",
                        "md5",
                        "llil_function_hash",
                        "disassembled_function_hash",
                        "function_address",
                        "tlsh_disassembly",
                        "tlsh_llil",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(40)",
                        "FixedString(32)",
                        "Nullable(FixedString(64))",
                        "FixedString(64)",
                        "UInt64",
                        "Nullable(FixedString(72))",
                        "Nullable(FixedString(72))",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Errors table (always include if per-function loop ran)
            if run_decompilation or run_disassembly or run_llil or run_cfg:
                export["function_analysis_errors"] = {
                    "table": "new_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.get('error_message', '')}{f['function_name']}{f['function_address']}{f.get('error_location', 'unknown')}"
                            ),
                            "new",
                            now,
                        ]
                        for f in self.analysis_results.get("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')",
                    ],
                }

            # Strings table
            if run_strings:
                export["strings_raw"] = {
                    "table": "code_binja_strings_raw",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            s["string"],
                            s["string_raw"],
                            s["string_encoding"],
                            s["string_offset"],
                            s["string_length"],
                            s["string_raw_length"],
                            s["string_entropy"],
                        ]
                        for s in self.analysis_results.get("strings", [])
                    ],
                    "column_names": [
                        "sha256",
                        "string",
                        "string_raw",
                        "string_encoding",
                        "string_offset",
                        "string_length",
                        "string_raw_length",
                        "string_entropy",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "String",
                        "LowCardinality(String)",
                        "UInt64",
                        "UInt32",
                        "UInt32",
                        "Float32",
                    ],
                }

            # CFG function-level features table
            if run_cfg:
                export["cfg_functions"] = {
                    "table": "code_binja_cfg_functions",
                    "data": [
                        [
                            cfg.get("disassembled_function_hash"),
                            cfg["cfg_topology_hash"],
                            cfg["block_count"],
                            cfg["edge_count"],
                            cfg.get("llil_total_operations", 0),
                            cfg.get("call_count", 0),
                            cfg["cyclomatic_complexity"],
                            cfg.get("loop_count", 0),
                            cfg.get("max_depth", 0),
                            cfg.get("max_fan_out", 0),
                            cfg.get("md_index_topdown", 0),
                            cfg.get("md_index_bottomup", 0),
                            cfg.get("prime_product_llil", 0),
                            cfg.get("cfg_feature_tlsh"),
                            cfg.get("wl_minhash", []),
                            cfg.get("bb_features", []),
                            cfg.get("cfg_adjacency", []),
                            now,
                        ]
                        for cfg in self.analysis_results.get("cfg", [])
                        if cfg is not None
                    ],
                    "column_names": [
                        "disassembled_function_hash",
                        "cfg_topology_hash",
                        "block_count",
                        "edge_count",
                        "llil_total_operations",
                        "call_count",
                        "cyclomatic_complexity",
                        "loop_count",
                        "max_depth",
                        "max_fan_out",
                        "md_index_topdown",
                        "md_index_bottomup",
                        "prime_product_llil",
                        "cfg_feature_tlsh",
                        "wl_minhash",
                        "bb_features",
                        "cfg_adjacency",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(16)",
                        "UInt16",
                        "UInt16",
                        "UInt32",
                        "UInt16",
                        "UInt16",
                        "UInt8",
                        "UInt16",
                        "UInt8",
                        "UInt64",
                        "UInt64",
                        "UInt64",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "Array(Array(UInt16))",
                        "Array(UInt32)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # GoReSym metadata table (only if goresym data exists)
            if self.goresym_data:
                export["golang_metadata"] = {
                    "table": "redb_golang_metadata",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            json.dumps(self.goresym_data),
                            now,
                        ]
                    ],
                    "column_names": [
                        "sha256",
                        "goresym",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "JSON",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            return export

    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
    import time

    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()
    start = time.perf_counter()
    # Create and run the extractor
    with DecompileBinja(args.filepath, logger) as extractor:
        success = extractor.extract()
        end = time.perf_counter()
        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((extractor.analysis_results))
            with open("diff", "w") as f:
                f.write(str(f"{end - start:.3f} seconds"))