Carlos M. Fernandes

92 papers A 10B 10C 7Misc 5Journal 30Unranked 30
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Nuno Fachada, Daniel F. S. Fernandes, Carlos M. Fernandes, João Pedro Matos-Carvalho
2025 J jnl
CoRR
Daniel Fernandes, João Pedro Matos-Carvalho, Carlos M. Fernandes, Nuno Fachada
2025 J jnl
CoRR
Nuno Fachada, Daniel Fernandes, Carlos M. Fernandes, Bruno D. Ferreira-Saraiva, João Pedro Matos-Carvalho
2025 J jnl
Future Internet
Nuno Fachada, Daniel Fernandes, Carlos M. Fernandes, Bruno D. Ferreira-Saraiva, João Pedro Matos-Carvalho
2024 J jnl
CoRR
Juan Luis Jiménez Laredo, Carlos M. Fernandes, Juan Julián Merelo, Christian Gagné
2022 B conf
EvoApplications
Juan Luis Jiménez Laredo, Loïs Naudin, Nathalie Corson, Carlos M. Fernandes
2021 J jnl
IEEE Trans. Affect. Comput.
Carlos M. Fernandes, Daria Migotina, Agostinho C. Rosa
2020 B conf
EvoApplications
Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos M. Fernandes, Eric Sanlaville
2020 J jnl
Entropy
Diogo de Andrade, Nuno Fachada, Carlos M. Fernandes, Agostinho C. Rosa
2020 J jnl
Swarm Evol. Comput.
Carlos M. Fernandes, Nuno Fachada, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Agostinho C. Rosa
2019 conf
GECCO (Companion)
Carlos M. Fernandes, Agostinho C. Rosa, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós
2019 J jnl
PeerJ Comput. Sci.
Carlos M. Fernandes, Nuno Fachada, Juan Julián Merelo Guervós, Agostinho C. Rosa
2018 J jnl
Comput. Oper. Res.
Nuno Leite, Carlos M. Fernandes, Fernando Melicio, Agostinho C. Rosa
2018 B conf
CEC
Carlos M. Fernandes, Agostinho C. Rosa, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos Cotta
2018 conf
GECCO (Companion)
Carlos M. Fernandes, Agostinho C. Rosa, Nuno Fachada, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós
2018 C conf
IJCCI
Carlos M. Fernandes, Nuno Fachada, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Pedro A. Castillo, Agostinho C. Rosa
2017 conf
ECAL
Juan Julián Merelo Guervós, Pedro A. Castillo, Antonio Miguel Mora, Mario García Valdez, Carlos Cotta, Carlos M. Fernandes
2017 Misc conf
IDC
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Agostinho C. Rosa
2016 A conf
PPSN
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2016 conf
GECCO (Companion)
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2016 J jnl
Trans. Comput. Collect. Intell.
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos Cotta, Agostinho C. Rosa
2016 J jnl
Appl. Soft Comput.
Pablo García-Sánchez, Gustavo Romero, Jesús González, Antonio Miguel Mora, Maribel García Arenas, Pedro Ángel Castillo Valdivieso, Carlos M. Fernandes, Juan Julián Merelo Guervós
2015 J jnl
Int. J. Arts Technol.
Carlos M. Fernandes
2014 B conf
EvoCOP
Juan Luis Jiménez Laredo, Sune S. Nielsen, Grégoire Danoy, Pascal Bouvry, Carlos M. Fernandes
2014 J jnl
Genet. Program. Evolvable Mach.
Juan Luis Jiménez Laredo, Pascal Bouvry, Daniel Lombraña González, Francisco Fernández de Vega, Maribel García Arenas, Juan Julián Merelo Guervós, Carlos M. Fernandes
2014 B conf
EvoApplications
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos Cotta, Agostinho C. Rosa
2014 J jnl
IEEE Trans. Cybern.
Carlos M. Fernandes, Antonio Miguel Mora, Juan Julián Merelo Guervós, Agostinho C. Rosa
2014 conf
IJCCI (Selected Papers)
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos Cotta, Agostinho C. Rosa
2014 conf
IJCCI (ECTA)
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos Cotta, Agostinho C. Rosa
2014 A conf
PPSN
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos Cotta, Rafael Nogueras, Agostinho C. Rosa
2014 J jnl
Clust. Comput.
Juan Luis Jiménez Laredo, Pascal Bouvry, Frédéric Guinand, Bernabé Dorronsoro, Carlos M. Fernandes
2013 B conf
IEEE Congress on Evolutionary Computation
Carlos M. Fernandes, Agostinho C. Rosa, Juan Luis Jiménez Laredo, Carlos Cotta, Juan Julián Merelo Guervós
2013 conf
ECAL
Carlos M. Fernandes, Juanlu J. Laredo, Juan Julián Merelo Guervós, Carlos Cotta, Agostinho C. Rosa
2013 conf
TPNC
Rafael Nogueras, Carlos Cotta, Carlos M. Fernandes, Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Agostinho C. Rosa
2013 J jnl
Int. J. Neural Syst.
Luis Javier Herrera, Carlos M. Fernandes, Antonio Miguel Mora, Daria Migotina, Rogerio Largo, Alberto Guillén, Agostinho C. Rosa
2013 J jnl
Nat. Comput.
Juan Julián Merelo Guervós, Antonio Miguel Mora, Carlos M. Fernandes, Anna Isabel Esparcia-Alcázar
2013 conf
GECCO (Companion)
Pablo García-Sánchez, María Isabel García Arenas, Antonio Miguel Mora, Pedro A. Castillo, Carlos M. Fernandes, Paloma de las Cuevas, Gustavo Romero, Jesús González, Juan Julián Merelo Guervós
2013 conf
LION
Juan Luis Jiménez Laredo, Bernabé Dorronsoro Díaz, Carlos M. Fernandes, Juan Julián Merelo Guervós, Pascal Bouvry
2013 conf
GECCO (Companion)
Carlos M. Fernandes, Juan Julián Merelo Guervós, Juan Luis Jiménez Laredo, Carlos Cotta, Agostinho C. Rosa
2013 C conf
IJCCI
Carlos M. Fernandes, Agostinho C. Rosa, Juan Luis Jiménez Laredo, Carlos Cotta, Juan Julián Merelo Guervós
2013 conf
CICAC
Carlos M. Fernandes, Antonio Mora García, Juan Julián Merelo Guervós, Carlos Cotta, Agostinho C. Rosa
2013 conf
IWANN (1)
José Manuel Sánchez Pascualvaca, Carlos M. Fernandes, Alberto Guillén, Antonio Miguel Mora, Rogerio Largo, Agostinho C. Rosa, Luis Javier Herrera
2013 J jnl
Appl. Intell.
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Agostinho C. Rosa, Juan Julián Merelo Guervós
2012 conf
IJCCI (Selected Papers)
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2012 conf
PPSN (2)
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2012 conf
3PGCIC
Juanlu J. Laredo, Bernabé Dorronsoro, Johnatan E. Pecero, Pascal Bouvry, Juan José Durillo, Carlos M. Fernandes
2012 J jnl
J. Comput. Sci. Technol.
Antonio Miguel Mora, Antonio Fernández-Ares, Juan Julián Merelo Guervós, Pablo García-Sánchez, Carlos M. Fernandes
2012 C conf
IJCCI
Carlos M. Fernandes, Antonio Mora García, Juan Julián Merelo Guervós, Agostinho C. Rosa
2012 conf
IJCCI (Selected Papers)
Carlos M. Fernandes, Antonio Mora García, Juan Julián Merelo Guervós, Agostinho C. Rosa
2012 conf
3PGCIC
Juan Julián Merelo Guervós, Antonio Miguel Mora, Carlos M. Fernandes, Anna Isabel Esparcia-Alcázar, Juan Luis Jiménez Laredo
2012 conf
GECCO (Companion)
Juan Julián Merelo Guervós, Carlos M. Fernandes, Antonio Miguel Mora, Anna Isabel Esparcia-Alcázar
2012 C conf
IJCCI
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2012 conf
GECCO (Companion)
Juan Julián Merelo Guervós, Antonio Miguel Mora, Anna Isabel Esparcia-Alcázar, Carlos M. Fernandes
2011 conf
EvoApplications (1)
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Antonio Miguel Mora, Agostinho C. Rosa, Juan Julián Merelo Guervós
2011 J jnl
Inf. Sci.
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2011 conf
LION
Juan Luis Jiménez Laredo, Juan Julián Merelo Guervós, Carlos M. Fernandes, Antonio Miguel Mora, Maribel García Arenas, Pedro A. Castillo, Pablo García-Sánchez
2011 B conf
IEEE Congress on Evolutionary Computation
Carlos M. Fernandes, Carlos Isidoro, Fábio Barata, Agostinho C. Rosa, Juan Julián Merelo Guervós
2011 conf
IWANN (2)
Antonio Fernández-Ares, Antonio Miguel Mora, Juan Julián Merelo Guervós, Pablo García-Sánchez, Carlos M. Fernandes
2011 B conf
IEEE Congress on Evolutionary Computation
Antonio Fernández-Ares, Antonio Miguel Mora, Juan Julián Merelo Guervós, Pablo García-Sánchez, Carlos M. Fernandes
2011 C conf
ISDA
Luis Javier Herrera, Antonio Miguel Mora, Carlos M. Fernandes, Daria Migotina, Alberto Guillén, Agostinho C. Rosa
2011 conf
LION
Carlos M. Fernandes, Juan Luis Jiménez Laredo, Antonio Miguel Mora, Agostinho C. Rosa, Juan Julián Merelo Guervós
2010 conf
IJCCI (Selected Papers)
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2010 conf
IJCCI (ICEC)
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2010 C conf
ISDA
Antonio Miguel Mora, Carlos M. Fernandes, Luis Javier Herrera, Pedro A. Castillo, Juan Julián Merelo Guervós, Fernando Rojas, Agostinho C. Rosa
2009 conf
ECAL (2)
Carlos M. Fernandes, Cláudio F. Lima, Juan Luis Jiménez Laredo, Agostinho C. Rosa, Juan Julián Merelo Guervós
2009 A conf
GECCO
Juan Luis Jiménez Laredo, Carlos M. Fernandes, Juan Julián Merelo Guervós, Christian Gagné
2009 Misc conf
IDC
Juan Luis Jiménez Laredo, Carlos M. Fernandes, Antonio Mora García, Pedro A. Castillo, Pablo García-Sánchez, Juan Julián Merelo Guervós
2009 J jnl
CoRR
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2008 A conf
GECCO
Carlos M. Fernandes, Juan Julián Merelo Guervós, Vitorino Ramos, Agostinho C. Rosa
2008 A conf
PPSN
Juan Luis Jiménez Laredo, Pedro A. Castillo, Antonio Miguel Mora, Juan Julián Merelo Guervós, Agostinho Cláudio da Rosa, Carlos M. Fernandes
2008 A conf
GECCO
Cláudio F. Lima, Carlos M. Fernandes, Fernando G. Lobo
2008 conf
ANTS Conference
Carlos M. Fernandes, Antonio Miguel Mora, Juan Julián Merelo Guervós, Vitorino Ramos, Juan Luis Jiménez Laredo, Agostinho C. Rosa
2008 J jnl
CoRR
Carlos M. Fernandes, Antonio Miguel Mora, Juan Julián Merelo Guervós, Vitorino Ramos, Juan Luis Jiménez Laredo
2008 J jnl
Int. J. High Perform. Syst. Archit.
Juan Luis Jiménez Laredo, Pedro A. Castillo, Antonio Miguel Mora, Juan Julián Merelo Guervós, Carlos M. Fernandes
2008 J jnl
Soft Comput.
Carlos M. Fernandes, Agostinho C. Rosa
2008 C conf
HIS
Carlos M. Fernandes, Juan Julián Merelo Guervós, Agostinho C. Rosa
2008 A conf
GECCO
Carlos M. Fernandes, Cláudio F. Lima, Agostinho C. Rosa
2007 A conf
GECCO
Carlos M. Fernandes, Agostinho C. Rosa, Vitorino Ramos
2007 J jnl
CoRR
Vitorino Ramos, Carlos M. Fernandes, Agostinho C. Rosa, Ajith Abraham
2007 B conf
IEEE Congress on Evolutionary Computation
Vitorino Ramos, Carlos M. Fernandes, Agostinho C. Rosa, Ajith Abraham
2007 Misc conf
SAC
Carlos M. Fernandes, Vitorino Ramos, Agostinho C. Rosa
2006 A conf
PPSN
Carlos M. Fernandes, Agostinho C. Rosa
2005 J jnl
CoRR
Vitorino Ramos, Carlos M. Fernandes, Agostinho C. Rosa
2005 J jnl
CoRR
Vitorino Ramos, Carlos M. Fernandes, Agostinho C. Rosa
2005 J jnl
CoRR
Carlos M. Fernandes, Vitorino Ramos, Agostinho C. Rosa
2005 J jnl
CoRR
Vitorino Ramos, Carlos M. Fernandes, Agostinho C. Rosa
2005 conf
ICANN (1)
Carlos M. Fernandes, Vitorino Ramos, Agostinho C. Rosa
2001 B conf
CEC
Carlos M. Fernandes, Agostinho C. Rosa
2001 Misc conf
SAC
Carlos M. Fernandes, Rui Tavares, Cristian Munteanu, Agostinho C. Rosa
2000 conf
SAC (1)
Carlos M. Fernandes, Rui Tavares, Agostinho C. Rosa
1999 A conf
GECCO
Carlos M. Fernandes, João Paulo Caldeira, Fernando Melicio, Agostinho C. Rosa
1999 Misc conf
SAC
Carlos M. Fernandes, João Paulo Caldeira, Fernando Melicio, Agostinho C. Rosa
redb/extractors/apk_extractors/apk_dex.py
← Index redb/extractors/apk_extractors/apk_dex.py python
import hashlib
import inspect
import json
from collections import Counter
from datetime import datetime, timezone
from typing import Any

