Chandan Kumar

37 papers A* 2B 8C 1Misc 2Journal 5Unranked 19
YearRankTypeTitle / Venue / Authors
2026 conf
CHI Extended Abstracts
Bhupender Kumar Saini, Chandan Kumar, Kathrin Pollmann, Janina Bierkandt, Doris Janssen, Christian Knecht, Nora Fronemann
2025 J jnl
ACM Trans. Web
Raphael Menges, Steffen Staab, Christoph Schaefer, Tina Walber, Chandan Kumar
2024 conf
CHI Extended Abstracts
Chandan Kumar, Bhupender Kumar Saini, Steffen Staab
2024 conf
CHI Extended Abstracts
Andreas Schuller, Doris Janssen, Julian Blumenröther, Theresa Maria Probst, Michael Schmidt, Chandan Kumar
2024 conf
CHI Extended Abstracts
Chandan Kumar, Eileen Wemmer, Apeksha Manoj Rahangdale, Astrid Marieke Rosenthal-von der Pütten
2022 B conf
ICMI
Ramin Hedeshy, Chandan Kumar, Mike Lauer, Steffen Staab
2021 A* conf
CHI
Ramin Hedeshy, Chandan Kumar, Raphael Menges, Steffen Staab
2020 conf
ETRA Short Papers
Raphael Menges, Sophia Kramer, Stefan Hill, Marius Nisslmueller, Chandan Kumar, Steffen Staab
2020 conf
ETRA Adjunct
Ramin Hedeshy, Chandan Kumar, Raphael Menges, Steffen Staab
2020 A* conf
CHI
Chandan Kumar, Ramin Hedeshy, I. Scott MacKenzie, Steffen Staab
2019 B conf
ETRA
Korok Sengupta, Raphael Menges, Chandan Kumar, Steffen Staab
2019 J jnl
ACM Trans. Comput. Hum. Interact.
Raphael Menges, Chandan Kumar, Steffen Staab
2019 B conf
ICMI
Chandan Kumar, Daniyal Akbari, Raphael Menges, I. Scott MacKenzie, Steffen Staab
2018 B conf
ETRA
Raphael Menges, Hanadi Tamimi, Chandan Kumar, Tina Walber, Christoph Schaefer, Steffen Staab
2018 B conf
ETRA
Raphael Menges, Hanadi Tamimi, Chandan Kumar, Tina Walber, Christoph Schaefer, Steffen Staab
2018 B conf
ETRA
Korok Sengupta, Min Ke, Raphael Menges, Chandan Kumar, Steffen Staab
2017 B conf
CBMS
Korok Sengupta, Jun Sun, Raphael Menges, Chandan Kumar, Steffen Staab
2017 J jnl
CoRR
Korok Sengupta, Jun Sun, Raphael Menges, Chandan Kumar, Steffen Staab
2017 B conf
CBMS
Chandan Kumar, Raphael Menges, Steffen Staab
2017 conf
WWW (Companion Volume)
Chandan Kumar, Raphael Menges, Daniel Müller, Steffen Staab
2017 conf
IUI Companion
Korok Sengupta, Raphael Menges, Chandan Kumar, Steffen Staab
2017 conf
W4A
Raphael Menges, Chandan Kumar, Daniel Müller, Korok Sengupta
2016 J jnl
IEEE Multim.
Chandan Kumar, Raphael Menges, Steffen Staab
2016 Misc conf
NordiCHI
Raphael Menges, Chandan Kumar, Korok Sengupta, Steffen Staab
2015 J jnl
ISPRS Int. J. Geo Inf.
Chandan Kumar, Wilko Heuten, Susanne Boll
2014 conf
MobiWIS
Chandan Kumar, Sebastian Barton, Wilko Heuten, Susanne Boll
2014 conf
WI-IAT (1)
Chandan Kumar, Uwe Gruenefeld, Wilko Heuten, Susanne Boll
2013 conf
I-KNOW
Chandan Kumar, Wilko Heuten, Susanne Boll
2013 conf
MapInteract
Chandan Kumar, Benjamin Poppinga, Daniel Haeuser, Wilko Heuten, Susanne Boll
2013 conf
GIR
Chandan Kumar, Susanne Boll
2013 conf
GIR
Chandan Kumar, Wilko Heuten, Susanne Boll
2013 conf
UbiComp (Adjunct Publication)
Chandan Kumar, Benjamin Poppinga, Daniel Haeuser, Wilko Heuten, Susanne Boll
2013 conf
EuroHCIR
Chandan Kumar, Dirk Ahlers, Wilko Heuten, Susanne Boll
2013 conf
CD-ARES
Chandan Kumar, Wilko Heuten, Susanne Boll
2009 Misc conf
SAC
Chandan Kumar, Prasad Pingali, Vasudeva Varma
2009 C conf
CICLing
Chandan Kumar, Prasad Pingali, Vasudeva Varma
2008 conf
Web Intelligence/IAT Workshops
Chandan Kumar, Prasad Pingali, Vasudeva Varma
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"