Hanli Zhao

59 papers A* 1A 1B 1C 1Journal 43Unranked 12
YearRankTypeTitle / Venue / Authors
2025 conf
CVM (1)
Hanli Zhao, Binhao Wang, Wanglong Lu, Juncong Lin
2025 J jnl
Neurocomputing
Wanglong Lu, Hanli Zhao, Xianta Jiang, Xiaogang Jin, Yong-Liang Yang, Kaijie Shi
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Wanglong Lu, Jikai Wang, Xiaogang Jin, Xianta Jiang, Hanli Zhao
2025 J jnl
Comput. Vis. Media
Wanglong Lu, Xianta Jiang, Xiaogang Jin, Yong-Liang Yang, Minglun Gong, Kaijie Shi, Tao Wang, Hanli Zhao
2025 J jnl
Pattern Recognit.
Hanli Zhao, Yu Wang, Wanglong Lu, Zili Yi, Jun Liu, Minglun Gong
2025 J jnl
CoRR
Wanglong Lu, Lingming Su, Jingjing Zheng, Vinícius Veloso de Melo, Farzaneh Shoeleh, John Hawkin, Terrence S. Tricco, Hanli Zhao, Xianta Jiang
2025 J jnl
CoRR
Kaijie Shi, Wanglong Lu, Hanli Zhao, Vinicius Prado da Fonseca, Ting Zou, Xianta Jiang
2025 J jnl
Pattern Recognit.
Wanglong Lu, Jikai Wang, Tao Wang, Kaihao Zhang, Xianta Jiang, Hanli Zhao
2024 J jnl
CoRR
Wanglong Lu, Jikai Wang, Xiaogang Jin, Xianta Jiang, Hanli Zhao
2024 J jnl
J. Electronic Imaging
Jikai Wang, Wanglong Lu, Yu Wang, Kaijie Shi, Xianta Jiang, Hanli Zhao
2024 J jnl
CoRR
Wanglong Lu, Jikai Wang, Tao Wang, Kaihao Zhang, Xianta Jiang, Hanli Zhao
2024 J jnl
Displays
Jie Xing, Ali Asghar Heidari, Huiling Chen, Hanli Zhao
2023 B conf
ETRA
Yu Wang, Wanglong Lu, Hanli Zhao, Xianta Jiang, Bin Zheng, M. Stella Atkins
2023 J jnl
Biomed. Signal Process. Control.
Jie Xing, Xinsen Zhou, Hanli Zhao, Huiling Chen, Ali Asghar Heidari
2023 J jnl
CoRR
Wanglong Lu, Xianta Jiang, Xiaogang Jin, Yong-Liang Yang, Minglun Gong, Tao Wang, Kaijie Shi, Hanli Zhao
2023 J jnl
J. Comput. Des. Eng.
Jie Xing, Qinqin Zhao, Huiling Chen, Yili Zhang, Feng Zhou, Hanli Zhao
2022 J jnl
CoRR
Wanglong Lu, Hanli Zhao, Xianta Jiang, Xiaogang Jin, Min Wang, Jiankai Lyu, Kaijie Shi
2022 J jnl
Displays
Min Wang, Wanglong Lu, Jiankai Lyu, Kaijie Shi, Hanli Zhao
2022 J jnl
J. Comput. Sci. Technol.
Hanli Zhao, Kaijie Shi, Xiaogang Jin, Ming-Liang Xu, Hui Huang, Wanglong Lu, Ying Liu
2021 J jnl
Neurocomputing
Wanglong Lu, Hanli Zhao, Qi He, Hui Huang, Xiaogang Jin
2021 A* conf
ACM Multimedia
Ruoxi Deng, Shengjun Liu, Jinxin Wang, Huibing Wang, Hanli Zhao, Xiaoqin Zhang
2020 J jnl
Int. J. Imaging Syst. Technol.
Hanli Zhao, Xiaqing Qiu, Wanglong Lu, Hui Huang, Xiaogang Jin
2020 J jnl
Vis. Comput.
Xujie Li, Hui Huang, Hanli Zhao, Yandan Wang, Mingxiao Hu
2019 conf
IEEE BigData
Qianru Wang, Li Zhao, Guiying Tang, Hanli Zhao, Xiaoqin Zhang
2018 J jnl
Vis. Comput.
Hanli Zhao, Lei Jiang, Xiaogang Jin, Hui Du, Xujie Li
2018 J jnl
Comput. Graph.
Hanli Zhao, Haining Zhang, Xiaogang Jin
2018 J jnl
Neurocomputing
Hanli Zhao, Heyang Guo, Xiaogang Jin, Jianbing Shen, Xiaoyang Mao, Junru Liu
2017 J jnl
Multim. Tools Appl.
Yue Yang, Hanli Zhao, Lihua You, Renlong Tu, Xueyi Wu, Xiaogang Jin
2016 J jnl
Multim. Tools Appl.
Xujie Li, Hanli Zhao, Hui Huang, Zhongyi Hu, Lei Xiao
2016 conf
Edutainment
Hanli Zhao, Dandan Gao, Ming Wang, Zhigeng Pan
2016 J jnl
Comput. Graph.
Hanli Zhao, Dandan Gao, Ming Wang, Zhigeng Pan
2016 J jnl
J. Electronic Imaging
Xujie Li, Hanli Zhao, Hui Huang, Lei Xiao, Zhongyi Hu, Jingkai Shao
2015 J jnl
Comput. Vis. Media
Xujie Li, Hanli Zhao, Gui-Zhi Nie, Hui Huang
2015 J jnl
Multim. Tools Appl.
Hui Huang, Xujie Li, Hanli Zhao, Gui-Zhi Nie, Zhongyi Hu, Lei Xiao
2015 J jnl
IEEE Trans. Vis. Comput. Graph.
Yandan Zhao, Xiaogang Jin, Yingqing Xu, Hanli Zhao, Meng Ai, Kun Zhou
2015 J jnl
J. Comput. Sci. Technol.
Hanli Zhao, Gui-Zhi Nie, Xujie Li, Xiaogang Jin, Zhigeng Pan
2013 J jnl
Multim. Tools Appl.
Hanli Zhao, Xiaogang Jin, Xiaoyang Mao
2013 J jnl
Multim. Tools Appl.
Shufang Lu, Xiaogang Jin, Hanli Zhao, Yandan Zhao
2012 J jnl
Vis. Comput.
Xiaoqiang Zhu, Xiaogang Jin, Shengjun Liu, Hanli Zhao
2012 J jnl
IEEE Computer Graphics and Applications
Shufang Lu, Aubrey Jaffer, Xiaogang Jin, Hanli Zhao, Xiaoyang Mao
2011 J jnl
Vis. Comput.
Hanli Zhao, Charlie C. L. Wang, Yong Chen, Xiaogang Jin
2011 conf
CAD/Graphics
Xujie Li, Hanli Zhao, Xiaogang Jin, Xiaochun Qin
2011 J jnl
Trans. Edutainment
Qingfeng Li, Hanli Zhao
2010 J jnl
Pattern Recognit.
Jianbing Shen, Hanqiu Sun, Jiaya Jia, Hanli Zhao, Xiaogang Jin, Shiaofen Fang
2009 conf
CAD/Graphics
Shengjun Liu, Charlie C. L. Wang, Kin-Chuen Hui, Xiaogang Jin, Hanli Zhao
2009 conf
CAD/Graphics
Jianbing Shen, Hanqiu Sun, Hanli Zhao, Xiaogang Jin
2009 conf
Edutainment
Hanli Zhao, Xiaogang Jin, Jianbing Shen, Li Shen, Ruifang Pan
2009 J jnl
Int. J. Comput. Games Technol.
Hanli Zhao, Xiaogang Jin, Jianbing Shen, Shufang Lu
2009 J jnl
Signal Process.
Jianbing Shen, Shiaofen Fang, Hanli Zhao, Xiaogang Jin, Hanqiu Sun
2009 J jnl
Comput. Animat. Virtual Worlds
Hanli Zhao, Ran Fan, Charlie C. L. Wang, Xiaogang Jin, Yuwei Meng
2009 A conf
ICME
Jianbing Shen, Hanqiu Sun, Hanli Zhao, Xiaogang Jin
2009 conf
CAD/Graphics
Hanli Zhao, Xiaogang Jin, Jianbing Shen, Feifei Wei
2009 J jnl
Vis. Comput.
Hanli Zhao, Xiaoyang Mao, Xiaogang Jin, Jianbing Shen, Feifei Wei, Jieqing Feng
2008 C conf
CW
Hanli Zhao, Xiaogang Jin, Jianbing Shen
2008 J jnl
Vis. Comput.
Hanli Zhao, Xiaogang Jin, Jianbing Shen, Xiaoyang Mao, Jieqing Feng
2007 conf
Symposium on Solid and Physical Modeling
Shengjun Liu, Charlie C. L. Wang, Kin-Chuen Hui, Xiaogang Jin, Hanli Zhao
2007 conf
Edutainment
Jianbing Shen, Xiaogang Jin, Hanli Zhao
2006 conf
Edutainment
Jianbing Shen, Xiaogang Jin, Chuan Zhou, Hanli Zhao
2006 conf
ICAT
Hanli Zhao, Xiaogang Jin, Jianbing Shen
redb/extractors/decompiler/bninja/analysis/cfg_features.py
← Index redb/extractors/decompiler/bninja/analysis/cfg_features.py python
import struct
from collections import deque
from typing import Optional