import tlsh

from redb.extractors.enum import Tag
from redb.extractors.apk_extractor import APKExtractor
from redb.models.dataclasses import APKDexFile

# Sensitive API patterns categorized for malware analysis
SENSITIVE_API_CATEGORIES = {
    "reflection": [
        "Ljava/lang/reflect/Method;->invoke",
        "Ljava/lang/reflect/Field;->get",
        "Ljava/lang/reflect/Field;->set",
        "Ljava/lang/reflect/Constructor;->newInstance",
        "Ljava/lang/Class;->forName",
        "Ljava/lang/Class;->getMethod",
        "Ljava/lang/Class;->getDeclaredMethod",
        "Ljava/lang/Class;->getDeclaredField",
        "Ljava/lang/ClassLoader;->loadClass",
    ],
    "crypto": [
        "Ljavax/crypto/Cipher;->getInstance",
        "Ljavax/crypto/Cipher;->init",
        "Ljavax/crypto/spec/SecretKeySpec;-><init>",
        "Ljavax/crypto/spec/IvParameterSpec;-><init>",
        "Ljava/security/MessageDigest;->getInstance",
        "Ljava/security/KeyStore;->getInstance",
        "Ljavax/crypto/Mac;->getInstance",
    ],
    "dynamic_loading": [
        "Ldalvik/system/DexClassLoader;-><init>",
        "Ldalvik/system/PathClassLoader;-><init>",
        "Ldalvik/system/InMemoryDexClassLoader;-><init>",
        "Ldalvik/system/BaseDexClassLoader;-><init>",
        "Ljava/lang/Runtime;->exec",
        "Ljava/lang/ProcessBuilder;->start",
    ],
    "telephony": [
        "Landroid/telephony/TelephonyManager;->getDeviceId",
        "Landroid/telephony/TelephonyManager;->getSubscriberId",
        "Landroid/telephony/TelephonyManager;->getLine1Number",
        "Landroid/telephony/TelephonyManager;->getSimSerialNumber",
        "Landroid/telephony/TelephonyManager;->getNetworkOperator",
        "Landroid/telephony/TelephonyManager;->getSimOperator",
    ],
    "sms": [
        "Landroid/telephony/SmsManager;->sendTextMessage",
        "Landroid/telephony/SmsManager;->sendMultipartTextMessage",
        "Landroid/telephony/SmsManager;->sendDataMessage",
    ],
    "network": [
        "Ljava/net/HttpURLConnection;->connect",
        "Ljava/net/URL;->openConnection",
        "Lokhttp3/OkHttpClient;-><init>",
        "Lokhttp3/Request$Builder;->build",
        "Lorg/apache/http/client/HttpClient;->execute",
        "Landroid/webkit/WebView;->loadUrl",
        "Landroid/webkit/WebView;->setWebViewClient",
    ],
    "native": [
        "Ljava/lang/System;->loadLibrary",
        "Ljava/lang/System;->load",
        "Ljava/lang/Runtime;->loadLibrary",
    ],
    "device_info": [
        "Landroid/os/Build;->FINGERPRINT",
        "Landroid/os/Build;->MODEL",
        "Landroid/os/Build;->MANUFACTURER",
        "Landroid/os/Build;->PRODUCT",
        "Landroid/os/Build;->BRAND",
        "Landroid/os/Build;->DEVICE",
        "Landroid/os/Build;->HARDWARE",
        "Landroid/os/Build;->SERIAL",
        "Landroid/os/Build$VERSION;->SDK_INT",
        "Landroid/provider/Settings$Secure;->getString",
    ],
    "file_io": [
        "Ljava/io/FileOutputStream;-><init>",
        "Ljava/io/FileInputStream;-><init>",
        "Landroid/content/SharedPreferences;->edit",
        "Landroid/database/sqlite/SQLiteDatabase;->execSQL",
        "Landroid/database/sqlite/SQLiteDatabase;->rawQuery",
    ],
    "ipc": [
        "Landroid/content/ContentResolver;->query",
        "Landroid/content/ContentResolver;->insert",
        "Landroid/content/ContentResolver;->delete",
        "Landroid/content/Intent;-><init>",
        "Landroid/content/Context;->sendBroadcast",
        "Landroid/content/Context;->startService",
        "Landroid/content/Context;->bindService",
    ],
}


