Xiangyu Wang

66 papers C 8Journal 47Unranked 11
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Ind. Informatics
Guodong Wang, Xiangyu Wang, Shihua Li
2026 J jnl
Int. J. Syst. Sci.
Luxin Lin, Zhiyi Chen, Xiangyu Wang, Shihua Li, Xinghuo Yu
2026 J jnl
IEEE Trans. Autom. Control.
Xiangyu Wang, Ji Wang, Yang-Yang Chen, Yuhao Ma, Shihua Li
2026 J jnl
IEEE Trans Autom. Sci. Eng.
Weiming Liu, Guodong Wang, Xiangyu Wang
2025 J jnl
IEEE Trans. Control. Syst. Technol.
Quanwei Wu, Guodong Wang, Xiangyu Wang
2025 J jnl
Trans. Inst. Meas. Control
Quanwei Wu, Xiangyu Wang
2025 J jnl
IEEE Robotics Autom. Lett.
Jinhao Liu, Jun Yang, Jianliang Mao, Tianqi Zhu, Qihang Xie, Yimeng Li, Xiangyu Wang, Shihua Li
2025 J jnl
J. Frankl. Inst.
Ziyang Huang, Yuhao Ma, Xiangyu Wang, Shihua Li
2025 J jnl
IEEE Trans. Autom. Control.
Jinhao Liu, Jun Yang, Yunda Yan, Yuan Tan, Xiangyu Wang, Shihua Li
2025 J jnl
IEEE Trans. Smart Grid
Saijin Huang, Zhiyi Chen, Xiangyu Wang, Shihua Li, Xinghuo Yu, Qi Li
2025 J jnl
J. Syst. Control. Eng.
Weiming Liu, Xiangyu Wang
2024 J jnl
IEEE Trans Autom. Sci. Eng.
Guodong Wang, Xiangyu Wang, Shihua Li
2024 J jnl
Autom.
Xiangyu Wang, Yujing Xu, Yue Cao, Shihua Li
2024 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Saijin Huang, Tian Liang Guo, Xiangyu Wang, Shihua Li, Qi Li
2024 C conf
INDIN
Qinhao Tang, Saijin Huang, Xiangyu Wang, Xianghui He, Guanjun Li
2024 J jnl
CoRR
Jinhao Liu, Jun Yang, Jianliang Mao, Tianqi Zhu, Qihang Xie, Yimeng Li, Xiangyu Wang, Shihua Li
2024 J jnl
IEEE Trans. Netw. Sci. Eng.
Guodong Wang, Xiangyu Wang, Shihua Li
2024 J jnl
Trans. Inst. Meas. Control
Xuechao Qiu, Xiangyu Wang
2023 J jnl
Trans. Inst. Meas. Control
Guanjun Li, Haoyuan Li, Xianghui He, Xiangyu Wang
2023 C conf
IECON
Xuechao Qiu, Xiangyu Wang, Dan Niu
2023 J jnl
J. Frankl. Inst.
Xuechao Qiu, Xiangyu Wang
2023 C conf
IECON
Yuanhan Wang, Yang-Yang Chen, Rui Yu, Guoqing Liu, Tianrun Liu, Xiangyu Wang
2023 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Xiangyu Wang, Wei Xing Zheng, Guodong Wang
2023 J jnl
IEEE Trans. Control. Syst. Technol.
Weiming Liu, Xiangyu Wang, Shihua Li
2023 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Zeyu Guo, Zuo Wang, Shihong Ding, Shihua Li, Xiangyu Wang
2023 J jnl
IEEE Trans. Smart Grid
Jilin Lang, Chuanlin Zhang, Fei Xia, Guodong Wang, Xiangyu Wang
2023 J jnl
IEEE Trans. Ind. Electron.
Jinhao Liu, Jun Yang, Shihua Li, Xiangyu Wang
2022 J jnl
IEEE Trans. Ind. Electron.
Xiangyu Wang, Weiming Liu, Quanwei Wu, Shihua Li
2022 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Guipu Li, Xiangyu Wang, Shihua Li
2022 J jnl
J. Frankl. Inst.
Guodong Wang, Xiangyu Wang, Shihua Li
2021 J jnl
Trans. Inst. Meas. Control
Xiangyu Wang, Ling Han, Jiyu Liu
2021 J jnl
IEEE Trans. Cybern.
Xiangyu Wang, Guodong Wang, Shihua Li
2021 J jnl
J. Frankl. Inst.
Baozeng Fu, Xiangyu Wang, Qingzhi Wang
2020 J jnl
Autom.
Xiangyu Wang, Guodong Wang, Shihua Li
2020 J jnl
IEEE Trans. Autom. Control.
Xiangyu Wang, Guodong Wang, Shihua Li
2020 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Xiangyu Wang, Shihua Li, Guodong Wang
2020 J jnl
J. Frankl. Inst.
Jiankun Sun, Jun Yang, Shihua Li, Xiangyu Wang, Guipu Li
2020 J jnl
J. Frankl. Inst.
Guipu Li, Xiangyu Wang, Shihua Li
2020 J jnl
Trans. Inst. Meas. Control
Wenwu Zhu, Dongbo Chen, Haibo Du, Xiangyu Wang
2020 C conf
IECON
Weiming Liu, Xiangyu Wang, Shengyi Liang
2019 J jnl
IEEE Trans. Control. Syst. Technol.
Tian Liang Guo, Zuo Wang, Xiangyu Wang, Shihua Li, Qi Li
2019 J jnl
IEEE Trans. Ind. Informatics
Tian Liang Guo, Zhenxing Sun, Xiangyu Wang, Shihua Li, Kanjian Zhang
2019 conf
ASCC
Guodong Wang, Xiangyu Wang, Shihua Li, Jun Yang, Dan Niu, Xisong Chen
2019 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Guipu Li, Xiangyu Wang, Shihua Li
2019 J jnl
J. Frankl. Inst.
Baozeng Fu, Shihua Li, Xiangyu Wang, Lei Guo
2019 J jnl
IEEE Access
Tian Liang Guo, Saijin Huang, Xiangyu Wang
2018 C conf
ICARCV
Xin Yu, Xiangyu Wang, Shihua Li, Jiyu Liu, Ya Zhang
2018 J jnl
IEEE Trans. Cybern.
Xiangyu Wang, Shihua Li, Michael Z. Q. Chen
2018 conf
ICAC
Pengyu Qiao, Dan Niu, Jie Wang, Xiaojun Wang, Xisong Chen, Xiangyu Wang
2018 conf
VSS
Xiangyu Wang, Guipu Li, Shihua Li
2018 conf
ICAC
Dan Niu, Zhenguo Kuang, Xisong Chen, Shuang Wei, Jun Yang, Xiangyu Wang
2018 J jnl
J. Frankl. Inst.
Guodong Wang, Xiangyu Wang, Shihua Li
2017 J jnl
IEEE Trans. Autom. Control.
Xiangyu Wang, Shihua Li, Xinghuo Yu, Jun Yang
2017 conf
ASCC
Guipu Li, Xiangyu Wang, Shihua Li, Wei Xing Zheng, Xisong Chen
2016 conf
VSS
Xiangyu Wang, Shihua Li
2016 J jnl
Autom.
Xiangyu Wang, Shihua Li, James Lam
2016 C conf
ACC
Xiangyu Wang, Shihua Li
2016 conf
ICCA
Guipu Li, Xiangyu Wang, Shihua Li, Haibo Du
2016 C conf
ICARCV
Hua Li, Haibo Du, Chen Yang, Wenwu Zhu, Xiangyu Wang
2016 conf
CDC
Guipu Li, Xiangyu Wang, Shihua Li, Jun Yang, Xisong Chen
2015 C conf
ACC
Xiangyu Wang, Shihua Li
2015 conf
CDC
Tian Liang Guo, Xiangyu Wang, Shihua Li
2014 J jnl
IEEE Trans. Cybern.
Xiangyu Wang, Shihua Li, Peng Shi
2014 conf
VSS
Xiangyu Wang, Shihua Li
2013 J jnl
Autom.
Shihua Li, Xiangyu Wang
2013 conf
ICONS
Xiangyu Wang, Shihua Li, Chunjiang Qian
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