Olivier Besson

156 papers C 1Misc 19Journal 115Unranked 20
YearRankTypeTitle / Venue / Authors
2026 J jnl
Signal Process.
Olivier Besson
2025 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2025 J jnl
Signal Process.
Olivier Besson
2024 J jnl
Signal Process.
Olivier Besson
2024 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2023 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2023 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Olivier Besson
2023 J jnl
IEEE Signal Process. Lett.
François Vincent, Olivier Besson, Benjamin Gigleux, Eric Chaumette
2023 J jnl
Signal Process.
Benjamin Gigleux, François Vincent, Olivier Besson, Eric Chaumette
2023 J jnl
IEEE Trans. Signal Process.
Olivier Besson
2022 J jnl
IEEE Trans. Signal Process.
Olivier Besson, François Vincent
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Corinne Mailhes, Olivier Besson, Amandine Guillot, Sophie Le Gac
2021 J jnl
Signal Process.
Olivier Besson, François Vincent, Stefania Matteoli
2021 J jnl
Signal Process.
François Vincent, Olivier Besson, Stefania Matteoli
2021 J jnl
IEEE Trans. Signal Process.
Olivier Besson
2021 J jnl
Signal Process.
Olivier Besson
2021 J jnl
Signal Process.
François Vincent, Olivier Besson
2021 J jnl
Signal Process.
François Vincent, Olivier Besson
2020 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2020 J jnl
Signal Process.
Olivier Besson
2020 J jnl
IEEE Trans. Signal Process.
Olivier Besson
2020 J jnl
Signal Process.
François Vincent, Jordi Vilà-Valls, Olivier Besson, Daniel Medina, Eric Chaumette
2020 J jnl
Signal Process.
François Vincent, Olivier Besson
2020 C conf
IGARSS
Corinne Mailhes, Olivier Besson, Amandine Guillot, Sophie Le Gac
2020 J jnl
Signal Process.
Olivier Besson
2020 J jnl
IEEE Signal Process. Lett.
François Vincent, Olivier Besson
2020 J jnl
IEEE Trans. Geosci. Remote. Sens.
François Vincent, Olivier Besson
2020 J jnl
Signal Process.
Olivier Besson, François Vincent
2020 J jnl
Signal Process.
Olivier Besson, François Vincent
2019 J jnl
IEEE Trans. Signal Process.
Pia Addabbo, Olivier Besson, Danilo Orlando, Giuseppe Ricci
2019 J jnl
IEEE Trans. Signal Process.
Angelo Coluccia, Giuseppe Ricci, Olivier Besson
2019 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2019 conf
CAMSAP
François Vincent, Olivier Besson
2018 J jnl
Signal Process.
Olivier Besson
2017 J jnl
Signal Process.
François Vincent, Frédéric Pascal, Olivier Besson
2017 conf
CAMSAP
François Vincent, Olivier Besson, Eric Chaumette
2017 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Angelo Coluccia, Eric Chaumette, Giuseppe Ricci, François Vincent
2017 conf
EUSIPCO
François Vincent, Eric Chaumette, Olivier Besson
2016 J jnl
IEEE Trans. Signal Process.
Olivier Besson
2016 Misc conf
ACSSC
Olivier Besson
2016 J jnl
IEEE Trans. Signal Process.
Yuri I. Abramovich, Olivier Besson, Ben A. Johnson
2016 J jnl
Signal Process.
Olivier Besson, Yuri I. Abramovich, Ben A. Johnson
2016 Misc conf
ICASSP
Pu Wang, Hongbin Li, Olivier Besson, Jun Fang
2016 conf
GlobalSIP
François Vincent, Olivier Besson, S. Abakar-Issakha, F. Bodereau, Laurent Ferro-Famil
2015 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Angelo Coluccia, Giuseppe Ricci
2015 conf
CAMSAP
Olivier Besson, Eric Chaumette, François Vincent
2015 J jnl
IEEE Signal Process. Lett.
François Vincent, Olivier Besson, Eric Chaumette
2015 J jnl
Signal Process.
Marie Lasserre, Stéphanie Bidon, Olivier Besson, François Le Chevalier
2015 J jnl
IEEE Trans. Signal Process.
Yuri I. Abramovich, Olivier Besson, Ben A. Johnson
2015 J jnl
IEEE Signal Process. Lett.
Yuri I. Abramovich, Olivier Besson
2015 conf
EUSIPCO
Yuri I. Abramovich, Ben A. Johnson, Olivier Besson
2015 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2015 J jnl
Signal Process.
Eric Chaumette, François Vincent, Olivier Besson
2015 J jnl
IEEE Signal Process. Lett.
Yuri I. Abramovich, Olivier Besson
2015 J jnl
IEEE Signal Process. Lett.
Olivier Besson, Yuri I. Abramovich
2014 J jnl
IEEE Signal Process. Lett.
Olivier Besson, Yuri I. Abramovich
2014 J jnl
Signal Process.
François Vincent, Olivier Besson, Eric Chaumette
2014 ch.
Optimal Transport
Olivier Besson, Martine Picq, Jérôme Poussin
2014 J jnl
J. Multivar. Anal.
Olivier Besson, Yuri I. Abramovich
2013 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Stéphanie Bidon
2013 conf
CAMSAP
François Vincent, Olivier Besson, Eric Chaumette
2013 Misc conf
ICASSP
Olivier Besson, Stéphanie Bidon
2013 Misc conf
ICASSP
Yuri I. Abramovich, Olivier Besson
2013 Misc conf
ACSSC
Olivier Besson, Yuri I. Abramovich
2013 J jnl
IEEE Signal Process. Lett.
Olivier Besson, Yuri I. Abramovich
2013 J jnl
IEEE Trans. Signal Process.
Yuri I. Abramovich, Olivier Besson
2013 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Yuri I. Abramovich
2013 J jnl
Signal Process.
Olivier Besson, Stéphanie Bidon
2013 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Francois Deudon, Stéphanie Bidon, Olivier Besson, Jean-Yves Tourneret
2012 conf
ACSCC
Francesco Bandiera, Olivier Besson, Giuseppe Ricci
2012 conf
SSP
Olivier Besson, Stéphanie Bidon
2012 Misc conf
ICASSP
Olivier Besson, Nicolas Dobigeon, Jean-Yves Tourneret
2012 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Nicolas Dobigeon, Jean-Yves Tourneret
2011 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Giuseppe Ricci
2011 J jnl
IET Commun.
Julien Montesinos, Olivier Besson, Cécile Larue de Tournemine
2011 conf
ACSCC
Olivier Besson, Nicolas Dobigeon, Jean-Yves Tourneret
2011 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Stéphanie Bidon, Olivier Besson, Jean-Yves Tourneret
2011 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Nicolas Dobigeon, Jean-Yves Tourneret
2011 conf
DSP
Francois Deudon, Stéphanie Bidon, Olivier Besson, Jean-Yves Tourneret
2011 J jnl
Traitement du Signal
Stéphanie Bidon, Olivier Besson, Jean-Yves Tourneret
2010 Misc conf
ICASSP
Francesco Bandiera, Olivier Besson, Giuseppe Ricci
2010 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Giuseppe Ricci
2010 J jnl
Signal Process.
Olivier Besson, Stéphanie Bidon, Cécile Larue de Tournemine
2009 J jnl
IEEE Signal Process. Lett.
Olivier Besson, Julien Montesinos, Cécile Larue de Tournemine
2008 J jnl
IEEE Trans. Signal Process.
Stéphanie Bidon, Olivier Besson, Jean-Yves Tourneret
2008 Misc conf
ICASSP
Francesco Bandiera, Olivier Besson, Danilo Orlando, Giuseppe Ricci
2008 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Giuseppe Ricci
2008 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Danilo Orlando, Giuseppe Ricci
2008 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Stéphanie Bidon, Jean-Yves Tourneret
2008 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Stéphanie Bidon, Jean-Yves Tourneret
2008 J jnl
IEEE Trans. Signal Process.
François Vincent, Olivier Besson, Cédric Richard
2008 J jnl
ARIMA J.
Olivier Besson, Soulèye Kane, Mamadou Sy
2008 J jnl
IEEE Signal Process. Lett.
Stéphanie Bidon, Olivier Besson, Jean-Yves Tourneret
2008 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Danilo Orlando, Giuseppe Ricci
2008 J jnl
Eur. Trans. Telecommun.
Garmy Sow, Olivier Besson, Marie-Laure Boucheret, Cécile Guiraud
2007 J jnl
IEEE Trans. Signal Process.
Olivier Besson
2007 J jnl
IEEE Signal Process. Lett.
Olivier Besson, Danilo Orlando
2007 conf
ICASSP (3)
Olivier Besson, Jean-Yves Tourneret, Stéphanie Bidon
2007 J jnl
IEEE Signal Process. Lett.
Olivier Besson
2007 J jnl
IEEE Trans. Signal Process.
Francesco Bandiera, Olivier Besson, Danilo Orlando, Giuseppe Ricci, Louis L. Scharf
2007 J jnl
IEEE Signal Process. Lett.
Olivier Besson, Jean-Yves Tourneret, Stéphanie Bidon
2007 conf
ICASSP (3)
François Vincent, Bernard Mouton, Eric Chaumette, Claude Nouals, Olivier Besson
2006 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Louis L. Scharf, Shawn Kraut
2006 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Louis L. Scharf
2006 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Shawn Kraut, Louis L. Scharf
2006 conf
ICASSP (3)
Francesco Bandiera, Olivier Besson, Danilo Orlando, Giuseppe Ricci, Louis L. Scharf
2005 J jnl
IEEE Trans. Signal Process.
Olivier Besson, G. Varfolomeev, François Vincent
2005 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Louis L. Scharf, François Vincent
2005 conf
ICASSP (4)
Olivier Besson, Louis L. Scharf, François Vincent
2005 J jnl
IEEE Trans. Signal Process.
Olivier Besson, François Vincent
2004 J jnl
IEEE Trans. Signal Process.
Andrei A. Monakov, Olivier Besson
2004 conf
ICASSP (2)
Olivier Besson, François Vincent
2004 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Andrei A. Monakov, Christophe Chalus
2003 J jnl
Signal Process.
Monika Agrawal, Petre Stoica, Olivier Besson, Per Åhgren
2003 J jnl
IEEE Trans. Commun.
Yukihiro Kamiya, Olivier Besson
2003 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica
2003 J jnl
IEEE Trans. Commun.
Petre Stoica, Olivier Besson
2003 J jnl
Digit. Signal Process.
Olivier Besson, Petre Stoica
2002 conf
EUSIPCO
Yukihiro Kamiya, Olivier Besson
2002 Misc conf
ICASSP
Olivier Besson, Petre Stoica
2002 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica, Yukihiro Kamiya
2001 J jnl
Wirel. Pers. Commun.
Olivier Besson, Petre Stoica
2001 Misc conf
ICASSP
Olivier Besson, Petre Stoica, Alex B. Gershman
2001 J jnl
IEEE Trans. Signal Process.
Petre Stoica, Olivier Besson, Alex B. Gershman
2001 J jnl
IEEE Trans. Signal Process.
Mounir Ghogho, Olivier Besson, Ananthram Swami
2001 J jnl
IEEE Commun. Lett.
Olivier Besson, Petre Stoica
2001 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica, Alex B. Gershman
2000 J jnl
IEEE Trans. Signal Process.
Olivier Besson, François Vincent, Petre Stoica, Alex B. Gershman
2000 conf
EUSIPCO
Petre Stoica, Olivier Besson
2000 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica
1999 J jnl
Digit. Signal Process.
Olivier Besson, Petre Stoica
1999 J jnl
Parallel Distributed Comput. Pract.
Olivier Besson
1999 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Georgios B. Giannakis, Fulvio Gini
1999 J jnl
Digit. Signal Process.
Olivier Besson, Petre Stoica
1999 Misc conf
ICASSP
Olivier Besson, Mounir Ghogho, Ananthram Swami
1999 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Mounir Ghogho, Ananthram Swami
1999 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica
1998 J jnl
Signal Process.
Olivier Besson, Petre Stoica
1998 Misc conf
ICASSP
Olivier Besson, Petre Stoica
1998 Misc conf
ICASSP
Frédéric Galtier, Olivier Besson
1998 J jnl
Signal Process.
Frédéric Galtier, Olivier Besson
1997 Misc conf
ICASSP
Frédéric Galtier, Olivier Besson
1997 Misc conf
ICASSP
Olivier Besson, Petre Stoica
1996 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica
1996 conf
EUSIPCO
Olivier Besson, Frédéric Galtier
1996 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Frédéric Galtier
1996 Misc conf
ICASSP
Olivier Besson, Petre Stoica
1996 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica
1996 conf
EUSIPCO
Olivier Besson, Petre Stoica
1995 Misc conf
ICASSP
Olivier Besson
1995 J jnl
Signal Process.
Olivier Besson
1995 J jnl
IEEE Trans. Signal Process.
Olivier Besson, Petre Stoica
1995 J jnl
Signal Process.
Olivier Besson, Petre Stoica
1993 J jnl
Signal Process.
Olivier Besson, Francis Castanie
1991 Misc conf
ICASSP
Olivier Besson, Francis Castanie
1990 Misc conf
ICASSP
Olivier Besson, Francis Castanie
redb/extractors/decompiler/DecompileAPK.py
← Index redb/extractors/decompiler/DecompileAPK.py python
"""APK Code Analysis Extractor.

Decompiles and disassembles APK DEX bytecode at the method level,
producing per-method content and reference records analogous to
the Binary Ninja code_binja_* tables.

Uses androguard + JADX + apktool to replicate Binary Ninja analysis
depth for Android applications.
"""

