Hailong Kang

11 papers C 1Journal 10
YearRankTypeTitle / Venue / Authors
2025 J jnl
IEEE Geosci. Remote. Sens. Lett.
Hailong Kang, Hongwen Deng, Rou Xin, Jun Li, Qinghua Guo, Marco Martorella
2024 C conf
IGARSS
Hailong Kang, Liang Xu, Tuoyu Shen, Jun Li, Marco Martorella
2024 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Zhaocheng Wang, Ruonan Wang, Hailong Kang, Feng Luo, Jiaqiu Ai
2024 J jnl
Remote. Sens.
Zhaocheng Wang, Guangxuan Hu, Shuo Zhao, Ruonan Wang, Hailong Kang, Feng Luo
2023 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Hailong Kang, Jun Li, Qinghua Guo, Marco Martorella, Elisa Giusti, Jinjian Cai
2023 J jnl
Remote. Sens.
Ruonan Wang, Zhaocheng Wang, Yu Chen, Hailong Kang, Feng Luo, Ying-Xi Liu
2022 J jnl
IEEE Geosci. Remote. Sens. Lett.
Jieru Ding, Min Wang, Hailong Kang, Zhiyi Wang
2021 J jnl
Nucleic Acids Res.
Yongbiao Xue, Yiming Bao, Zhang Zhang, Wenming Zhao, Jing-Fa Xiao, Shunmin He, Guoqing Zhang, Yixue Li, Guoping Zhao, Runsheng Chen, Shuhui Song, Lina Ma, Dong Zou, Dongmei Tian, Cuiping Li, Junwei Zhu, Zheng Gong, Meili Chen, Anke Wang, Yingke Ma, Mengwei Li, Xufei Teng, Ying Cui, Guangya Duan, Mochen Zhang, Tong Jin, Chengmin Shi, Zhenglin Du, Yadong Zhang, Chuandong Liu, Rujiao Li, Jingyao Zeng, Lili Hao, Shuai Jiang, Hua Chen, Dali Han, Tao Zhang, Wang Kang, Fei Yang, Jing Qu, Weiqi Zhang, Guanghui Liu, Lin Liu, Yang Zhang, Guangyi Niu, Tongtong Zhu, Changrui Feng, Xiaonan Liu, Yuansheng Zhang, Zhao Li, Ruru Chen, Qianpeng Li, Zhongyi Hua, Chao Jiang, Ziyuan Chen, Fangshu He, Yuyang Zhao, Yan Jin, Luqi Huang, Yuan Yuan, Chenfen Zhou, Qingwei Xu, Sheng He, Wei Ye, Ruifang Cao, Pengyu Wang, Yunchao Ling, Xing Yan, Qingzhong Wang, Qiang Du, Wenting Zong, Hongen Kang, Zhuang Xiong, Wendi Huan, Sirui Zhang, Qiguang Xia, Xiaojuan Fan, Zefeng Wang, Xu Chen, Tingting Chen, Sisi Zhang, Bixia Tang, Lili Dong, Zhewen Zhang, Zhonghuang Wang, Hailong Kang, Yanqing Wang, Song Wu, Ming Chen, Chang Liu, Yujia Xiong, Xueying Shao, Yanyan Li, Honghong Zhou, Xiaomin Chen, Yu Zheng, Quan Kang, Di Hao, LiLi Zhang, Huaxia Luo, Yajing Hao, Peng Zhang, Zhi Nie, Shuhuan Yu, Jian Sang, Zhaohua Li, Xiangquan Zhang, Qing Zhou, Shuang Zhai, Yaping Zhang, Guodong Wang, Qianghui Zhu, Xin Li, Menghua Li, Jun Yan, Chen Li, Zhennan Wang, Xiangfeng Wang, Yuanming Liu, Hong Luo, Xiaoyuan Wu, Hai-Chun Jing, Lianhe Zhao, Jiajia Wang, Tinrui Song, Yi Zhao, Furrukh Mehmood, Shahid Ali, Amjad Ali, Shoaib Saleem, Irfan Hussain, Amir Ali Abbasi, Zhixiang Zuo, Jian Ren, Xinxin Zhang, Yun Xiao, Xia Li, Yiran Tu, Yu Xue, Wanying Wu, Peifeng Ji, Fangqing Zhao, Xianwen Meng, Di Peng, Hao Luo, Feng Gao, Wanshan Ning, Shaofeng Lin, Teng Liu, An-Yuan Guo, Hao Yuan, Yong E. Zhang, Xiaodan Tan, Weizhi Zhang, Yubin Xie, Chenwei Wang, Chun-Jie Liu, De-Chang Yang, Feng Tian, Ge Gao, Dachao Tang, Lan Yao, Qinghua Cui, Ni A. An, Chuan-Yun Li, Xiaotong Luo
2021 J jnl
IEEE Access
Huihui Ma, Haihong Tao, Hailong Kang
2019 J jnl
Digit. Signal Process.
Yifan Guo, Guisheng Liao, Jun Li, Hailong Kang
2019 J jnl
Sensors
Hailong Kang, Jun Li, Hongyan Zhao, Zhiyu Bao, Zehua Yu
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"