import blake3
import mmh3


# ---------------------------------------------------------------------------
# Task 1.1: Core Graph Utilities
# ---------------------------------------------------------------------------

def bfs_order(successors: list[list[int]], n: int) -> list[int]:
    """
    BFS traversal from node 0 (entry block), returns node indices in visit order.
    Unreachable nodes appended at the end.
    """
    if n == 0:
        return []

    visited = set()
    order = []
    queue = deque([0])
    visited.add(0)

    while queue:
        idx = queue.popleft()
        order.append(idx)
        for target in successors[idx]:
            if target not in visited:
                visited.add(target)
                queue.append(target)

    # Append unreachable blocks (dead code)
    for i in range(n):
        if i not in visited:
            order.append(i)

    return order


def bfs_max_depth(successors: list[list[int]], n: int) -> int:
    """
    Maximum BFS depth from entry block (node 0).
    Replaces the per-block depth column with a single scalar.
    """
    if n == 0:
        return 0

    depth = {0: 0}
    max_d = 0
    queue = deque([0])

    while queue:
        node = queue.popleft()
        for s in successors[node]:
            if s not in depth:
                depth[s] = depth[node] + 1
                if depth[s] > max_d:
                    max_d = depth[s]
                queue.append(s)

    return max_d


# ---------------------------------------------------------------------------
# Task 1.2: Back-Edge Detection (Iterative DFS)
# ---------------------------------------------------------------------------

