Xiao Xu

42 papers A* 1C 2Misc 1Journal 35Unranked 3
YearRankTypeTitle / Venue / Authors
2026 J jnl
Pattern Recognit.
Haiwei Hou, Shifei Ding, Chuangui Cao, Xiao Xu, Lili Guo, Xuan Li
2026 J jnl
IEEE Trans. Cogn. Dev. Syst.
Haiwei Hou, Shifei Ding, Xiao Xu, Lili Guo, Ling Ding, Xindong Wu
2026 A* conf
WWW
Shifei Ding, Zhe Li, Xiao Xu, Chao Li
2025 J jnl
IEEE Trans. Knowl. Data Eng.
Shifei Ding, Chao Li, Xiao Xu, Lili Guo, Ling Ding, Xindong Wu
2025 J jnl
Appl. Soft Comput.
Xiao Xu, Hong Liao, Xu Yang
2025 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Shifei Ding, Chao Li, Xiao Xu, Lili Guo, Ling Ding, Xindong Wu
2025 J jnl
IEEE Trans. Knowl. Data Eng.
Hui Tu, Shifei Ding, Xiao Xu, Lili Guo, Ling Ding, Xindong Wu
2025 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Ling Ding, Chao Li, Shifei Ding, Xiao Xu, Lili Guo, Xindong Wu
2025 J jnl
Knowl. Based Syst.
Shifei Ding, Zhe Li, Xiao Xu, Lili Guo, Ling Ding
2025 J jnl
IEEE Trans. Knowl. Data Eng.
Chao Li, Shifei Ding, Xiao Xu, Lili Guo, Ling Ding, Xindong Wu
2024 conf
IIP (1)
Haiwei Hou, Shifei Ding, Xiao Xu, Lili Guo
2024 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Shifei Ding, Haiwei Hou, Xiao Xu, Jian Zhang, Lili Guo, Ling Ding
2024 J jnl
Inf. Sci.
Hui Tu, Shifei Ding, Xiao Xu, Haiwei Hou, Chao Li, Ling Ding
2024 J jnl
CoRR
Benyu Wu, Shifei Ding, Xiao Xu, Lili Guo, Ling Ding, Xindong Wu
2024 J jnl
ACM Trans. Knowl. Discov. Data
Shifei Ding, Benyu Wu, Ling Ding, Xiao Xu, Lili Guo, Hongmei Liao, Xindong Wu
2023 J jnl
Pattern Recognit.
Shifei Ding, Chao Li, Xiao Xu, Ling Ding, Jian Zhang, Lili Guo, Tianhao Shi
2023 J jnl
Soft Comput.
Haiwei Hou, Shifei Ding, Xiao Xu, Ling Ding
2023 J jnl
Inf. Sci.
Shifei Ding, Wei Du, Xiao Xu, Tianhao Shi, Yanru Wang, Chao Li
2023 J jnl
Appl. Soft Comput.
Xiangnan Liu, Shifei Ding, Xiao Xu, Lijuan Wang
2023 J jnl
Int. J. Mach. Learn. Cybern.
Shifei Ding, Wei Du, Chao Li, Xiao Xu, Lijuan Wang, Ling Ding
2023 J jnl
Appl. Intell.
Xiao Xu, Qidong Wang, Lili Guo, Jian Zhang, Shifei Ding
2023 J jnl
Inf. Sci.
Chao Li, Shifei Ding, Xiao Xu, Haiwei Hou, Ling Ding
2023 C conf
ISCC
Xuehan Zhang, Zhongxu Bao, Yuqing Yin, Xu Yang, Xiao Xu, Qiang Niu
2023 J jnl
Pattern Recognit.
Shifei Ding, Benyu Wu, Xiao Xu, Lili Guo, Ling Ding
2023 C conf
ISCC
Xuehan Zhang, Zhongxu Bao, Yuqing Yin, Xu Yang, Xiao Xu, Qiang Niu
2023 J jnl
Int. J. Mach. Learn. Cybern.
Shifei Ding, Yuting Sun, Jian Zhang, Lili Guo, Xiao Xu, Zichen Zhang
2023 Misc conf
ICASSP
Qidong Wang, Lili Guo, Shifei Ding, Jian Zhang, Xiao Xu
2023 J jnl
Appl. Soft Comput.
Xiao Xu, Haiwei Hou, Shifei Ding
2022 J jnl
Int. J. Mach. Learn. Cybern.
Haiwei Hou, Shifei Ding, Xiao Xu
2022 J jnl
Appl. Intell.
Chao Li, Shifei Ding, Xiao Xu, Shuying Du, Tianhao Shi
2021 J jnl
Appl. Intell.
Tianhao Shi, Shifei Ding, Xiao Xu, Ling Ding
2021 J jnl
Inf. Sci.
Xiao Xu, Shifei Ding, Yanru Wang, Lijuan Wang, Weikuan Jia
2020 J jnl
Knowl. Based Syst.
Xiao Xu, Shifei Ding, Lijuan Wang, Yanru Wang
2019 J jnl
Soft Comput.
Xiao Xu, Shifei Ding, Hui Xu, Hongmei Liao, Yu Xue
2019 J jnl
Eng. Appl. Artif. Intell.
Yanru Wang, Shifei Ding, Xiao Xu, Weikuan Jia
2018 conf
BigComp
Xiao Xu, Shifei Ding, Tongfeng Sun
2018 J jnl
Knowl. Based Syst.
Xiao Xu, Shifei Ding, Zhongzhi Shi
2018 J jnl
Int. J. Mach. Learn. Cybern.
Xiao Xu, Shifei Ding, Mingjing Du, Yu Xue
2018 J jnl
Int. J. Mach. Learn. Cybern.
Mingjing Du, Shifei Ding, Xiao Xu, Yu Xue
2018 J jnl
Soft Comput.
Shifei Ding, Xiao Xu, Shuyan Fan, Yu Xue
2017 J jnl
Knowl. Based Syst.
Shifei Ding, Mingjing Du, Tongfeng Sun, Xiao Xu, Yu Xue
2016 conf
IIP
Shuyan Fan, Shifei Ding, Mingjing Du, Xiao Xu
redb/extractors/ioc_extractor/ioc_extractor.py
← Index redb/extractors/ioc_extractor/ioc_extractor.py python
"""
IOC Extractor - Extractor class for extracting IOCs from decompilation results.

This extractor works with in-memory data from DecompileBinja, following the
standard Extractor pattern to support both ClickHouse and PrintExporter (dry-run).

Usage:
    # After DecompileBinja completes:
    ioc_extractor = IOCExtractorFromResults(
        analysis_results=decompiler.analysis_results,
        sha256=sha256,
        log=logger,
        exporters=exporters,
        index_prefix=index_prefix
    )
    ioc_extractor.export_data()
"""

