Hang Fan

26 papers A* 1B 1C 1Journal 23
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Hang Fan, Juan Nathaniel, Yi Xiao, Ce Bian, Fenghua Ling, Ben Fei, Lei Bai, Pierre Gentine
2026 J jnl
Expert Syst. Appl.
Hang Fan, Yunze Chai, Chenxi Liu, Weican Liu, Zuhan Zhang, Wencai Run, Dunnan Liu
2026 J jnl
Adv. Eng. Informatics
Hang Fan, Weican Liu, Zuhan Zhang, Ying Lu, Wencai Run, Dunnan Liu
2026 J jnl
Inf. Fusion
Hang Fan, Mingxuan Li, Zuhan Zhang, Long Cheng, Yujian Ye, Weican Liu, Dunnan Liu
2025 J jnl
Eng. Appl. Artif. Intell.
Xiang Pan, Hang Fan, Jianlan Wang, Yan Fu, Wei Chu, Weipeng Tai, Jing Gu, Jianming Ni
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
Hang Fan, Yunze Chai, Chenxi Liu, Weican Liu, Zuhan Zhang, Wencai Run, Dunnan Liu
2025 J jnl
CoRR
Hang Fan, Weican Liu, Zuhan Zhang, Ying Lu, Wencai Run, Dunnan Liu
2025 J jnl
CoRR
Hang Fan, Yi Xiao, Yongquan Qu, Fenghua Ling, Ben Fei, Lei Bai, Pierre Gentine
2025 J jnl
CoRR
Xiaoqing Lian, Jie Zhu, Tianxu Lv, Shiyun Nie, Hang Fan, Guosheng Wu, Yunjun Ge, Lihua Li, Xiangxiang Zeng, Xiang Pan
2025 J jnl
CoRR
Hang Fan, Mingxuan Li, Zuhan Zhang, Long Cheng, Yujian Ye, Dunnan Liu
2025 J jnl
Expert Syst. Appl.
Hang Fan, Xiaoyu Fan, Wei Wei, Tianyi Hao, Kun Chen, Guosai Wang, Wei Xu
2025 A* conf
CVPR
Siwei Tu, Ben Fei, Weidong Yang, Fenghua Ling, Hao Chen, Zili Liu, Kun Chen, Hang Fan, Wanli Ouyang, Lei Bai
2025 J jnl
CoRR
Siwei Tu, Ben Fei, Weidong Yang, Fenghua Ling, Hao Chen, Zili Liu, Kun Chen, Hang Fan, Wanli Ouyang, Lei Bai
2025 J jnl
CoRR
Hang Fan, Yu Shi, Zongliang Fu, Shuo Chen, Wei Wei, Wei Xu, Jian Li
2024 J jnl
Remote. Sens.
Yu Qin, Fengxian Wang, Yubao Liu, Hang Fan, Yongbo Zhou, Jing Duan
2023 J jnl
Symmetry
Hang Fan, Fei Gao, Wenhao Li, Kun Zhang
2023 J jnl
CoRR
Zhi Li, Hang Fan, Shuyan Dong
2023 J jnl
CoRR
Hang Fan, Xiaoyu Fan, Tianyi Hao, Wei Wei, Kun Chen, Guosai Wang, Xiaofeng Jia, Yidong Li, Wei Xu
2022 J jnl
Genom. Proteom. Bioinform.
Xiaoai Zhang, Qingzhi Zhai, Jinfeng Wang, Xiuling Ma, Bo Xing, Hang Fan, Zhiying Gao, Fangqing Zhao, Wei Liu
2020 J jnl
Genom. Proteom. Bioinform.
Wang-Lin Liu, Mingyue Cheng, Jinman Li, Peng Zhang, Hang Fan, Qinghe Hu, Maozhen Han, Longxiang Su, Huaiwu He, Yigang Tong, Kang Ning, Yun Long
2019 J jnl
Comput. Hum. Behav.
Minghua Song, Zhuan Zhu, Shen Liu, Hang Fan, Tingting Zhu, Lin Zhang
2019 J jnl
CoRR
Kunjin Chen, Yu Zhang, Qin Wang, Jun Hu, Hang Fan, Jinliang He
2015 C conf
VCIP
Hang Fan, Yangui Zhou, Haowen Liang, Jiahui Wang, Peter Krebs, Daikun Lin, Jianbang Su, Kunyang Li, Haiyu Chen, Xiaolu Wang, Jianying Zhou
2014 B conf
IJCNN
Tong Zhao, Junjie Hu, Pinjia He, Hang Fan, Michael R. Lyu, Irwin King
2013 J jnl
Microelectron. Reliab.
Lingli Jiang, Hang Fan, Ming Qiao, Bo Zhang, Zhaoji Li
redb/extractors/js_extractors/js_xray.py
← Index redb/extractors/js_extractors/js_xray.py python
"""Subprocess wrapper for the bundled js-x-ray Node bridge.

Mirrors `js_deobfuscator.py`: shell out to a Node script with a per-sample
timeout, kill the process group on hang, demote `FileNotFoundError` to debug
(missing tool is routine — the host either has Node + the bundled package
installed or it doesn't), and return a structured result on success.

The bridge lives at `redb/extractors/js_extractors/scripts/js-xray-runner.js`.
Operators install the JS dependency once with `npm install` in that directory
(or override the path with `JS_XRAY_RUNNER_PATH`).

Configuration (env vars):
    JS_XRAY_RUNNER_PATH   Path to the Node bridge script (default: bundled).
    JS_XRAY_TIMEOUT       Seconds before the subprocess is killed. Default: 30.

`run(source, log)` returns `XRayResult(obfuscator, warnings)` on a successful
analysis, or `XRayResult(None, [])` for any non-success path (binary missing,
timeout, parse failure, etc.). The two unsuccessful states are
indistinguishable to the caller on purpose — they all collapse to "no
js-x-ray verdict, fall back to heuristic".
"""