def count_back_edges(successors: list[list[int]], n: int) -> int:
    """
    Count natural loops via iterative DFS back-edge detection.
    A back edge is an edge to a GRAY (in-stack) node.

    Iterative to avoid stack overflow on functions with 1000+ blocks
    (common in obfuscated malware, VM dispatchers, unrolled loops).
    """
    if n == 0:
        return 0

    WHITE, GRAY, BLACK = 0, 1, 2
    color = [WHITE] * n
    back_edges = 0

    stack = [(0, iter(successors[0]))]
    color[0] = GRAY

    while stack:
        u, children = stack[-1]
        try:
            v = next(children)
            if color[v] == GRAY:
                back_edges += 1
            elif color[v] == WHITE:
                color[v] = GRAY
                stack.append((v, iter(successors[v])))
        except StopIteration:
            color[u] = BLACK
            stack.pop()

    return back_edges


# ---------------------------------------------------------------------------
# Task 1.3: Topology Hash
# ---------------------------------------------------------------------------

def compute_topology_hash(
    successors: list[list[int]],
    bfs: list[int],
    n: int,
) -> bytes:
    """
    BLAKE3 hash of BFS-ordered canonical adjacency.
    Pure graph shape — ignores all block content.
    Two functions with identical control flow structure produce identical hashes.

    Returns 16 bytes (128-bit).
    """
    if n == 0:
        return b'\x00' * 16

    # Remap: original index -> BFS position
    remap = {original: position for position, original in enumerate(bfs)}

    canonical = bytearray()
    for position in range(n):
        original_idx = bfs[position]
        remapped_succs = sorted(
            remap[s] for s in successors[original_idx] if s in remap
        )
        # Pack: node_index (2 bytes) + num_successors (1 byte) + successor indices (2 bytes each)
        canonical.extend(struct.pack('<HB', position, len(remapped_succs)))
        for s in remapped_succs:
            canonical.extend(struct.pack('<H', s))

    return blake3.blake3(bytes(canonical)).digest(length=16)


# ---------------------------------------------------------------------------
# Task 1.4: MD-Index (Top-Down and Bottom-Up)
# ---------------------------------------------------------------------------

