Ramon Guzman

25 papers C 13Journal 11Unranked 1
YearRankTypeTitle / Venue / Authors
2025 J jnl
IEEE Trans. Ind. Electron.
Carlos Alfaro, Ramon Guzman, Antonio Camacho, Ángel Borrell, Luis García de Vicuña
2025 J jnl
IEEE Trans. Ind. Electron.
José-Pascual Chico-Villegas, Ramon Guzman, Luis García de Vicuña, Miguel Castilla, Ángel Borrell
2024 C conf
IECON
José-Pascual Chico-Villegas, Ramon Guzman, Luis García de Vicuña, Jaume Miret, Miguel Castilla, Ángel Borrell
2023 C conf
IECON
Hasan Komurcugil, Naki Guler, Sertac Bayhan, Ramon Guzman
2023 C conf
IECON
José-Pascual Chico-Villegas, Ramon Guzman, Luis García de Vicuña, Jaume Miret, Miguel Castilla, Hasan Komurcugil
2022 J jnl
IEEE Trans. Ind. Electron.
Carlos Alfaro Aragon, Ramon Guzman, Luis García de Vicuña, Jaume Miret, Miguel Castilla
2022 J jnl
IEEE Trans. Ind. Electron.
Carlos Alfaro, Ramon Guzman, Luis García de Vicuña, Hasan Komurcugil, Helena Martín
2022 C conf
IECON
Hasan Komurcugil, Sertac Bayhan, Naki Guler, Ramon Guzman
2021 J jnl
IEEE Trans. Ind. Electron.
Osman Kukrer, Hasan Komurcugil, Ramon Guzman, Luis García de Vicuña
2020 J jnl
IEEE Trans. Ind. Electron.
Miguel Andres Garnica Lopez, Luis García de Vicuña, Jaume Miret, Miguel Castilla, Ramon Guzman
2019 J jnl
IEEE Trans. Ind. Electron.
Ramon Guzman, Luis García de Vicuña, Antonio Camacho, Jaume Miret, Juan M. Rey
2018 J jnl
IEEE Trans. Ind. Electron.
Javier Morales, Luis García de Vicuña, Ramon Guzman, Miguel Castilla, Jaume Miret
2018 J jnl
IEEE Trans. Ind. Electron.
Ramon Guzman, Luis García de Vicuña, Miguel Castilla, Jaume Miret, Jordi de la Hoz
2017 conf
ISIE
Mohammad Moradi Ghahderijani, Miguel Castilla, Jaume Miret, Ramon Guzman, Juan Manuel Rey
2016 J jnl
IEEE Trans. Ind. Electron.
Ramon Guzman, Luis García de Vicuña, Javier Morales, Miguel Castilla, Jaume Miret
2016 C conf
IECON
Javier Morales, Luis García de Vicuña, Ramon Guzman
2015 C conf
IECON
Ramon Guzman, Luis García de Vicuña, Javier Morales, Arash Momeneh, Jaume Miret, Javier Torres-Martinez
2015 C conf
IECON
Javier Torres-Martinez, Miguel Castilla, Jaume Miret, Mohammad Moradi Ghahderijani, Javier Morales, Ramon Guzman
2015 C conf
IECON
Javier Morales, Luis García de Vicuña, Ramon Guzman, Miguel Castilla, Jaume Miret, Javier Torres-Martinez
2015 C conf
IECON
Javier Morales, Luis García de Vicuña, Ramon Guzman, Miguel Castilla, Arash Momeneh, Javier Torres-Martinez
2015 C conf
IECON
Ramon Guzman, Luis García de Vicuña, Javier Morales, Miguel Castilla, Jaume Miret, Javier Torres-Martinez
2014 J jnl
IEEE Trans. Ind. Electron.
José Matas, Miguel Castilla, Jaume Miret, Luis García de Vicuña, Ramon Guzman
2013 C conf
IECON
Ramon Guzman, Luis García de Vicuña, Antonio Camacho, José Matas, Miguel Castilla, Jaume Miret
2013 C conf
IECON
Antonio Camacho, Miguel Castilla, Jaume Miret, José Matas, Ramon Guzman, Oscar De Sousa-Perez, Pau Martí, Luis García de Vicuña
2013 C conf
IECON
Oscar De Sousa-Perez, Jaume Miret, Antonio Camacho, Pau Martí, Ramon Guzman
redb/extractors/apk_extractors/apk_features.py
← Index redb/extractors/apk_extractors/apk_features.py python
import inspect
import zipfile
from datetime import datetime, timezone
from typing import Any

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


