Rachel A. Ward

108 papers A* 12A 4B 2Misc 2Journal 83Unranked 4
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Mohammed Abouzaid, Andrew J. Blumberg, Martin Hairer, Joe Kileel, Tamara G. Kolda, Paul D. Nelson, Daniel Spielman, Nikhil Srivastava, Rachel A. Ward, Shmuel Weinberger, Lauren Williams
2024 J jnl
CoRR
Erisa Hasani, Rachel A. Ward
2024 J jnl
SIAM J. Matrix Anal. Appl.
Ruhui Jin, Joe Kileel, Tamara G. Kolda, Rachel A. Ward
2023 A* conf
ICML
Yijun Dong, Yuege Xie, Rachel A. Ward
2023 J jnl
CoRR
Yijun Dong, Kevin Miller, Qi Lei, Rachel A. Ward
2023 A* conf
NeurIPS
Rachel A. Ward, Tamara G. Kolda
2023 J jnl
CoRR
Rachel A. Ward, Tamara G. Kolda
2023 J jnl
SIAM J. Appl. Dyn. Syst.
Dimitrios Giannakis, Amelia Henriksen, Joel A. Tropp, Rachel A. Ward
2023 A* conf
NeurIPS
William Swartworth, Deanna Needell, Rachel A. Ward, Mark Kong, Halyun Jeong
2023 J jnl
CoRR
Hung-Hsu Chou, Holger Rauhut, Rachel A. Ward
2023 A conf
AISTATS
Shuo Yang, Yijun Dong, Rachel A. Ward, Inderjit S. Dhillon, Sujay Sanghavi, Qi Lei
2022 A* conf
AAAI
Xiaoxia Wu, Yuege Xie, Simon Shaolei Du, Rachel A. Ward
2022 J jnl
CoRR
Yijun Dong, Yuege Xie, Rachel A. Ward
2022 J jnl
CoRR
Nhat Ho, Tongzheng Ren, Sujay Sanghavi, Purnamrita Sarkar, Rachel A. Ward
2022 B conf
CPM
Abhinav Nellore, Rachel A. Ward
2022 J jnl
J. Data Sci. Stat. Vis.
Aaron Defazio, Mark Tygert, Rachel A. Ward, Jure Zbontar
2022 conf
MSML
Zhijun Chen, Hayden Schaeffer, Rachel A. Ward
2022 J jnl
CoRR
Zhijun Chen, Hayden Schaeffer, Rachel A. Ward
2022 A* conf
COLT
Itay Evron, Edward Moroshko, Rachel A. Ward, Nathan Srebro, Daniel Soudry
2022 J jnl
CoRR
Itay Evron, Edward Moroshko, Rachel A. Ward, Nati Srebro, Daniel Soudry
2022 J jnl
SIAM J. Matrix Anal. Appl.
Stefan Bamberger, Felix Krahmer, Rachel A. Ward
2022 J jnl
Found. Comput. Math.
De Huang, Jonathan Niles-Weed, Joel A. Tropp, Rachel A. Ward
2022 J jnl
CoRR
Raghu Bollapragada, Tyler Chen, Rachel A. Ward
2022 J jnl
SIAM J. Math. Data Sci.
Yuege Xie, Hung-Hsu Chou, Holger Rauhut, Rachel A. Ward
2022 conf
MSML
Yuege Xie, Robert Shi, Hayden Schaeffer, Rachel A. Ward
2022 J jnl
CoRR
Shuo Yang, Yijun Dong, Rachel A. Ward, Inderjit S. Dhillon, Sujay Sanghavi, Qi Lei
2022 J jnl
CoRR
Ruhui Jin, Joe Kileel, Tamara G. Kolda, Rachel A. Ward
2022 J jnl
CoRR
Juncai He, Richard Tsai, Rachel A. Ward
2022 A* conf
COLT
Matthew Faw, Isidoros Tziotis, Constantine Caramanis, Aryan Mokhtari, Sanjay Shakkottai, Rachel A. Ward
2022 J jnl
CoRR
Matthew Faw, Isidoros Tziotis, Constantine Caramanis, Aryan Mokhtari, Sanjay Shakkottai, Rachel A. Ward
2021 J jnl
CoRR
Xiaoxia Wu, Yuege Xie, Simon S. Du, Rachel A. Ward
2021 J jnl
CoRR
Abhinav Nellore, Rachel A. Ward
2021 A* conf
NeurIPS
Robert Lunde, Purnamrita Sarkar, Rachel A. Ward
2021 J jnl
CoRR
Abolfazl Hashemi, Hayden Schaeffer, Robert Shi, Ufuk Topcu, Giang Tran, Rachel A. Ward
2021 J jnl
CoRR
Stefan Bamberger, Felix Krahmer, Rachel A. Ward
2021 J jnl
CoRR
Dimitris Giannakis, Amelia Henriksen, Joel A. Tropp, Rachel A. Ward
2021 J jnl
CoRR
Yuege Xie, Bobby Shi, Hayden Schaeffer, Rachel A. Ward
2021 A* conf
COLT
De Huang, Jonathan Niles-Weed, Rachel A. Ward
2021 J jnl
CoRR
De Huang, Jonathan Niles-Weed, Rachel A. Ward
2020 J jnl
Multiscale Model. Simul.
Hayden Schaeffer, Giang Tran, Rachel A. Ward, Linan Zhang
2020 A* conf
NeurIPS
Xiaoxia Wu, Edgar Dobriban, Tongzheng Ren, Shanshan Wu, Zhiyuan Li, Suriya Gunasekar, Rachel A. Ward, Qiang Liu
2020 A conf
AISTATS
Yuege Xie, Xiaoxia Wu, Rachel A. Ward
2020 ed.
MSML
Jianfeng Lu, Rachel A. Ward
2020 J jnl
J. Approx. Theory
Lam Si Tung Ho, Hayden Schaeffer, Giang Tran, Rachel A. Ward
2020 J jnl
CoRR
Yuege Xie, Rachel A. Ward, Holger Rauhut, Hung-Hsu Chou
2019 A* conf
ICML
Rachel A. Ward, Xiaoxia Wu, Léon Bottou
2019 J jnl
CoRR
Amelia Henriksen, Rachel A. Ward
2019 J jnl
CoRR
Denali Molitor, Deanna Needell, Rachel A. Ward
2019 J jnl
CoRR
Ruhui Jin, Tamara G. Kolda, Rachel A. Ward
2019 J jnl
CoRR
Xiaoxia Wu, Simon S. Du, Rachel A. Ward
2019 J jnl
CoRR
Xiaoxia Wu, Edgar Dobriban, Tongzheng Ren, Shanshan Wu, Zhiyuan Li, Suriya Gunasekar, Rachel A. Ward, Qiang Liu
2019 J jnl
CoRR
Yuege Xie, Xiaoxia Wu, Rachel A. Ward
2018 J jnl
CoRR
Rachel A. Ward, Xiaoxia Wu, Léon Bottou
2018 J jnl
SIAM J. Appl. Math.
Hayden Schaeffer, Giang Tran, Rachel A. Ward
2018 J jnl
CoRR
Hayden Schaeffer, Giang Tran, Rachel A. Ward, Linan Zhang
2018 J jnl
CoRR
Christopher Kennedy, Rachel A. Ward
2018 J jnl
CoRR
Lam Si Tung Ho, Hayden Schaeffer, Giang Tran, Rachel A. Ward
2018 J jnl
CoRR
Xiaoxia Wu, Rachel A. Ward, Léon Bottou
2017 J jnl
Multiscale Model. Simul.
Giang Tran, Rachel A. Ward
2017 A conf
ITCS
Christopher Kennedy, Rachel A. Ward
2017 Misc conf
ACSSC
Armin Eftekhari, Michael B. Wakin, Ping Li, Paul G. Constantine, Rachel A. Ward
2016 J jnl
CoRR
Soledad Villar, Afonso S. Bandeira, Andrew J. Blumberg, Rachel A. Ward
2016 J jnl
CoRR
Deanna Needell, Rachel A. Ward
2016 J jnl
CoRR
Dustin G. Mixon, Soledad Villar, Rachel A. Ward
2016 B conf
ITW
Dustin G. Mixon, Soledad Villar, Rachel A. Ward
2016 J jnl
CoRR
Christopher Kennedy, Rachel A. Ward
2016 J jnl
CoRR
Shahar Mendelson, Holger Rauhut, Rachel A. Ward
2016 J jnl
CoRR
Armin Eftekhari, Ping Li, Michael B. Wakin, Rachel A. Ward
2016 J jnl
CoRR
Armin Eftekhari, Michael B. Wakin, Rachel A. Ward
2016 J jnl
IEEE Trans. Inf. Theory
Karin Knudson, Rayan Saab, Rachel A. Ward
2016 J jnl
Math. Program.
Deanna Needell, Nathan Srebro, Rachel A. Ward
2016 J jnl
IEEE Trans. Signal Process.
Bubacarr Bah, Rachel A. Ward
2015 J jnl
J. Mach. Learn. Res.
Yudong Chen, Srinadh Bhojanapalli, Sujay Sanghavi, Rachel A. Ward
2015 J jnl
CoRR
Felix Krahmer, Deanna Needell, Rachel A. Ward
2015 J jnl
SIAM J. Math. Anal.
Felix Krahmer, Deanna Needell, Rachel A. Ward
2015 J jnl
Inf. Comput.
Abhinav Nellore, Rachel A. Ward
2015 A conf
ITCS
Pranjal Awasthi, Afonso S. Bandeira, Moses Charikar, Ravishankar Krishnaswamy, Soledad Villar, Rachel A. Ward
2015 J jnl
CoRR
Bubacarr Bah, Rachel A. Ward
2014 J jnl
CoRR
Rachel A. Ward
2014 A* conf
ICML
Yudong Chen, Srinadh Bhojanapalli, Sujay Sanghavi, Rachel A. Ward
2014 J jnl
CoRR
Pranjal Awasthi, Afonso S. Bandeira, Moses Charikar, Ravishankar Krishnaswamy, Soledad Villar, Rachel A. Ward
2014 J jnl
IEEE Trans. Image Process.
Felix Krahmer, Rachel A. Ward
2014 conf
NIPS
Deanna Needell, Rachel A. Ward, Nathan Srebro
2013 J jnl
SIAM J. Imaging Sci.
Mark A. Iwen, Fadil Santosa, Rachel A. Ward
2013 J jnl
CoRR
Srinadh Bhojanapalli, Yudong Chen, Sujay Sanghavi, Rachel A. Ward
2013 J jnl
IEEE Trans. Image Process.
Deanna Needell, Rachel A. Ward
2013 J jnl
CoRR
Abhinav Nellore, Rachel A. Ward
2013 J jnl
SIAM J. Imaging Sci.
Deanna Needell, Rachel A. Ward
2013 J jnl
CoRR
Deanna Needell, Nathan Srebro, Rachel A. Ward
2012 J jnl
CoRR
Mark A. Iwen, Fadil Santosa, Rachel A. Ward
2012 J jnl
CoRR
Felix Krahmer, Rachel A. Ward
2012 J jnl
IEEE Trans. Inf. Theory
Felix Krahmer, Rayan Saab, Rachel A. Ward
2012 J jnl
J. Approx. Theory
Holger Rauhut, Rachel A. Ward
2012 J jnl
CoRR
Deanna Needell, Rachel A. Ward
2012 J jnl
CoRR
Deanna Needell, Rachel A. Ward
2012 J jnl
SIAM J. Math. Anal.
Nicolas Burq, Semyon Dyatlov, Rachel A. Ward, Maciej Zworski
2011 J jnl
Appl. Math. Comput.
William Perkins, Mark Tygert, Rachel A. Ward
2011 J jnl
SIAM J. Optim.
Massimo Fornasier, Holger Rauhut, Rachel A. Ward
2011 J jnl
SIAM J. Math. Anal.
Felix Krahmer, Rachel A. Ward
2011 A* conf
CHI
Leanne M. Hirshfield, Rebecca Gulotta, Stuart H. Hirshfield, Samuel W. Hincks, Matthew Russell, Rachel A. Ward, Tom Williams, Robert J. K. Jacob
2011 conf
HCI (20)
Leanne M. Hirshfield, Stuart H. Hirshfield, Samuel W. Hincks, Matthew Russell, Rachel A. Ward, Tom Williams
2010 Misc conf
CISS
Holger Rauhut, Rachel A. Ward
2010 J jnl
Found. Comput. Math.
Massimo Fornasier, Rachel A. Ward
2010 J jnl
CoRR
Felix Krahmer, Rachel A. Ward
2010 J jnl
CoRR
Felix Krahmer, Rachel A. Ward
2010 J jnl
IEEE Trans. Image Process.
Boris Alexeev, Rachel A. Ward
2009 J jnl
IEEE Trans. Inf. Theory
Rachel A. Ward
2009 J jnl
GeoInformatica
Jeff Danciger, Satyan L. Devadoss, John Mugno, Don Sheehy, Rachel A. Ward
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