Omid Abari

61 papers A* 19A 3B 2Misc 14Journal 16Unranked 7
YearRankTypeTitle / Venue / Authors
2025 J jnl
CoRR
Heyu Guo, Shanmu Wang, Ruichun Ma, Shiqi Jiang, Yasaman Ghasempour, Omid Abari, Baining Guo, Lili Qiu
2025 J jnl
ACM Trans. Sens. Networks
Ju Wang, Liqiong Chang, Shourya Aggarwal, Omid Abari, Srinivasan Keshav
2025 J jnl
CoRR
John Hateley, Sriram Narasimhan, Omid Abari
2024 J jnl
CoRR
Haofan Lu, Christopher Vattheuer, Baharan Mirzasoleiman, Omid Abari
2024 Misc conf
HotMobile
Tianxiang Li, Mohammad Hossein Mazaheri, Kalaivani Kamalakannan, Haofan Lu, Omid Abari
2024 A* conf
MobiCom
Tianxiang Li, Mohammad Hossein Mazaheri, Omid Abari
2024 J jnl
CoRR
Tianxiang Li, Haofan Lu, Omid Abari
2024 A* conf
ICML
Haofan Lu, Christopher Vattheuer, Baharan Mirzasoleiman, Omid Abari
2024 J jnl
IEEE Internet Things J.
Ali Abedi, Haofan Lu, Alex Chen, Charlie Liu, Omid Abari
2023 A* conf
SIGCOMM
Haofan Lu, Mohammad Mazaheri, Reza Rezvani, Omid Abari
2023 J jnl
CoRR
Christopher Vattheuer, Charlie Liu, Ali Abedi, Omid Abari
2023 A* conf
MobiCom
Mohammad Mazaheri, Rafael Ruiz, Domenico Giustiniano, Joerg Widmer, Omid Abari
2023 conf
IPSN
Justin Feng, Timothy Jacques, Omid Abari, Nader Sehatbakhsh
2023 conf
IPSN
Justin Feng, Timothy Jacques, Omid Abari, Nader Sehatbakhsh
2023 J jnl
CoRR
Ali Abedi, Haofan Lu, Alex Chen, Charlie Liu, Omid Abari
2023 Misc conf
NSDI
Kun Woo Cho, Mohammad Hossein Mazaheri, Jeremy Gummeson, Omid Abari, Kyle Jamieson
2022 Misc conf
HotMobile
Tianxiang Li, Mohammad Hossein Mazaheri, Omid Abari
2022 J jnl
GetMobile Mob. Comput. Commun.
Mohammad Mazaheri, Omid Abari
2022 J jnl
GetMobile Mob. Comput. Commun.
Farzan Dehbashi, Ali Abedi, Tim Brecht, Omid Abari
2022 Misc conf
HotNets
Tianxiang Li, Haofan Lu, Reza Rezvani, Ali Abedi, Omid Abari
2022 B conf
SECON
Ju Wang, Liqiong Chang, Omid Abari, Srinivasan Keshav
2022 J jnl
CoRR
Kun Woo Cho, Mohammad Hossein Mazaheri, Jeremy Gummeson, Omid Abari, Kyle Jamieson
2021 Misc conf
HotNets
Ali Abedi, Omid Abari
2021 J jnl
Comput. Commun.
Ali Abedi, Tim Brecht, Omid Abari
2021 A* conf
UIST
Antony Albert Raj Irudayaraj, Rishav Agarwal, Nikhita Joshi, Aakar Gupta, Omid Abari, Daniel Vogel
2021 A* conf
MobiCom
Farzan Dehbashi, Ali Abedi, Tim Brecht, Omid Abari
2021 A* conf
SIGCOMM
Mohammad Hossein Mazaheri, Alex Chen, Omid Abari
2021 Misc conf
HotMobile
Kun Woo Cho, Mohammad Hossein Mazaheri, Jeremy Gummeson, Omid Abari, Kyle Jamieson
2020 conf
BuildSys
David Radke, Omid Abari, Tim Brecht, Kate Larson
2020 conf
IoTDI
Liqiong Chang, Ju Wang, Omid Abari, Srinivasan Keshav
2020 Misc conf
HotNets
Mohammad Hossein Mazaheri, Alex Chen, Omid Abari
2020 A conf
MSWiM
Ali Abedi, Tim Brecht, Omid Abari
2020 Misc conf
SenSys
Ju Wang, Jianyan Li, Mohammad Hossein Mazaheri, Keiko Katsuragawa, Daniel Vogel, Omid Abari
2020 A conf
MobiSys
Ju Wang, Liqiong Chang, Shourya Aggarwal, Omid Abari, Srinivasan Keshav
2020 Misc conf
HotNets
Ali Abedi, Omid Abari
2020 A* conf
SIGCOMM
Ali Abedi, Farzan Dehbashi, Mohammad Hossein Mazaheri, Omid Abari, Tim Brecht
2019 J jnl
GetMobile Mob. Comput. Commun.
Mohammad Hossein Mazaheri, Ali Abedi, Soroush Ameli, Omid Abari
2019 A* conf
SIGCOMM
Mohammad Hossein Mazaheri, Soroush Ameli, Ali Abedi, Omid Abari
2019 A conf
MobiSys
Ju Wang, Liqiong Chang, Omid Abari, Srinivasan Keshav
2019 J jnl
GetMobile Mob. Comput. Commun.
Ju Wang, Omid Abari, Srinivasan Keshav
2019 conf
SIGCOMM Posters and Demos
Farzan Dehbashi, Nauman Ahmed, Manav Mehra, Ju Wang, Omid Abari
2019 A* conf
UIST
Keiko Katsuragawa, Ju Wang, Ziyang Shan, Ningshan Ouyang, Omid Abari, Daniel Vogel
2019 Misc conf
HotNets
Ali Abedi, Omid Abari, Tim Brecht
2018 A* conf
MobiCom
Ju Wang, Omid Abari, Srinivasan Keshav
2018 A* conf
SIGCOMM
Haitham Hassanieh, Omid Abari, Michael Rodriguez, Mohammed A. Abdelghany, Dina Katabi, Piotr Indyk
2018 A* conf
SIGCOMM
Deepak Vasisht, Guo Zhang, Omid Abari, Hsiao-Ming Lu, Jacob Flanz, Dina Katabi
2018 A* conf
MobiCom
Mohammad Hossein Mazaheri, Ali Abedi, Omid Abari
2018 Misc conf
HotNets
Ali Abedi, Mohammad Hossein Mazaheri, Omid Abari, Tim Brecht
2017 J jnl
CoRR
Haitham Hassanieh, Omid Abari, Michael Rodreguez, Mohammed A. Abdelghany, Dina Katabi, Piotr Indyk
2017 conf
mmNets
Omid Abari
2017 Misc conf
NSDI
Omid Abari, Dinesh Bharadia, Austin Duffield, Dina Katabi
2016 A* conf
MobiCom
Omid Abari, Haitham Hassanieh, Michael Rodreguiz, Dina Katabi
2016 Misc conf
HotNets
Omid Abari, Dinesh Bharadia, Austin Duffield, Dina Katabi
2016 Misc conf
HotNets
Omid Abari, Haitham Hassanieh, Michael Rodreguez, Dina Katabi
2016 J jnl
CoRR
Omid Abari, Hariharan Rahul, Dina Katabi
2015 A* conf
INFOCOM
Omid Abari, Hariharan Rahul, Dina Katabi, Mondira Pant
2015 A* conf
SIGCOMM
Omid Abari, Deepak Vasisht, Dina Katabi, Anantha P. Chandrakasan
2014 conf
ISSCC
Omid Abari, Ezzeldin Hamed, Haitham Hassanieh, Abhinav Agarwal, Dina Katabi, Anantha P. Chandrakasan, Vladimir Stojanovic
2014 A* conf
INFOCOM
Haitham Hassanieh, Lixin Shi, Omid Abari, Ezzeldin Hamed, Dina Katabi
2014 B conf
FPL
Abhinav Agarwal, Haitham Hassanieh, Omid Abari, Ezzeldin Hamed, Dina Katabi, Arvind
2014 A* conf
MobiCom
Omid Abari, Hariharan Rahul, Dina Katabi
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