Wanghan Xu

21 papers A* 2Journal 19
YearRankTypeTitle / Venue / Authors
2025 J jnl
CoRR
Ming Hu, Chenglong Ma, Wei Li, Wanghan Xu, Jiamin Wu, Jucheng Hu, Tianbin Li, Guohang Zhuang, Jiaqi Liu, Yingzhou Lu, Ying Chen, Chaoyang Zhang, Cheng Tan, Jie Ying, Guocheng Wu, Shujian Gao, Pengcheng Chen, Jiashi Lin, Haitao Wu, Lulu Chen, Fengxiang Wang, Yuanyuan Zhang, Xiangyu Zhao, Feilong Tang, Encheng Su, Junzhi Ning, Xinyao Liu, Ye Du, Changkai Ji, Cheng Tang, Huihui Xu, Ziyang Chen, Ziyan Huang, Jiyao Liu, Pengfei Jiang, Yizhou Wang, Chen Tang, Jianyu Wu, Yuchen Ren, Siyuan Yan, Zhonghua Wang, Zhongxing Xu, Shiyan Su, Shangquan Sun, Runkai Zhao, Zhisheng Zhang, Yu Liu, Fudi Wang, Yuanfeng Ji, Yanzhou Su, Hongming Shan, Chun-Mei Feng, Jiahao Xu, Jiangtao Yan, Wenhao Tang, Diping Song, Lihao Liu, Yanyan Huang, Lequan Yu, Bin Fu, Shujun Wang, Xiaomeng Li, Xiaowei Hu, Yun Gu, Ben Fei, Zhongying Deng, Benyou Wang, Yuewen Cao, Minjie Shen, Haodong Duan, Jie Xu, Yirong Chen, Fang Yan, Hongxia Hao, Jielan Li, Jiajun Du, Yanbo Wang, Imran Razzak, Chi Zhang, Lijun Wu, Conghui He, Zhaohui Lu, Jinhai Huang, Yihao Liu, Fenghua Ling, Yuqiang Li, Aoran Wang, Qihao Zheng, Nanqing Dong, Tianfan Fu, Dongzhan Zhou, Yan Lu, Wenlong Zhang, Jin Ye, Jianfei Cai, Wanli Ouyang, Yu Qiao, Zongyuan Ge, Shixiang Tang, Junjun He
2025 J jnl
CoRR
Jing-An Sun, Hang Fan, Junchao Gong, Ben Fei, Kun Chen, Fenghua Ling, Wenlong Zhang, Wanghan Xu, Li Yan, Pierre Gentine, Lei Bai
2025 J jnl
CoRR
Junchao Gong, Jingyi Xu, Ben Fei, Fenghua Ling, Wenlong Zhang, Kun Chen, Wanghan Xu, Weidong Yang, Xiaokang Yang, Lei Bai
2025 J jnl
CoRR
Peilin Feng, Zhutao Lv, Junyan Ye, Xiaolei Wang, Xinjie Huo, Jinhua Yu, Wanghan Xu, Wenlong Zhang, Lei Bai, Conghui He, Weijia Li
2025 J jnl
CoRR
Zijie Guo, Jiong Wang, Xiaoyu Yue, Wangxu Wei, Zhe Jiang, Wanghan Xu, Ben Fei, Wenlong Zhang, Xinyu Gu, Lijing Cheng, Jing-Jia Luo, Chao Li, Yaqiang Wang, Tao Chen, Wanli Ouyang, Fenghua Ling, Lei Bai
2025 J jnl
CoRR
Wanghan Xu, Xiangyu Zhao, Yuhao Zhou, Xiaoyu Yue, Ben Fei, Fenghua Ling, Wenlong Zhang, Lei Bai
2025 J jnl
CoRR
Xiangru Tang, Wanghan Xu, Yujie Wang, Zijie Guo, Daniel Shao, Jiapeng Chen, Cixuan Zhang, Ziyi Wang, Lixin Zhang, Guancheng Wan, Wenlong Zhang, Lei Bai, Zhenfei Yin, Philip Torr, Hanrui Wang, Di Jin
2025 J jnl
CoRR
Wanghan Xu, Xiaoyu Yue, Zidong Wang, Yao Teng, Wenlong Zhang, Xihui Liu, Luping Zhou, Wanli Ouyang, Lei Bai
2025 J jnl
CoRR
Tao Han, Wanghan Xu, Junchao Gong, Xiaoyu Yue, Song Guo, Luping Zhou, Lei Bai
2025 J jnl
CoRR
Xiangyu Zhao, Wanghan Xu, Bo Liu, Yuhao Zhou, Fenghua Ling, Ben Fei, Xiaoyu Yue, Lei Bai, Wenlong Zhang, Xiao-Ming Wu
2025 J jnl
CoRR
Wanghan Xu, Wenlong Zhang, Fenghua Ling, Ben Fei, Yusong Hu, Fangxuan Ren, Jintai Lin, Wanli Ouyang, Lei Bai
2025 J jnl
CoRR
Zhiwang Zhou, Yuandong Pu, Xuming He, Yidi Liu, Yixin Chen, Junchao Gong, Xiang Zhuang, Wanghan Xu, Qinglong Cao, Shixiang Tang, Yihao Liu, Wenlong Zhang, Lei Bai
2024 J jnl
CoRR
Tao Han, Zhenghao Chen, Song Guo, Wanghan Xu, Lei Bai
2024 A* conf
ICML
Junchao Gong, Lei Bai, Peng Ye, Wanghan Xu, Na Liu, Jianhua Dai, Xiaokang Yang, Wanli Ouyang
2024 J jnl
CoRR
Junchao Gong, Lei Bai, Peng Ye, Wanghan Xu, Na Liu, Jianhua Dai, Xiaokang Yang, Wanli Ouyang
2024 J jnl
CoRR
Wanghan Xu, Kang Chen, Tao Han, Hao Chen, Wanli Ouyang, Lei Bai
2024 A* conf
NeurIPS
Wanghan Xu, Fenghua Ling, Wenlong Zhang, Tao Han, Hao Chen, Wanli Ouyang, Lei Bai
2024 J jnl
CoRR
Wanghan Xu, Fenghua Ling, Wenlong Zhang, Tao Han, Hao Chen, Wanli Ouyang, Lei Bai
2024 J jnl
CoRR
Wanghan Xu, Bin Shi, Ao liu, Jiqiang Zhang, Bo Dong
2024 J jnl
CoRR
Wanghan Xu
2024 J jnl
CoRR
Tao Han, Song Guo, Zhenghao Chen, Wanghan Xu, Lei Bai
redb/extractors/macho_extractors/macho_universal.py
← Index redb/extractors/macho_extractors/macho_universal.py python
import hashlib
import inspect
import json
from datetime import datetime, timezone
from typing import Any, List