class APKDexExtractor(APKExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        known_benign=False, known_malicious=False,
        apk=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            known_benign, known_malicious, apk,
        )
        self.dex_files = []
        self.log.debug(inspect.currentframe().f_code.co_name)

    def tag(self):
        return Tag.APK_DEX.value

    def _analyze_api_usage(self, dex):
        """Categorize sensitive API calls found in DEX bytecode."""
        api_usage = {cat: set() for cat in SENSITIVE_API_CATEGORIES}

        try:
            for method in dex.get_encoded_methods():
                code = method.get_code()
                if not code:
                    continue
                try:
                    bytecode = code.get_bc()
                    if not bytecode:
                        continue
                    for instruction in bytecode.get_instructions():
                        op_name = instruction.get_name()
                        if not op_name or not op_name.startswith("invoke"):
                            continue
                        output = instruction.get_output()
                        if not output:
                            continue
                        for category, patterns in SENSITIVE_API_CATEGORIES.items():
                            for pattern in patterns:
                                if pattern in output:
                                    api_usage[category].add(output.strip())
                                    break
                except Exception:
                    continue
        except Exception as e:
            self.log.warning(f"Error analyzing API usage: {e}")

        # Convert sets to sorted lists
        return {cat: sorted(calls) for cat, calls in api_usage.items() if calls}

    def _compute_obfuscation_indicators(self, classes, methods):
        """Compute obfuscation indicators from class/method names."""
        class_names = []
        for cls in classes:
            try:
                name = cls.get_name()
                if name:
                    class_names.append(name)
            except Exception:
                continue

        method_names = []
        for m in methods:
            try:
                name = m.get_name()
                if name and name not in ("<init>", "<clinit>"):
                    method_names.append(name)
            except Exception:
                continue

        if not class_names:
            return None

        # Short class names: extract just the class part from Dalvik notation
        short_class = 0
        for n in class_names:
            simple = n.split("/")[-1].rstrip(";")
            if len(simple) <= 2:
                short_class += 1

        short_method = sum(1 for n in method_names if len(n) <= 2)

        return {
            "short_class_names_pct": round(short_class / max(len(class_names), 1), 4),
            "short_method_names_pct": round(short_method / max(len(method_names), 1), 4),
            "non_ascii_identifiers": sum(1 for n in class_names if not n.isascii()),
            "avg_class_name_length": round(
                sum(len(n) for n in class_names) / max(len(class_names), 1), 2
            ),
        }

    def _compute_top_packages(self, classes):
        """Compute top packages by class count."""
        package_counter = Counter()
        for cls in classes:
            try:
                name = cls.get_name()  # "Lcom/example/foo/Bar;"
                if not name:
                    continue
                parts = name[1:].replace("/", ".").rsplit(".", 1)
                if len(parts) > 1:
                    package = parts[0]
                else:
                    package = "(default)"
                package_counter[package] += 1
            except Exception:
                continue

        return [
            {"package": pkg, "class_count": count}
            for pkg, count in package_counter.most_common(20)
        ]

    def extract(self):
        if not self._is_valid_apk():
            self.log.error(f"Invalid APK for {self.hash.sha256}")
            return None

        from androguard.core.dex import DEX

        try:
            dex_names = list(self.apk.get_dex_names() or [])
        except Exception as e:
            self.log.warning(f"Error getting DEX names for {self.hash.sha256}: {e}")
            dex_names = []

        try:
            dex_buffers = list(self.apk.get_all_dex() or [])
        except Exception as e:
            self.log.error(f"Error getting DEX buffers for {self.hash.sha256}: {e}")
            return None

        if not dex_buffers:
            self.log.debug("No DEX files found in APK")
            return None

        self.dex_files = []
        for i, dex_data in enumerate(dex_buffers):
            dex_name = dex_names[i] if i < len(dex_names) else f"classes{i}.dex"

            dex_sha256 = hashlib.sha256(dex_data).hexdigest()
            dex_tlsh = None
            if len(dex_data) >= 50:
                try:
                    dex_tlsh = tlsh.hash(dex_data) or None
                except Exception:
                    pass

            try:
                d = DEX(dex_data)
            except Exception as e:
                self.log.warning(f"Failed to parse DEX {dex_name}: {e}")
                continue

            try:
                classes = list(d.get_classes() or [])
            except Exception as e:
                self.log.warning(f"Error getting classes from {dex_name}: {e}")
                classes = []
            try:
                methods = list(d.get_methods() or [])
            except Exception as e:
                self.log.warning(f"Error getting methods from {dex_name}: {e}")
                methods = []
            try:
                strings = list(d.get_strings() or [])
            except Exception as e:
                self.log.warning(f"Error getting strings from {dex_name}: {e}")
                strings = []

            try:
                top_packages = self._compute_top_packages(classes)
            except Exception as e:
                self.log.warning(f"Error computing top packages for {dex_name}: {e}")
                top_packages = []
            try:
                api_usage = self._analyze_api_usage(d)
            except Exception as e:
                self.log.warning(f"Error analyzing API usage for {dex_name}: {e}")
                api_usage = {}
            try:
                obfuscation_indicators = self._compute_obfuscation_indicators(classes, methods)
            except Exception as e:
                self.log.warning(f"Error computing obfuscation indicators for {dex_name}: {e}")
                obfuscation_indicators = None

            self.dex_files.append(APKDexFile(
                filename=dex_name,
                sha256=dex_sha256,
                class_count=len(classes),
                method_count=len(methods),
                string_count=len(strings),
                tlsh=dex_tlsh,
                top_packages=top_packages,
                api_usage=api_usage if api_usage else None,
                obfuscation_indicators=obfuscation_indicators,
            ))

        return self.dex_files if self.dex_files else None

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            if not self.dex_files:
                return None

            current_time = datetime.now(timezone.utc)

            # DEX table: one row per DEX file
            dex_data = []
            for dex in self.dex_files:
                dex_data.append([
                    self.sha256,
                    dex.sha256,
                    dex.filename,
                    dex.tlsh,
                    dex.class_count,
                    dex.method_count,
                    dex.string_count,
                    json.dumps(dex.top_packages) if dex.top_packages else None,
                    json.dumps(dex.obfuscation_indicators) if dex.obfuscation_indicators else None,
                    current_time,
                ])

            # API usage table: one row per category per DEX
            api_data = []
            for dex in self.dex_files:
                if dex.api_usage:
                    for category, api_calls in dex.api_usage.items():
                        api_data.append([
                            self.sha256,
                            dex.sha256,
                            category,
                            api_calls,
                            current_time,
                        ])

            return {
                'multi_table': True,
                'dex': {
                    'table': 'redb_apk_dex',
                    'data': dex_data,
                    'column_names': [
                        'sha256', 'dex_sha256', 'dex_filename', 'dex_tlsh',
                        'dex_class_count', 'dex_method_count', 'dex_string_count',
                        'dex_top_packages', 'dex_obfuscation_indicators',
                        'analysis_date',
                    ],
                    'column_type_names': [
                        'FixedString(64)', 'FixedString(64)', 'String', 'Nullable(String)',
                        'UInt32', 'UInt32', 'UInt32',
                        'Nullable(String)', 'Nullable(String)',
                        "DateTime64(3, 'UTC')",
                    ],
                },
                'api_usage': {
                    'table': 'redb_apk_dex_api_usage',
                    'data': api_data,
                    'column_names': [
                        'sha256', 'dex_sha256', 'api_category',
                        'api_calls', 'analysis_date',
                    ],
                    'column_type_names': [
                        'FixedString(64)', 'FixedString(64)', 'LowCardinality(String)',
                        'Array(String)', "DateTime64(3, 'UTC')",
                    ],
                },
            }

    def get_clickhouse_table(self) -> str:
        return "redb_apk_dex"