from __future__ import annotations

import json
import os
import signal
import subprocess
import tempfile
from dataclasses import dataclass, field
from typing import List, Optional

# Bundled bridge: redb/extractors/js_extractors/scripts/js-xray-runner.js
_DEFAULT_RUNNER = os.path.join(
    os.path.dirname(__file__), "scripts", "js-xray-runner.js"
)
_DEFAULT_NODE = "node"
_DEFAULT_TIMEOUT_SECS = 30


@dataclass
class XRayResult:
    """Parsed js-x-ray output. `obfuscator` is the recognised family name
    (e.g. "jsfuck", "obfuscator.io") or None when js-x-ray did not flag the
    code. `warnings` carries every {kind, value} pair the analyser produced;
    the heuristic uses it as a corroborating signal. `avg_identifier_length`
    is js-x-ray's own AST-derived figure — used as a fallback for the
    heuristic's `avg_identifier_length<2` strong signal when pyjsparser
    can't parse the source (anything ES2015+ trips it)."""

    obfuscator: Optional[str] = None
    warnings: List[dict] = field(default_factory=list)
    avg_identifier_length: Optional[float] = None

    @property
    def flagged(self) -> bool:
        return self.obfuscator is not None


def _empty() -> XRayResult:
    return XRayResult(obfuscator=None, warnings=[])


def run(source: str, log) -> XRayResult:
    if not source:
        return _empty()

    runner = os.getenv("JS_XRAY_RUNNER_PATH", _DEFAULT_RUNNER)
    node_bin = os.getenv("JS_XRAY_NODE_BIN", _DEFAULT_NODE)
    timeout = int(os.getenv("JS_XRAY_TIMEOUT", str(_DEFAULT_TIMEOUT_SECS)))

    if not os.path.exists(runner):
        log.debug(f"js-x-ray runner not found at {runner}")
        return _empty()

    # Skip the subprocess entirely when the JS dependency isn't installed.
    # Without this, every call to a host that has `node` but never ran
    # `npm install` next to the runner would still fork node, get a require
    # error, and exit nonzero — wasted ~50–200ms per JS sample (and per test).
    runner_dir = os.path.dirname(runner)
    if not os.path.isdir(os.path.join(runner_dir, "node_modules", "@nodesecure", "js-x-ray")):
        log.debug(f"@nodesecure/js-x-ray not installed in {runner_dir}")
        return _empty()

    tmp_path = None
    try:
        with tempfile.NamedTemporaryFile(
            suffix=".js", mode="w", delete=False, encoding="utf-8"
        ) as tmp:
            tmp.write(source)
            tmp_path = tmp.name

        try:
            process = subprocess.Popen(
                [node_bin, runner, tmp_path],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                preexec_fn=os.setsid,
            )
            try:
                stdout, stderr = process.communicate(timeout=timeout)
            except subprocess.TimeoutExpired:
                # Kill the whole process group so any node helpers die too.
                try:
                    os.killpg(os.getpgid(process.pid), signal.SIGTERM)
                    process.wait(timeout=5)
                except Exception:
                    try:
                        os.killpg(os.getpgid(process.pid), signal.SIGKILL)
                    except Exception:
                        pass
                log.warning(f"js-x-ray timed out after {timeout}s")
                return _empty()

            if process.returncode != 0:
                err = stderr.decode("utf-8", errors="replace").strip()
                log.debug(f"js-x-ray exited {process.returncode}: {err}")
                return _empty()

            text = stdout.decode("utf-8", errors="replace").strip()
            if not text:
                return _empty()

            try:
                payload = json.loads(text)
            except json.JSONDecodeError as e:
                log.warning(f"js-x-ray emitted non-JSON output: {e}")
                return _empty()

            obfuscator = payload.get("obfuscator")
            warnings = payload.get("warnings") or []
            if not isinstance(warnings, list):
                warnings = []

            ids_avg = payload.get("idsLengthAvg")
            if not isinstance(ids_avg, (int, float)):
                ids_avg = None

            return XRayResult(
                obfuscator=obfuscator,
                warnings=warnings,
                avg_identifier_length=ids_avg,
            )
        finally:
            if tmp_path:
                try:
                    os.unlink(tmp_path)
                except Exception:
                    pass
    except FileNotFoundError:
        log.debug(f"node binary not found at {node_bin}")
        return _empty()
    except Exception as e:
        log.error(f"js-x-ray subprocess error: {e}")
        return _empty()