import gc
import hashlib
import inspect
import logging
import os
import threading
import time
from datetime import datetime, timezone
from typing import Any, Dict, Optional

from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
from redb.extractors.enum import Tag
from redb.extractors.extractor import Extractor


class DecompileAPK(Extractor):
    """APK code analysis extractor — produces multi-table ClickHouse export.

    Follows the same pattern as DecompileBinja for consistency.
    """

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        known_benign=False,
        known_malicious=False,
        filetype=None,
        decompile_modules=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            known_benign=known_benign,
            known_malicious=known_malicious,
        )
        self.log.debug(inspect.currentframe().f_code.co_name)
        self.analysis_results = None
        self.analyzer = None
        self.filetype = filetype or "apk"
        self.decompile_modules = decompile_modules or {"all"}

        try:
            self.APK_DECOMPILE_TIMEOUT = int(
                os.getenv("APK_DECOMPILE_TIMEOUT", "600")
            )
        except ValueError:
            self.log.warning(
                "Invalid APK_DECOMPILE_TIMEOUT value, using default of 600 seconds"
            )
            self.APK_DECOMPILE_TIMEOUT = 600

    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 cleanup_run(self):
        """Clean up after analysis."""
        try:
            if self.analyzer:
                self.analyzer.cleanup()
                self.analyzer = None
            gc.collect()
        except Exception as e:
            self.log.error(f"Error in cleanup: {e}")

    def analyze_apk(self) -> Optional[Dict[str, Any]]:
        """Run APK code analysis and return results."""
        self.log.debug("Starting APK code analysis")
        try:
            self.analyzer = APKCodeAnalyzer(
                filepath=self.filepath,
                timeout=self.APK_DECOMPILE_TIMEOUT,
                log=self.log,
                decompile_modules=self.decompile_modules,
            )
            results = self.analyzer.extract()
            return results
        except Exception as e:
            self.log.error(f"Error in APK code 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.

        Uses daemon thread with timeout, same pattern as DecompileBinja.
        """
        self.log.debug(inspect.currentframe().f_code.co_name)

        extraction_completed = False
        extraction_result = False
        extraction_error = None

        def do_extraction():
            nonlocal extraction_completed, extraction_result, extraction_error
            try:
                results = self.analyze_apk()
                if not results:
                    extraction_result = False
                else:
                    self.analysis_results = 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

        extraction_thread = threading.Thread(target=do_extraction)
        extraction_thread.daemon = True
        extraction_thread.start()

        start_time = time.time()
        while (
            not extraction_completed
            and (time.time() - start_time) < self.APK_DECOMPILE_TIMEOUT
        ):
            time.sleep(1)

        if not extraction_completed:
            self.log.error(
                f"APK extraction timed out after {self.APK_DECOMPILE_TIMEOUT} seconds"
            )
            self.cleanup_run()
            return None

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

        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

        if exporter_type == "ClickHouseExporter":
            now = datetime.now(timezone.utc)
            export = {"multi_table": True}

            # Table 1: Decompiled method content
            if self.analysis_results.get("decompiled_content"):
                export["decompiled_content"] = {
                    "table": "code_apk_decompiled_methods_content",
                    "data": [
                        [
                            f["decompiled_method_hash"],
                            f["decompiled_method"],
                            f.get("decompiled_method_type", "UNKNOWN"),
                            1 if f.get("decompiled_has_string_encryption") else 0,
                            1 if f.get("decompiled_has_reflection_calls") else 0,
                            1 if f.get("decompiled_excessive_goto_count") else 0,
                            now,
                        ]
                        for f in self.analysis_results["decompiled_content"]
                    ],
                    "column_names": [
                        "decompiled_method_hash",
                        "decompiled_method",
                        "decompiled_method_type",
                        "decompiled_has_string_encryption",
                        "decompiled_has_reflection_calls",
                        "decompiled_excessive_goto_count",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'UNKNOWN'=5)",
                        "UInt8",
                        "UInt8",
                        "UInt8",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 2: Decompiled method references
            if self.analysis_results.get("decompiled_refs"):
                export["decompiled_refs"] = {
                    "table": "code_apk_decompiled_methods_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["decompiled_method_hash"],
                            f.get("smali_method_hash"),
                            f.get("decompiled_class_name", ""),
                            f.get("decompiled_method_name", ""),
                            f.get("decompiled_method_signature", ""),
                            f.get("decompiled_method_prototype", ""),
                            f.get("functions_caller", []),
                            f.get("functions_call", []),
                            now,
                        ]
                        for f in self.analysis_results["decompiled_refs"]
                    ],
                    "column_names": [
                        "sha256",
                        "decompiled_method_hash",
                        "smali_method_hash",
                        "decompiled_class_name",
                        "decompiled_method_name",
                        "decompiled_method_signature",
                        "decompiled_method_prototype",
                        "functions_caller",
                        "functions_call",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "LowCardinality(String)",
                        "String",
                        "String",
                        "Array(String)",
                        "Array(String)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 3: Smali method content
            if self.analysis_results.get("smali_content"):
                export["smali_content"] = {
                    "table": "code_apk_smali_methods_content",
                    "data": [
                        [
                            f["smali_method_hash"],
                            f["smali_method"],
                            f.get("smali_method_type", "UNKNOWN"),
                            f.get("smali_instructions_count", 0),
                            f.get("smali_register_count", 0),
                            1 if f.get("smali_has_string_encryption") else 0,
                            1 if f.get("smali_has_reflection_calls") else 0,
                            1 if f.get("smali_excessive_goto_count") else 0,
                            f.get("smali_flattened_score", 0.0),
                            f.get("smali_mba_score", 0.0),
                            now,
                        ]
                        for f in self.analysis_results["smali_content"]
                    ],
                    "column_names": [
                        "smali_method_hash",
                        "smali_method",
                        "smali_method_type",
                        "smali_instructions_count",
                        "smali_register_count",
                        "smali_has_string_encryption",
                        "smali_has_reflection_calls",
                        "smali_excessive_goto_count",
                        "smali_flattened_score",
                        "smali_mba_score",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'UNKNOWN'=5)",
                        "UInt32",
                        "UInt16",
                        "UInt8",
                        "UInt8",
                        "UInt8",
                        "Float64",
                        "Float64",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 4: Smali method references
            if self.analysis_results.get("smali_refs"):
                export["smali_refs"] = {
                    "table": "code_apk_smali_methods_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["smali_method_hash"],
                            f.get("decompiled_method_hash"),
                            f.get("smali_class_name", ""),
                            f.get("smali_method_name", ""),
                            f.get("smali_method_signature", ""),
                            now,
                        ]
                        for f in self.analysis_results["smali_refs"]
                    ],
                    "column_names": [
                        "sha256",
                        "smali_method_hash",
                        "decompiled_method_hash",
                        "smali_class_name",
                        "smali_method_name",
                        "smali_method_signature",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "LowCardinality(String)",
                        "String",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 5: Method similarity metrics (content-based fuzzy matching)
            if self.analysis_results.get("similarity_metrics"):
                export["method_similarity_metrics"] = {
                    "table": "code_apk_method_similarity_metrics",
                    "data": [
                        [
                            f["smali_method_hash"],
                            f.get("ssdeep_smali"),
                            f.get("tlsh_smali"),
                            f.get("ssdeep_smali_normalized"),
                            f.get("tlsh_smali_normalized"),
                            f.get("minhash", []),
                            now,
                        ]
                        for f in self.analysis_results["similarity_metrics"]
                    ],
                    "column_names": [
                        "smali_method_hash",
                        "ssdeep_smali",
                        "tlsh_smali",
                        "ssdeep_smali_normalized",
                        "tlsh_smali_normalized",
                        "minhash",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 5b: CFG method features (structural/topological)
            if self.analysis_results.get("cfg"):
                export["cfg_methods"] = {
                    "table": "code_apk_cfg_methods",
                    "data": [
                        [
                            cfg["smali_method_hash"],
                            cfg["cfg_topology_hash"],
                            cfg["block_count"],
                            cfg["edge_count"],
                            cfg.get("cfg_instructions_count", 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_smali", 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["cfg"]
                        if cfg is not None
                    ],
                    "column_names": [
                        "smali_method_hash",
                        "cfg_topology_hash",
                        "block_count",
                        "edge_count",
                        "cfg_instructions_count",
                        "call_count",
                        "cyclomatic_complexity",
                        "loop_count",
                        "max_depth",
                        "max_fan_out",
                        "md_index_topdown",
                        "md_index_bottomup",
                        "prime_product_smali",
                        "cfg_feature_tlsh",
                        "wl_minhash",
                        "bb_features",
                        "cfg_adjacency",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(16)",
                        "UInt16",
                        "UInt16",
                        "UInt32",
                        "UInt16",
                        "UInt16",
                        "UInt16",
                        "UInt16",
                        "UInt16",
                        "UInt64",
                        "UInt64",
                        "UInt64",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "Array(Array(UInt16))",
                        "Array(UInt32)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 6: Strings — reuse code_binja_strings_raw for cross-format correlation
            # DEX strings are MUTF-8; string_raw = string since no encoding difference
            if self.analysis_results.get("strings"):
                export["strings_raw"] = {
                    "table": "code_binja_strings_raw",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            s["string"],
                            s["string"],  # string_raw = string (MUTF-8 decoded to UTF-8)
                            s.get("string_encoding", "UTF8"),
                            s.get("string_offset", 0),
                            s.get("string_length", len(s["string"])),
                            s.get("string_length", len(s["string"])),  # string_raw_length = string_length
                            s.get("string_entropy", 0.0),
                        ]
                        for s in self.analysis_results["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",
                    ],
                }

            # Table 7: Analysis errors
            if self.analysis_results.get("analysis_errors"):
                export["analysis_errors"] = {
                    "table": "code_apk_analysis_errors",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f.get("class_name"),
                            f.get("method_name"),
                            f.get("error_location", "unknown"),
                            f.get("error_message", ""),
                            f.get("error_type", "unknown"),
                            self.calculate_md5(
                                f"{f.get('error_message', '')}"
                                f"{f.get('class_name', '')}"
                                f"{f.get('method_name', '')}"
                                f"{f.get('error_location', 'unknown')}"
                            ),
                            "new",
                            now,
                        ]
                        for f in self.analysis_results["analysis_errors"]
                    ],
                    "column_names": [
                        "sha256",
                        "class_name",
                        "method_name",
                        "error_location",
                        "error_message",
                        "error_type",
                        "error_hash",
                        "status",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "LowCardinality(String)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "FixedString(32)",
                        "Enum8('new'=1, 'investigating'=2, 'fixed'=3, 'wontfix'=4)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            return export

        return None

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

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