import inspect
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, List, Dict, Optional

from redb.extractors.enum import Tag
from redb.extractors.database_exporters import DatabaseExporter

# Import the IOCScraper and related classes from standalone module
from redb.extractors.ioc_extractor.standalone_ioc_extractor import (
    IOCScraper,
    IOCType,
    SourceType,
    ExtractedIOC,
)
from typing import Set


class IOCExtractorFromResults:
    """
    Extracts IOCs from in-memory decompilation results.

    This follows a simplified Extractor pattern but doesn't inherit from Extractor
    since it doesn't read from a binary file - instead it takes already-processed
    analysis results from DecompileBinja.
    """

    def __init__(
        self,
        analysis_results: Dict[str, Any],
        sha256: str,
        log: Any,
        exporters: Optional[List[DatabaseExporter]] = None,
        index_prefix: Optional[str] = None,
        tld_file: Optional[Path] = None,
        suppress_types: Optional[Set[IOCType]] = None,
        js_context: bool = False,
    ):
        """
        Initialize IOC Extractor with analysis results.

        Args:
            analysis_results: Dict containing 'strings' and 'decompiled' lists from DecompileBinja
            sha256: Sample SHA256 hash
            log: Logger instance
            exporters: List of database exporters (ClickHouse, Print, etc.)
            index_prefix: Index prefix for database
            tld_file: Optional path to TLD list file
            js_context: When True, the underlying IOCScraper rejects FQDN
                candidates that match JS object-access syntax (see
                JS_FP_TLDS / JS_FP_SLDS). Set this for the JS pipeline only;
                APK suppresses FQDN entirely via suppress_types and binary
                callers leave it disabled.
        """
        self.log = log
        self.log.debug(f"Creating {self.__class__.__name__}")
        self.analysis_results = analysis_results
        self.sha256 = sha256
        self.exporters = exporters or []
        self.index_prefix = index_prefix
        self.scraper = IOCScraper(
            tld_file, suppress_types=suppress_types, js_context=js_context,
        )
        self.extracted_iocs: List[ExtractedIOC] = []

    def extract(self) -> List[ExtractedIOC]:
        """
        Extract IOCs from strings and decompiled functions in analysis_results.

        Returns:
            List of ExtractedIOC objects
        """
        self.log.debug(inspect.currentframe().f_code.co_name)
        self.extracted_iocs = []

        # Extract from strings
        strings_count = self._extract_from_strings()

        # Extract from decompiled functions
        functions_count = self._extract_from_decompiled()

        # Extract from text-based artefact surfaces (JS, PowerShell, etc.)
        text_count = self._extract_from_text()

        self.log.info(
            f"Extracted {len(self.extracted_iocs)} IOCs for {self.sha256[:16]}... "
            f"(strings: {strings_count}, functions: {functions_count}, "
            f"text: {text_count})"
        )

        return self.extracted_iocs

    def _extract_from_strings(self) -> int:
        """Extract IOCs from sample's strings."""
        count = 0
        strings = self.analysis_results.get("strings", [])

        for s in strings:
            string_value = s.get("string", "")
            string_offset = s.get("string_offset", 0)

            if isinstance(string_value, bytes):
                string_value = string_value.decode('utf-8', errors='replace')

            for ioc in self.scraper.scrape(string_value, SourceType.STRING, str(string_offset)):
                self.extracted_iocs.append(ioc)
                count += 1

        return count

    def _extract_from_decompiled(self) -> int:
        """Extract IOCs from sample's decompiled functions.

        Supports both Binja format (key: "decompiled", fields: "decompiled_function",
        "decompiled_function_hash", "function_type") and APK format (key:
        "decompiled_content", fields: "decompiled_method", "decompiled_method_hash",
        "method_type").
        """
        count = 0

        # Binja format
        decompiled = self.analysis_results.get("decompiled", [])
        for func in decompiled:
            func_type = func.get("function_type", "UNKNOWN")
            if func_type in ("LIBRARY", "THUNK"):
                continue

            func_content = func.get("decompiled_function", "")
            func_hash = func.get("decompiled_function_hash", "unknown")

            if isinstance(func_content, bytes):
                func_content = func_content.decode('utf-8', errors='replace')

            for ioc in self.scraper.scrape(func_content, SourceType.DECOMPILED_FUNCTION, func_hash):
                self.extracted_iocs.append(ioc)
                count += 1

        # APK format (decompiled_content with method-level fields)
        decompiled_content = self.analysis_results.get("decompiled_content", [])
        for func in decompiled_content:
            func_type = func.get("method_type", "UNKNOWN")
            if func_type in ("LIBRARY", "THUNK"):
                continue

            func_content = func.get("decompiled_method", "")
            func_hash = func.get("decompiled_method_hash", "unknown")

            if isinstance(func_content, bytes):
                func_content = func_content.decode('utf-8', errors='replace')

            for ioc in self.scraper.scrape(func_content, SourceType.DECOMPILED_FUNCTION, func_hash):
                self.extracted_iocs.append(ioc)
                count += 1

        return count

    def _extract_from_text(self) -> int:
        """Extract IOCs from text-based artefact surfaces.

        Walks `analysis_results["text_raw"]` and `analysis_results["text_normalized"]`,
        each a list of `{"content": str, "content_hash": str}` dicts. Each
        list is routed through its own SourceType (`TEXT_RAW` /
        `TEXT_NORMALIZED`) so analysts can distinguish IOCs that were already
        present in the raw source from those exposed only after normalisation
        (deobfuscation/beautification). Generic across text-based formats —
        used by JS today, intended for PowerShell, Python, email body,
        extracted PDF/Office text in the future.
        """
        count = 0

        for key, source_type in (
            ("text_raw", SourceType.TEXT_RAW),
            ("text_normalized", SourceType.TEXT_NORMALIZED),
        ):
            for entry in self.analysis_results.get(key, []):
                content = entry.get("content", "")
                content_hash = entry.get("content_hash", "unknown")

                if isinstance(content, bytes):
                    content = content.decode('utf-8', errors='replace')

                for ioc in self.scraper.scrape(content, source_type, content_hash):
                    self.extracted_iocs.append(ioc)
                    count += 1

        return count

    def prepare_export_data(self, exporter_type: str) -> Any:
        """
        Prepare data for specific export type.

        Returns tuple for ClickHouse or list of dicts for Print/Elasticsearch.
        """
        self.log.debug(inspect.currentframe().f_code.co_name)

        if not self.extracted_iocs:
            return None

        now = datetime.now(timezone.utc)

        if exporter_type == "ClickHouseExporter":
            data = [
                [
                    self.sha256,
                    ioc.ioc_type.value,
                    ioc.ioc_value,
                    ioc.source_type.value,
                    ioc.source_identifier,
                    now,
                ]
                for ioc in self.extracted_iocs
            ]

            column_names = [
                "sha256",
                "ioc_type",
                "ioc_value",
                "source_type",
                "source_identifier",
                "extracted_at",
            ]

            column_type_names = [
                "FixedString(64)",
                "Enum8('ipv4'=1, 'ipv6'=2, 'fqdn'=3, 'url'=4, 'email'=5, 'server'=6, "
                "'hash_md5'=10, 'hash_sha1'=11, 'hash_sha256'=12, 'cve'=20, 'cwe'=21, 'cpe'=22, "
                "'crypto_btc'=30, 'crypto_eth'=31, 'crypto_xrp'=32, 'crypto_bch'=33, "
                "'crypto_ada'=34, 'crypto_substrate'=35, 'path_linux'=40, 'path_windows'=41, "
                "'registry_key'=42, 'onion'=50)",
                "String",
                "Enum8('decompiled_function'=1, 'disassembled_function'=2, 'string'=3, "
                "'text_raw'=4, 'text_normalized'=5)",
                "String",
                "DateTime64(3, 'UTC')",
            ]

            return (data, column_names, column_type_names)

        else:
            # For PrintExporter and others - return list of dicts
            return [
                {
                    "sha256": self.sha256,
                    "ioc_type": ioc.ioc_type.value,
                    "ioc_value": ioc.ioc_value,
                    "source_type": ioc.source_type.value,
                    "source_identifier": ioc.source_identifier,
                    "extracted_at": now.isoformat(),
                }
                for ioc in self.extracted_iocs
            ]

    def get_clickhouse_table(self) -> str:
        """Return the ClickHouse table name for IOCs."""
        return "redb_iocs"

    def tag(self) -> str:
        """Return the tag for this extractor."""
        return Tag.IOC.value if hasattr(Tag, 'IOC') else "ioc"

    def export_data(self) -> bool:
        """
        Export extracted IOCs to all configured exporters.

        Returns:
            True if export succeeded, False if failed, None if no data
        """
        self.log.debug(inspect.currentframe().f_code.co_name)

        # First extract the IOCs
        extracted = self.extract()

        if not extracted:
            self.log.debug("No IOCs extracted, skipping export")
            return None

        success = True

        from redb.extractors.database_exporters import PrintExporter, ClickHouseExporter

        for exporter in self.exporters:
            try:
                if isinstance(exporter, PrintExporter):
                    # For PrintExporter, pass the list of dicts
                    export_data = self.prepare_export_data("PrintExporter")
                    success &= exporter.export(export_data)

                elif isinstance(exporter, ClickHouseExporter):
                    # For ClickHouse, pass tuple with table info
                    export_data = self.prepare_export_data("ClickHouseExporter")
                    if export_data:
                        success &= exporter.export(
                            export_data,
                            table=self.get_clickhouse_table(),
                            column_names=export_data[1],
                            column_type_names=export_data[2]
                        )

            except Exception as e:
                self.log.error(f"Error exporting IOCs to {exporter.__class__.__name__}: {e}")
                success = False

        return success