from redb.extractors.enum import Tag
from redb.extractors.macho_extractor import MachOExtractor
from redb.models.dataclasses import MachOUniversal


class MachOUniversalExtractor(MachOExtractor):

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        macho=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious,
            macho,
        )
        self.elastic_index = self.index_prefix + "-macho_universal"
        self.log.debug(inspect.currentframe().f_code.co_name)

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

    def _extract_universal_info(self):
        """Extract Universal/FAT binary architecture information using new API."""
        self.log.debug(inspect.currentframe().f_code.co_name)

        if not self.macho:
            return None

        try:
            # Parse at Universal level first (new API requirement)
            self.macho.parse()

            # Get architectures using new API
            architectures = self.macho.get_architectures()
            if not architectures:
                return None

            # Check if this is a FAT binary
            is_fat = len(architectures) > 1

            architecture_info = []

            # Extract info for each architecture
            for arch_name in architectures:
                try:
                    # Get general info for this architecture
                    general_info = self.macho.get_general_info(arch=arch_name)

                    # Get header info for this architecture
                    header_info = self.macho.get_macho_header(arch=arch_name)

                    # Get architecture-specific MachO instance for detailed analysis
                    arch_macho = self.macho.get_macho_for_arch(arch_name)

                    # Calculate architecture slice hash (if we can access the raw data)
                    arch_sha256 = None
                    arch_md5 = None
                    arch_sha1 = None

                    # For FAT binaries, try to get slice-specific info
                    if is_fat and arch_macho:
                        try:
                            # This would require access to the slice data
                            # For now, we'll use the general file info
                            arch_sha256 = general_info.get('SHA256', '') if general_info else ''
                            arch_md5 = general_info.get('MD5', '') if general_info else ''
                            arch_sha1 = general_info.get('SHA1', '') if general_info else ''
                        except Exception as e:
                            self.log.debug(f"Could not extract slice hash for {arch_name}: {e}")

                    architecture_info.append({
                        'architecture': arch_name,
                        'arch_sha256': arch_sha256,
                        'arch_md5': arch_md5,
                        'arch_sha1': arch_sha1,
                        'cputype': header_info.get('cputype') if header_info else None,
                        'cpusubtype': header_info.get('cpusubtype') if header_info else None,
                        'filetype': header_info.get('filetype') if header_info else None
                    })

                except Exception as e:
                    self.log.warning(f"Error extracting info for architecture {arch_name}: {e}")
                    continue

            # Create Universal dataclass
            macho_universal = MachOUniversal(
                is_fat=is_fat,
                architecture_count=len(architectures),
                architectures=architectures,
                architecture_info=architecture_info,
                fat_hash=self.sha256,
                fat_md5=self.md5,
                fat_sha1=self.sha1
            )

            return macho_universal

        except Exception as e:
            self.log.error(f"Error extracting MachO Universal info: {e}")
            return None

    def _extract_fat_architecture_mappings(self):
        """Extract detailed FAT binary architecture mappings for database relationships."""
        self.log.debug(inspect.currentframe().f_code.co_name)

        if not self.macho:
            return []

        try:
            # Parse at Universal level first
            self.macho.parse()

            # Get architectures using new API
            architectures = self.macho.get_architectures()
            if not architectures or len(architectures) <= 1:
                return []  # Not a FAT binary

            mappings = []
            current_time = datetime.now(timezone.utc)

            # For each architecture, create a mapping record
            for arch_name in architectures:
                try:
                    # Get general info
                    general_info = self.macho.get_general_info()

                    # Create mapping record for FAT binary architecture table
                    mapping = {
                        'fat_hash': self.sha256,  # SHA256 of the FAT binary
                        'architecture': arch_name,
                        'arch_sha256': general_info.get('SHA256', '') if general_info else '',  # Will need proper slice extraction
                        'arch_md5': general_info.get('MD5', '') if general_info else '',
                        'arch_sha1': general_info.get('SHA1', '') if general_info else '',
                        'arch_filename': f"{general_info.get('Filename', '')}.{arch_name}" if general_info else '',
                        'analysis_date': current_time
                    }
                    mappings.append(mapping)

                except Exception as e:
                    self.log.warning(f"Error creating mapping for architecture {arch_name}: {e}")
                    continue

            return mappings

        except Exception as e:
            self.log.error(f"Error extracting FAT architecture mappings: {e}")
            return []

    def extract(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        try:
            universal_info = self._extract_universal_info()
            return universal_info
        except Exception as e:
            self.log.error(f"Error extracting MachO Universal info: {e}")
            return None

    def extract_fat_binary_basic_properties_data(self):
        """Extract data needed for creating multiple BasicProperties records for FAT binaries.

        Returns:
            Tuple: (is_fat, fat_sha256, architectures_info) where:
                - is_fat: bool indicating if this is a FAT binary
                - fat_sha256: SHA256 of the FAT wrapper
                - architectures_info: dict with arch names and their hashes
        """
        self.log.debug(inspect.currentframe().f_code.co_name)

        if not self.macho:
            return False, None, {}

        try:
            # Parse at Universal level first
            self.macho.parse()

            # Get architectures using new API
            architectures = self.macho.get_architectures()
            if not architectures or len(architectures) <= 1:
                return False, None, {}  # Not a FAT binary

            # This is a FAT binary
            architectures_info = {}

            for arch_name in architectures:
                try:
                    # Get general info for this architecture
                    general_info = self.macho.get_general_info(arch=arch_name)

                    if general_info:
                        architectures_info[arch_name] = {
                            'sha256': general_info.get('SHA256', ''),
                            'md5': general_info.get('MD5', ''),
                            'sha1': general_info.get('SHA1', ''),
                            'filename': general_info.get('Filename', ''),
                            'filesize': general_info.get('Filesize', 0)
                        }
                except Exception as e:
                    self.log.warning(f"Error extracting info for architecture {arch_name}: {e}")
                    continue

            return True, self.sha256, architectures_info

        except Exception as e:
            self.log.error(f"Error extracting FAT binary data: {e}")
            return False, None, {}

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ElasticsearchExporter":
            return self.extract()
        elif exporter_type == "ClickHouseExporter":
            universal_info = self.extract()
            if universal_info is None:
                return None

            data = []
            current_time = datetime.now(timezone.utc)

            # Get architecture info for the binary
            try:
                if universal_info.is_fat:
                    # For FAT binaries, architecture fields should be NULL since it contains multiple
                    architecture_raw = None
                    architecture_str = None
                else:
                    # For single-arch binaries, get the actual architecture info
                    header_info = self.macho.get_macho_header()
                    architecture_raw = header_info.get('cputype', 0) if header_info else 0
                    architecture_str = universal_info.architectures[0] if universal_info.architectures else None
            except Exception as e:
                self.log.warning(f"Could not get architecture info for binary: {e}")
                architecture_raw = None
                architecture_str = None

            # Main Universal binary record
            data.append([
                self.sha256,                              # sha256
                self.md5,                                 # md5
                self.sha1,                                # sha1
                None,                                     # parent_sha256 (always None for main FAT binary)
                architecture_raw,                         # architecture (raw CPU type)
                architecture_str,                         # architecture_str (human-readable)
                universal_info.is_fat,                    # is_fat
                universal_info.architecture_count,       # architecture_count
                universal_info.architectures,            # architectures (array)
                json.dumps(universal_info.architecture_info[0] if len(universal_info.architecture_info) == 1 else {"architectures": universal_info.architecture_info}) if universal_info.architecture_info else None,  # architecture_info (JSON)
                current_time,                             # analysis_date
            ])

            column_names = [
                'sha256', 'md5', 'sha1', 'parent_sha256', 'architecture', 'architecture_str',
                'is_fat', 'architecture_count', 'architectures', 'architecture_info',
                'analysis_date'
            ]

            column_type_names = [
                'FixedString(64)', 'FixedString(32)', 'FixedString(40)',
                'Nullable(FixedString(64))', 'Nullable(UInt32)', 'LowCardinality(Nullable(String))',
                'UInt8', 'UInt32', 'Array(LowCardinality(String))', 'JSON',
                'DateTime64(3, \'UTC\')'
            ]

            return (data, column_names, column_type_names)

        return None

    def prepare_fat_architecture_export_data(self) -> Any:
        """Prepare export data for the FAT binary architecture mapping table."""
        mappings = self._extract_fat_architecture_mappings()
        if not mappings:
            return None

        data = []
        for mapping in mappings:
            data.append([
                mapping['fat_hash'],
                mapping['architecture'],
                mapping['arch_sha256'],
                mapping['arch_md5'],
                mapping['arch_sha1'],
                mapping['arch_filename'],
                mapping['analysis_date'],
            ])

        column_names = [
            'fat_hash', 'architecture', 'arch_sha256', 'arch_md5', 'arch_sha1',
            'arch_filename', 'analysis_date'
        ]

        column_type_names = [
            'FixedString(64)', 'LowCardinality(String)', 'FixedString(64)',
            'FixedString(32)', 'FixedString(40)', 'String',
            'DateTime64(3, \'UTC\')'
        ]

        return (data, column_names, column_type_names)

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

    # def get_fat_architecture_table(self) -> str:
    #     """Return table name for FAT binary architecture mappings."""
    #     return "redb_fat_binary_architectures"