Vangelis Metsis

77 papers A* 1B 8Misc 5Journal 23Unranked 40
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Bikram De, Habib Irani, Vangelis Metsis
2026 conf
VISAPP (2)
Evangelos G. Sartinas, Dimitrios I. Kosmopoulos, Emmanouil Z. Psarakis, Kostas Blekos, Bikram Kumar De, Vangelis Metsis
2026 J jnl
CoRR
Habib Irani, Bikram De, Vangelis Metsis
2025 J jnl
CoRR
Arshia Kermani, Verónica Pérez-Rosas, Vangelis Metsis
2025 J jnl
CoRR
Habib Irani, Vangelis Metsis
2025 conf
DSP
Bikram De, Kostas Blekos, Vassilis Pikoulis, Dimitrios I. Kosmopoulos, Vangelis Metsis
2025 J jnl
CoRR
Habib Irani, Vangelis Metsis
2025 J jnl
CoRR
Yasamin Ghahremani, Vangelis Metsis
2025 J jnl
Expert Syst. J. Knowl. Eng.
Habib Irani, Yasamin Ghahremani, Arshia Kermani, Vangelis Metsis
2024 J jnl
CoRR
Xiaomin Li, Mykhailo Sakevych, Gentry Atkinson, Vangelis Metsis
2024 Misc conf
FLAIRS
Habib Irani, Vangelis Metsis
2024 conf
PETRA
Alexander Katrompas, Vangelis Metsis
2024 conf
AIME (1)
Bikram De, Mykhailo Sakevych, Vangelis Metsis
2023 conf
PETRA
Lee B. Hinkle, Vangelis Metsis
2023 conf
ICASSP Workshops
Lee B. Hinkle, Tristan Pedro, Tyler Lynn, Gentry Atkinson, Vangelis Metsis
2023 conf
EUSIPCO
Gentry Atkinson, Xiaomin Li, Vangelis Metsis
2023 conf
WACV (Workshops)
Xiaomin Li, Ramin Nabati, Kunjan Singh, Enrique Corona, Vangelis Metsis, Armin Parchami
2023 conf
AIAI (1)
Lee B. Hinkle, Gentry Atkinson, Vangelis Metsis
2023 conf
ICANN (6)
Alexander Katrompas, Vangelis Metsis
2022 B conf
Intelligent Environments (Workshops)
Lee B. Hinkle, Gentry Atkinson, Vangelis Metsis
2022 B conf
Intelligent Environments
Lee B. Hinkle, Vangelis Metsis
2022 conf
NAS
Cody Blakeney, Gentry Atkinson, Nathaniel Huish, Yan Yan, Vangelis Metsis, Ziliang Zong
2022 J jnl
Int. J. Neural Syst.
Anne Hee Hiong Ngu, Vangelis Metsis, Shuan Coyne, Priyanka Srinivas, Tarek Salad, Uddin Mahmud, Kyong Hee Chee
2022 B conf
AIME
Alexander Katrompas, Theodoros Ntakouris, Vangelis Metsis
2022 J jnl
CoRR
Xiaomin Li, Anne Hee Hiong Ngu, Vangelis Metsis
2022 B conf
AIME
Xiaomin Li, Vangelis Metsis, Huangyingrui Wang, Anne Hee Hiong Ngu
2022 J jnl
CoRR
Xiaomin Li, Vangelis Metsis, Huangyingrui Wang, Anne Hee Hiong Ngu
2022 conf
AIAI (2)
Morgan Byers, Lee B. Hinkle, Vangelis Metsis
2021 Misc conf
AIAI
Gentry Atkinson, Vangelis Metsis
2021 Misc conf
AIAI
Anne H. H. Ngu, Shaun Coyne, Priyanka Srinivas, Vangelis Metsis
2021 conf
IntelliSys (1)
Alexander Katrompas, Vangelis Metsis
2021 J jnl
ACM Trans. Comput. Heal.
Taylor R. Mauldin, Anne H. H. Ngu, Vangelis Metsis, Marc E. Canby
2021 J jnl
CoRR
Cody Blakeney, Gentry Atkinson, Nathaniel Huish, Yan Yan, Vangelis Metsis, Ziliang Zong
2021 B conf
AIME
Lee B. Hinkle, Vangelis Metsis
2021 conf
PETRA
Gentry Atkinson, Vangelis Metsis
2021 A* conf
AAAI
Morgan Byers, Vangelis Metsis
2020 conf
UbiComp/ISWC Adjunct
Gentry Atkinson, Vangelis Metsis
2020 J jnl
Sensors
George Koutitas, Varun Kumar Siddaraju, Vangelis Metsis
2020 conf
PerCom Workshops
Anne H. H. Ngu, Vangelis Metsis, Shaun Coyne, Brian Chung, Rachel Pai, Joshua Chang
2019 conf
PETRA
George Koutitas, Kenneth Scott Smith, Grayson Lawrence, Vangelis Metsis, Clayton Stamper, Mark Trahan, Ted Lehr
2019 J jnl
Open J. Internet Things
Taylor R. Mauldin, Anne H. H. Ngu, Vangelis Metsis, Marc E. Canby, Jelena Tesic
2019 conf
ICDIS
Lee Hinkle, Kamrad Khoshhal, Vangelis Metsis
2018 J jnl
Sensors
Taylor R. Mauldin, Marc E. Canby, Vangelis Metsis, Anne H. H. Ngu, Coralys Cubero Rivera
2017 J jnl
IEEE Trans. Cogn. Dev. Syst.
Kamrad Khoshhal Roudposhti, Jorge Dias, Paulo Peixoto, Vangelis Metsis, Urbano Nunes
2017 conf
PETRA
Adam Anderson, Thomas Hsiao, Vangelis Metsis
2017 J jnl
IEEE Internet Things J.
Anne Hee Hiong Ngu, Mario A. Gutierrez, Vangelis Metsis, Surya Nepal, Quan Z. Sheng
2015 conf
ICHI
Hugo Espiritu, Vangelis Metsis
2015 conf
PETRA
Dylan Ebert, Vangelis Metsis, Fillia Makedon
2015 conf
PETRA
Michalis Papakostas, James Staud, Fillia Makedon, Vangelis Metsis
2015 conf
PETRA
Vangelis Metsis, Ioannis D. Schizas, Gregg Marshall
2015 conf
PETRA
Alexandros Lioulemes, Paul Sassaman, Shawn N. Gieser, Vangelis Karkaletsis, Fillia Makedon, Vangelis Metsis
2014 conf
PETRA
David Paulk, Vangelis Metsis, Christopher McMurrough, Fillia Makedon
2014 J jnl
IEEE ACM Trans. Comput. Biol. Bioinform.
Vangelis Metsis, Fillia Makedon, Dinggang Shen, Heng Huang
2014 conf
HAVE
Scott Phan, Alexandros Lioulemes, Cyril Lutterodt, Fillia Makedon, Vangelis Metsis
2014 J jnl
Pers. Ubiquitous Comput.
Vangelis Metsis, Dimitrios I. Kosmopoulos, Vassilis Athitsos, Fillia Makedon
2014 conf
PETRA
Shawn N. Gieser, Vangelis Metsis, Fillia Makedon
2014 conf
PETRA
Alexandros Lioulemes, Georgios Galatas, Vangelis Metsis, Gian Luca Mariottini, Fillia Makedon
2013 J jnl
J. Multimodal User Interfaces
Christopher McMurrough, Vangelis Metsis, Dimitrios I. Kosmopoulos, Ilias Maglogiannis, Fillia Makedon
2013 conf
ICIMTH
Dimitrios Zikos, Georgios Galatas, Vangelis Metsis, Fillia Makedon
2013 conf
PETRA
Alexandros Papangelis, Robert Gatchel, Vangelis Metsis, Fillia Makedon
2013 Misc conf
ICNC
Vangelis Metsis, Pat Jangyodsuk, Vassilis Athitsos, Maura Iversen, Fillia Makedon
2013 conf
PETRA
Michael R. Gardner, Vangelis Metsis, Eric Becker, Fillia Makedon
2012 B conf
ICPR
Zhong Zhang, Weihua Liu, Vangelis Metsis, Vassilis Athitsos
2012 B conf
ETRA
Christopher McMurrough, Vangelis Metsis, Jonathan Rich, Fillia Makedon
2012 J jnl
Knowl. Inf. Syst.
Kevin Dela Rosa, Vangelis Metsis, Vassilis Athitsos
2012 conf
PETRA
Christopher McMurrough, Jonathan Rich, Vangelis Metsis, An Nguyen, Fillia Makedon
2011 J jnl
Telematics Informatics
Charalampos Doukas, Vangelis Metsis, Eric Becker, Zhengyi Le, Fillia Makedon, Ilias Maglogiannis
2011 conf
PETRA
Vangelis Metsis, Georgios Galatas, Alexandros Papangelis, Dimitrios I. Kosmopoulos, Fillia Makedon
2010 conf
PETRA
Kyungseo Park, Yong Lin, Vangelis Metsis, Zhengyi Le, Fillia Makedon
2010 conf
PETRA
Alexandros Papangelis, Vangelis Metsis, John Shawe-Taylor, Fillia Makedon
2009 conf
IC3
Ishfaq Ahmad, Roman Arora, Derek White, Vangelis Metsis, Rebecca Ingram
2009 Misc conf
AIAI
Vangelis Metsis, Heng Huang, Fillia Makedon, Aria Tzika
2009 conf
PETRA
Roman Arora, Vangelis Metsis, Rong Zhang, Fillia Makedon
2009 conf
PETRA
Eric Becker, Vangelis Metsis, Roman Arora, Jyothi K. Vinjumur, Yurong Xu, Fillia Makedon
2008 conf
PETRA
Vangelis Metsis, Zhengyi Le, Yu Lei, Fillia Makedon
2007 B conf
AIME
Konstantinos Stamatakis, Vangelis Metsis, Vangelis Karkaletsis, Marek Ruzicka, Vojtech Svátek, Enrique Amigó, Matti Pöllä, Constantine D. Spyropoulos
2006 conf
CEAS
Vangelis Metsis, Ion Androutsopoulos, Georgios Paliouras
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