class APKFeaturesExtractor(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.apk_features = None
        self.log.debug(inspect.currentframe().f_code.co_name)

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

    def _extract_zip_timestamps(self):
        """Extract earliest and latest content modification from ZIP entries."""
        earliest = None
        latest = None
        try:
            zf = self._get_zip_file()
            if zf:
                with zf:
                    for info in zf.infolist():
                        try:
                            dt = datetime(*info.date_time)
                            if earliest is None or dt < earliest:
                                earliest = dt
                            if latest is None or dt > latest:
                                latest = dt
                        except (ValueError, TypeError):
                            continue
        except Exception as e:
            self.log.warning(f"Error extracting ZIP timestamps: {e}")
        return (
            earliest.isoformat() if earliest else None,
            latest.isoformat() if latest else None,
        )

    def _extract_supported_abis(self):
        """Determine supported ABIs from lib/ directory."""
        abis = set()
        for f in self._list_files():
            if f.startswith("lib/") and f.endswith(".so"):
                parts = f.split("/")
                if len(parts) >= 3:
                    abis.add(parts[1])
        return sorted(abis)

    def _count_dex_files(self):
        """Count DEX files and compute total size."""
        dex_count = 0
        total_size = 0
        try:
            zf = self._get_zip_file()
            if zf:
                with zf:
                    for info in zf.infolist():
                        if info.filename.endswith(".dex"):
                            dex_count += 1
                            total_size += info.file_size
        except Exception as e:
            self.log.warning(f"Error counting DEX files: {e}")
        return dex_count, total_size

    def _check_embedded_apk(self):
        """Check if the archive contains nested APK files."""
        for f in self._list_files():
            if f.lower().endswith(".apk"):
                return True
        return False

    def _safe_extract(self, field_name, func, default=None):
        """Extract a single field, logging and returning default on failure."""
        try:
            return func()
        except Exception as e:
            self.log.warning(
                f"Error extracting APK field '{field_name}' for "
                f"{self.hash.sha256}: {e}"
            )
            return default

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

        package_name = self._safe_extract(
            "package_name", lambda: self.apk.get_package()
        )
        app_name = self._safe_extract(
            "app_name", lambda: self.apk.get_app_name()
        )

        def _get_version_code():
            try:
                return int(self.apk.get_androidversion_code() or 0)
            except (ValueError, TypeError):
                return 0

        version_code = self._safe_extract("version_code", _get_version_code)
        version_name = self._safe_extract(
            "version_name", lambda: self.apk.get_androidversion_name()
        )

        def _get_sdk(getter):
            val = getter()
            return int(val) if val else None

        min_sdk = self._safe_extract(
            "min_sdk_version", lambda: _get_sdk(self.apk.get_min_sdk_version)
        )
        target_sdk = self._safe_extract(
            "target_sdk_version", lambda: _get_sdk(self.apk.get_target_sdk_version)
        )
        compile_sdk = self._safe_extract(
            "compile_sdk_version",
            lambda: _get_sdk(self.apk.get_effective_target_sdk_version),
        )

        main_activity = self._safe_extract(
            "main_activity", lambda: self.apk.get_main_activity()
        )

        is_debuggable = self._safe_extract(
            "is_debuggable",
            lambda: self.apk.get_attribute_value(
                "application", "debuggable"
            ) == "true",
            False,
        )
        allow_backup = self._safe_extract(
            "allow_backup",
            lambda: self.apk.get_attribute_value(
                "application", "allowBackup"
            ) != "false",
            True,
        )
        uses_cleartext = self._safe_extract(
            "uses_cleartext_traffic",
            lambda: self.apk.get_attribute_value(
                "application", "usesCleartextTraffic"
            ) == "true",
            False,
        )

        supported_abis = self._safe_extract(
            "supported_abis", self._extract_supported_abis, []
        )
        dex_count, total_dex_size = self._safe_extract(
            "dex_files", self._count_dex_files, (0, 0)
        )
        all_files = self._safe_extract("file_list", self._list_files, [])
        total_file_count = len(all_files)
        has_native_code = any(
            f.startswith("lib/") and f.endswith(".so") for f in all_files
        )
        has_assets = any(f.startswith("assets/") for f in all_files)
        contains_embedded_apk = self._safe_extract(
            "contains_embedded_apk", self._check_embedded_apk, False
        )

        uses_libraries = self._safe_extract(
            "uses_libraries",
            lambda: list(self.apk.get_libraries() or []),
            [],
        )

        earliest_mod, latest_mod = self._safe_extract(
            "zip_timestamps", self._extract_zip_timestamps, (None, None)
        )

        self.apk_features = APKFeatures(
            package_name=package_name,
            app_name=app_name,
            version_code=version_code,
            version_name=version_name,
            min_sdk_version=min_sdk,
            target_sdk_version=target_sdk,
            compile_sdk_version=compile_sdk,
            main_activity=main_activity,
            is_debuggable=is_debuggable,
            allow_backup=allow_backup,
            uses_cleartext_traffic=uses_cleartext,
            supported_abis=supported_abis,
            dex_count=dex_count,
            total_dex_size=total_dex_size,
            total_file_count=total_file_count,
            has_native_code=has_native_code,
            has_assets=has_assets,
            uses_libraries=uses_libraries,
            earliest_content_modification=earliest_mod,
            latest_content_modification=latest_mod,
            contains_embedded_apk=contains_embedded_apk,
        )
        return self.apk_features

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

            f = self.apk_features
            current_time = datetime.now(timezone.utc)
            data = [[
                self.sha256,
                f.package_name,
                f.app_name,
                f.version_code,
                f.version_name,
                f.min_sdk_version,
                f.target_sdk_version,
                f.compile_sdk_version,
                f.main_activity,
                int(f.is_debuggable),
                int(f.allow_backup),
                int(f.uses_cleartext_traffic),
                f.supported_abis,
                f.dex_count,
                f.total_dex_size,
                f.total_file_count,
                int(f.has_native_code),
                int(f.has_assets),
                f.uses_libraries,
                f.earliest_content_modification,
                f.latest_content_modification,
                int(f.contains_embedded_apk),
                current_time,
            ]]

            column_names = [
                "sha256",
                "package_name", "app_name", "version_code", "version_name",
                "min_sdk_version", "target_sdk_version", "compile_sdk_version",
                "main_activity",
                "is_debuggable", "allow_backup", "uses_cleartext_traffic",
                "supported_abis",
                "dex_count", "total_dex_size", "total_file_count",
                "has_native_code", "has_assets",
                "uses_libraries",
                "earliest_content_modification", "latest_content_modification",
                "contains_embedded_apk",
                "analysis_date",
            ]

            column_type_names = [
                "FixedString(64)",
                "Nullable(String)", "Nullable(String)", "Nullable(UInt32)", "Nullable(String)",
                "Nullable(UInt16)", "Nullable(UInt16)", "Nullable(UInt16)",
                "Nullable(String)",
                "UInt8", "UInt8", "UInt8",
                "Array(String)",
                "UInt16", "UInt64", "UInt32",
                "UInt8", "UInt8",
                "Array(String)",
                "Nullable(String)", "Nullable(String)",
                "UInt8",
                "DateTime64(3, 'UTC')",
            ]

            return (data, column_names, column_type_names)

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