def compute_md_index_topdown(
    successors: list[list[int]],
    predecessors: list[list[int]],
    bfs: list[int],
) -> int:
    """
    BinDiff-style top-down MD-index.
    Hash of (in_degree, out_degree) sequence in BFS order from entry.
    Returns UInt64.
    """
    if not bfs:
        return 0

    degree_bytes = bytearray()
    for idx in bfs:
        in_deg = min(len(predecessors[idx]), 255)
        out_deg = min(len(successors[idx]), 255)
        degree_bytes.extend(struct.pack('<BB', in_deg, out_deg))

    h = blake3.blake3(bytes(degree_bytes)).digest(length=8)
    return struct.unpack('<Q', h)[0]


def compute_md_index_bottomup(
    successors: list[list[int]],
    predecessors: list[list[int]],
    n: int,
) -> int:
    """
    Bottom-up MD-index: BFS from exit blocks (no successors),
    traversing edges in reverse.
    Returns UInt64.
    """
    if n == 0:
        return 0

    exits = [i for i in range(n) if len(successors[i]) == 0]
    if not exits:
        exits = [n - 1]  # Fallback: use last block

    visited = set(exits)
    order = []
    queue = deque(exits)

    while queue:
        idx = queue.popleft()
        order.append(idx)
        for pred in predecessors[idx]:
            if pred not in visited:
                visited.add(pred)
                queue.append(pred)

    # Append unreachable blocks
    for i in range(n):
        if i not in visited:
            order.append(i)

    degree_bytes = bytearray()
    for idx in order:
        in_deg = min(len(predecessors[idx]), 255)
        out_deg = min(len(successors[idx]), 255)
        degree_bytes.extend(struct.pack('<BB', in_deg, out_deg))

    h = blake3.blake3(bytes(degree_bytes)).digest(length=8)
    return struct.unpack('<Q', h)[0]


# ---------------------------------------------------------------------------
# Task 1.5: Prime Product
# ---------------------------------------------------------------------------

# Small primes assigned to LLIL opcode categories.
# Keys are the integer values of binaryninja.LowLevelILOperation enum members.
# We use integer keys so this module doesn't import binaryninja.
#
# Mapping rationale: same operation class -> same prime.
# Using LLIL (not native asm) makes this architecture-independent.
#
# Populated at import time by cfg.py using the real LowLevelILOperation enum values.
# Unknown ops map to prime 1 (identity element) in compute_prime_product().
LLIL_OP_PRIMES: dict[int, int] = {}


def compute_prime_product(llil_operations: list[int]) -> int:
    """
    Product of small primes assigned to each LLIL opcode.
    Position-independent: block reordering doesn't change the result.
    Mod 2^64 for fixed-size storage.

    Args:
        llil_operations: flat list of LLIL operation enum integer values
                         for all instructions in the function.
    Returns:
        UInt64 prime product, or 0 if no instructions.
    """
    if not llil_operations:
        return 0

    product = 1
    for op in llil_operations:
        prime = LLIL_OP_PRIMES.get(op, 1)
        product = (product * prime) % (2**64)

    return product


# ---------------------------------------------------------------------------
# Task 1.6: ACFG Block Features
# ---------------------------------------------------------------------------

# Instruction category indices for ACFG feature vectors
CAT_ARITHMETIC = 0
CAT_LOGIC = 1
CAT_TRANSFER = 2
CAT_CALL = 3
CAT_COMPARISON = 4
CAT_MEMORY = 5
CAT_OTHER = 6

# Maps LLIL operation integer values to category indices.
# Populated at import time by cfg.py using the real LowLevelILOperation enum.
LLIL_OP_CATEGORIES: dict[int, int] = {}


def build_block_features(
    block_llil_ops: list[list[int]],
    successors: list[list[int]],
    n: int,
) -> list[list[int]]:
    """
    Extract Gemini-style ACFG features per block.

    Args:
        block_llil_ops: per-block list of LLIL operation integer values.
                        block_llil_ops[i] is the list of ops for block i.
                        Empty list if LLIL unavailable for that block.
        successors: index-based adjacency list.
        n: number of blocks.

    Returns:
        List of [instr_count, arithmetic, logic, transfer, call, comparison,
                 memory, successor_count] per block. All values capped at 65535.
    """
    features = []
    for i in range(n):
        cats = [0, 0, 0, 0, 0, 0, 0]
        ops = block_llil_ops[i] if i < len(block_llil_ops) else []
        for op in ops:
            cat = LLIL_OP_CATEGORIES.get(op, CAT_OTHER)
            cats[cat] += 1

        instr_count = len(ops)
        features.append([
            min(instr_count, 65535),
            min(cats[CAT_ARITHMETIC], 65535),
            min(cats[CAT_LOGIC], 65535),
            min(cats[CAT_TRANSFER], 65535),
            min(cats[CAT_CALL], 65535),
            min(cats[CAT_COMPARISON], 65535),
            min(cats[CAT_MEMORY], 65535),
            min(len(successors[i]), 65535),
        ])

    return features


# ---------------------------------------------------------------------------
# Task 1.7: CFG Feature TLSH
# ---------------------------------------------------------------------------

def compute_cfg_feature_tlsh(
    bb_features: list[list[int]],
    bfs: list[int],
) -> Optional[str]:
    """
    TLSH hash of BFS-ordered per-block feature vectors.
    Captures both structure (BFS ordering) and instruction distribution.

    Returns TLSH hex string or None if too few bytes for TLSH (< 50).
    """
    import tlsh as _tlsh

    feature_bytes = bytearray()
    for idx in bfs:
        feats = bb_features[idx]
        feature_bytes.extend(struct.pack(
            '<HBBBBBBB',
            min(feats[0], 65535),
            min(feats[1], 255),
            min(feats[2], 255),
            min(feats[3], 255),
            min(feats[4], 255),
            min(feats[5], 255),
            min(feats[6], 255),
            min(feats[7], 255),
        ))

    if len(feature_bytes) < 50:
        return None

    try:
        h = _tlsh.hash(bytes(feature_bytes))
        return h if h and h != 'TNULL' else None
    except Exception:
        return None


# ---------------------------------------------------------------------------
# Task 1.8: WL-MinHash
# ---------------------------------------------------------------------------

# Pre-computed seeds for MinHash permutations.
NUM_WL_MINHASH_PERMS = 128
_WL_MINHASH_SEEDS = list(range(NUM_WL_MINHASH_PERMS))  # Seeds 0..127


def compute_wl_minhash(
    successors: list[list[int]],
    predecessors: list[list[int]],
    bb_features: list[list[int]],
    n: int,
    iterations: int = 3,
) -> list[int]:
    """
    Weisfeiler-Leman MinHash for fuzzy topology similarity.

    Initial labels: mmh3 hash of per-block ACFG feature tuple (content-aware).
    WL refinement: incorporate sorted neighbor labels at each iteration.
    MinHash: 128-permutation signature over shingle set.

    Returns list of 128 uint8 values, or [255]*128 sentinel for empty functions.
    """
    if n == 0:
        return [255] * NUM_WL_MINHASH_PERMS

    # Initial labels: hash of instruction category tuple per block
    labels = []
    for i in range(n):
        feats = bb_features[i] if i < len(bb_features) else [0] * 8
        # mmh3 with seed=0 for initial labels
        label = mmh3.hash(str(tuple(feats)), 0) & 0xFFFFFFFF
        labels.append(label)

    # Collect shingles: (iteration, label) pairs as strings for mmh3
    shingles: set[str] = set()

    # Iteration 0: individual block labels
    for label in labels:
        shingles.add(f"0:{label}")

    # WL iterations: refine labels by neighborhood aggregation
    for iteration in range(1, iterations + 1):
        new_labels = []
        for i in range(n):
            succ_labels = tuple(sorted(labels[s] for s in successors[i]))
            pred_labels = tuple(sorted(labels[p] for p in predecessors[i]))
            composite = f"{labels[i]}|{succ_labels}|{pred_labels}"
            new_label = mmh3.hash(composite, 0) & 0xFFFFFFFF
            new_labels.append(new_label)
            shingles.add(f"{iteration}:{new_label}")
        labels = new_labels

    if not shingles:
        return [255] * NUM_WL_MINHASH_PERMS

    # Compute MinHash signature using mmh3 with different seeds
    shingle_list = list(shingles)
    signature = []
    for seed in _WL_MINHASH_SEEDS:
        min_val = 0xFFFFFFFF
        for s in shingle_list:
            h = mmh3.hash(s, seed) & 0xFFFFFFFF
            if h < min_val:
                min_val = h
        # Compress to uint8 for storage
        signature.append(min_val & 0xFF)

    return signature


# ---------------------------------------------------------------------------
# Task 1.9: Packed Adjacency
# ---------------------------------------------------------------------------

def pack_adjacency(successors: list[list[int]]) -> list[int]:
    """
    Pack CFG edges as Array(UInt32).
    Each UInt32 = (source_index << 16) | target_index.
    Supports up to 65,535 blocks per function.
    """
    edges = []
    for src, targets in enumerate(successors):
        for tgt in targets:
            if src < 65536 and tgt < 65536:
                edges.append((src << 16) | tgt)
    return edges