Vincent Jeanselme

21 papers Journal 16Unranked 5
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Zilin Jing, Vincent Jeanselme, Yuta Kobayashi, Simon A. Lee, Chao Pang, Aparajita Kashyap, Yanwei Li, Xinzhuo Jiang, Shalmali Joshi
2025 conf
MLHC
Mert Ketenci, Vincent Jeanselme, Harry Reyes Nieva, Shalmali Joshi, Noémie Elhadad
2025 J jnl
CoRR
Mert Ketenci, Vincent Jeanselme, Harry Reyes Nieva, Shalmali Joshi, Noémie Elhadad
2025 J jnl
CoRR
Vincent Jeanselme, Brian D. M. Tom, Jessica K. Barrett
2025 J jnl
CoRR
Chao Pang, Vincent Jeanselme, Young Sang Choi, Xinzhuo Jiang, Zilin Jing, Aparajita Kashyap, Yuta Kobayashi, Yanwei Li, Florent Pollet, Karthik Natarajan, Shalmali Joshi
2025 J jnl
CoRR
Young Sang Choi, Vincent Jeanselme, Pierre A. Elias, Shalmali Joshi
2025 J jnl
Manag. Sci.
Maria De-Arteaga, Vincent Jeanselme, Artur Dubrawski, Alexandra Chouldechova
2025 J jnl
CoRR
Yuta Kobayashi, Vincent Jeanselme, Shalmali Joshi
2025 J jnl
CoRR
Vincent Jeanselme, Glen P. Martin, Matthew Sperrin, Niels Peek, Brian D. M. Tom, Jessica K. Barrett
2025 J jnl
CoRR
Emily Alsentzer, Marie-Laure Charpignon, Bill Chen, Niharika D'Souza, Jason A. Fries, Yixing Jiang, Aparajita Kashyap, Chanwoo Kim, Simon A. Lee, Aishwarya Mandyam, Ashery Christopher Mbilinyi, Nikita Mehandru, Nitish Nagesh, Brighton Nuwagira, Emma Pierson, Arvind Pillai, Akane Sano, Tanveer F. Syeda-Mahmood, Shashank Yadav, Elias Adhanom, Muhammad Umar Afza, Amelia Archer, Suhana Bedi, Vasiliki Bikia, Trenton Chang, George H. Chen, Winston Chen, Erica Chiang, Edward Choi, Octavia Ciora, Paz Dozie-Nnamah, Shaza Elsharief, Matthew Engelhard, Ali Eshragh, Jean Feng, Josh Fessel, Scott L. Fleming, Kei Sen Fong, Thomas Frost, Soham Gadgil, Judy Gichoya, Leeor Hershkovich, Sujeong Im, Bhavya Jain, Vincent Jeanselme, Furong Jia, Qixuan Jin, Yuxuan Jin, Daniel Kapash, Geetika Kapoor, Behdokht Kiafar, Matthias Kleiner, Stefan Kraft, Annika Kumar, Daeun Kyung, Zhongyuan Liang, Joanna Lin, Qianchu Liu, Chang Liu, Hongzhou Luan, Chris Lunt, Leopoldo Julian Lechuga López, Matthew B. A. McDermott, Shahriar Noroozizadeh, Connor O'Brien, YongKyung Oh, Mixail Ota, Stephen Pfohl, Meagan Pi, Tanmoy Sarkar Pias, Emma Rocheteau, Avishaan Sethi, Toru Shirakawa, Anita Silver, Neha Simha, Kamile Stankeviciute, Max Sunog, Peter Szolovits, Shengpu Tang, Jialu Tang, Aaron Tierney, John Valdovinos, Byron Wallace, Will Ke Wang, Peter Washington, Jeremy C. Weiss, Daniel Wolfe, Emily Wong, Hye Sun Yun, Xiaoman Zhang, Xiao Yu Cindy Zhang, Hayoung Jeong, Kaveri A. Thakoor
2024 J jnl
Adv. Data Anal. Classif.
Benedikt Boecking, Vincent Jeanselme, Artur Dubrawski
2024 J jnl
CoRR
Vincent Jeanselme, Chang Ho Yoon, Fabian Falck, Brian D. M. Tom, Jessica K. Barrett
2024 J jnl
CoRR
Hyewon Jeong, Sarah Jabbour, Yuzhe Yang, Rahul Thapa, Hussein Mozannar, William Jongwon Han, Nikita Mehandru, Michael Wornow, Vladislav Lialin, Xin Liu, Alejandro Lozano, Jiacheng Zhu, Rafal Dariusz Kocielnik, Keith Harrigian, Haoran Zhang, Edward Lee, Milos Vukadinovic, Aparna Balagopalan, Vincent Jeanselme, Katherine Matton, Ilker Demirel, Jason A. Fries, Parisa Rashidi, Brett K. Beaulieu-Jones, Xuhai Orson Xu, Matthew B. A. McDermott, Tristan Naumann, Monica Agrawal, Marinka Zitnik, Berk Ustun, Edward Choi, Kristen Yeom, Gamze Gürsoy, Marzyeh Ghassemi, Emma Pierson, George H. Chen, Sanjat Kanjilal, Michael Oberst, Linying Zhang, Harvineet Singh, Tom Hartvigsen, Helen Zhou, Chinasa T. Okolo
2023 conf
CHIL
Vincent Jeanselme, Chang Ho Yoon, Brian D. M. Tom, Jessica K. Barrett
2023 J jnl
CoRR
Vincent Jeanselme, Chang Ho Yoon, Brian D. M. Tom, Jessica K. Barrett
2022 J jnl
CoRR
Benedikt Boecking, Vincent Jeanselme, Artur Dubrawski
2022 J jnl
CoRR
Vincent Jeanselme, Glen P. Martin, Niels Peek, Matthew Sperrin, Brian D. M. Tom, Jessica K. Barrett
2022 conf
ML4H@NeurIPS
Vincent Jeanselme, Maria De-Arteaga, Zhe Zhang, Jessica K. Barrett, Brian D. M. Tom
2022 J jnl
CoRR
Vincent Jeanselme, Maria De-Arteaga, Zhe Zhang, Jessica K. Barrett, Brian D. M. Tom
2022 conf
CHIL
Vincent Jeanselme, Brian D. M. Tom, Jessica K. Barrett
2021 conf
SPACA
Chirag Nagpal, Vincent Jeanselme, Artur Dubrawski
redb/extractors/decompiler/apk/smali_normalization.py
← Index redb/extractors/decompiler/apk/smali_normalization.py python
"""Semantic normalization of Dalvik/smali instructions.

Analogous to Binary Ninja's LLIL normalization: strips register allocation
noise and instruction encoding variants while preserving semantic operations.

Three normalization levels (most aggressive to most detailed):
  - 'category':    semantic category only (MOV, ALU, CALL, ...)
  - 'opcode':      base opcode, width-invariant (add, sub, invoke, ...)
  - 'opcode_api':  opcode category + API method/field references for
                   invoke/field/alloc instructions (default for MinHash)

References:
  - Smali+ 12-category reduction (Canfora et al.)
  - MOSDroid opcode family grouping
  - DroidSIFT/DroidSim API-sensitive similarity
"""

import re
from typing import List

# ---------------------------------------------------------------------------
# Dalvik opcode -> semantic category mapping
# ---------------------------------------------------------------------------
# Prefix-matched against instruction opcodes. Order matters for overlapping
# prefixes (longer/more-specific prefixes should come first in iteration,
# but since we use startswith and break on first match, we order by
# specificity within the list).

OPCODE_CATEGORIES = {
    # Arithmetic/logic
    "add": "ALU", "sub": "ALU", "mul": "ALU", "div": "ALU",
    "rem": "ALU", "and": "ALU", "or": "ALU", "xor": "ALU",
    "shl": "ALU", "shr": "ALU", "ushr": "ALU", "neg": "ALU",
    "not": "ALU",
    # Data movement
    "move": "MOV", "const": "CONST",
    # Memory access (field/array)
    "iget": "LOAD", "sget": "LOAD", "aget": "LOAD",
    "iput": "STORE", "sput": "STORE", "aput": "STORE",
    # Invocations
    "invoke": "CALL",
    # Control flow
    "if": "BRANCH", "goto": "JMP",
    "switch": "SWITCH",
    "return": "RET",
    # Object/type
    "new": "ALLOC", "check": "TYPE", "instance": "TYPE",
    # Array
    "fill": "ARR", "array": "ARR",
    # Comparison
    "cmpl": "CMP", "cmpg": "CMP", "cmp": "CMP",
    # Exception / synchronization
    "throw": "EXC", "monitor": "SYNC",
    # Conversion (int-to-long, float-to-int, etc.)
    "int-to": "CONV", "long-to": "CONV", "float-to": "CONV",
    "double-to": "CONV",
}

# Pre-compiled regexes for operand extraction
_METHOD_REF_RE = re.compile(r"(L[\w/$]+;->[\w<>]+\(.*?\)[\w/$;\[]*)")
_FIELD_REF_RE = re.compile(r"(L[\w/$]+;->[\w]+:[\w/$;\[]+)")
_CLASS_REF_RE = re.compile(r"(L[\w/$]+;)")
_CONST_STRING_RE = re.compile(r'^const-string(?:/jumbo)?\s')


def categorize_opcode(opcode: str) -> str:
    """Map a Dalvik opcode to its semantic category.

    Prefix-matched: 'add-int/2addr' matches 'add' -> 'ALU'.
    Returns 'OTHER' for unrecognized opcodes.
    """
    for prefix, cat in OPCODE_CATEGORIES.items():
        if opcode.startswith(prefix):
            return cat
    return "OTHER"


# Mapping from semantic categories to the ACFG feature vector indices
# used by Binary Ninja's build_block_features (cfg_features.py).
# This enables cross-platform ACFG feature comparison.
CATEGORY_TO_ACFG_INDEX = {
    "ALU": 0,       # CAT_ARITHMETIC
    "CONV": 0,      # arithmetic-adjacent
    "CMP": 4,       # CAT_COMPARISON
    "MOV": 2,       # CAT_TRANSFER
    "CONST": 2,     # transfer-adjacent (loading constants)
    "LOAD": 5,      # CAT_MEMORY
    "STORE": 5,     # CAT_MEMORY
    "CALL": 3,      # CAT_CALL
    "BRANCH": 1,    # CAT_LOGIC (conditional logic)
    "JMP": 1,       # CAT_LOGIC
    "SWITCH": 1,    # CAT_LOGIC
    "RET": 2,       # CAT_TRANSFER
    "ALLOC": 5,     # CAT_MEMORY (heap allocation)
    "TYPE": 6,      # CAT_OTHER
    "ARR": 5,       # CAT_MEMORY
    "EXC": 6,       # CAT_OTHER
    "SYNC": 6,      # CAT_OTHER
    "OTHER": 6,     # CAT_OTHER
}


def normalize_instruction(line: str, level: str = "opcode_api") -> str:
    """Normalize a single smali instruction line.

    Args:
        line: A single smali instruction (whitespace-stripped).
        level: Normalization level:
            'category'   - most aggressive: just semantic category
            'opcode'     - base opcode only, width/addressing-mode invariant
            'opcode_api' - category + API references for invoke/field/alloc
                          (default, best for MinHash similarity)

    Returns:
        Normalized instruction string, or empty string for non-instructions.
    """
    stripped = line.strip()
    if not stripped:
        return ""

    parts = stripped.split(None, 1)
    opcode = parts[0]
    operands = parts[1] if len(parts) > 1 else ""

    if level == "category":
        return categorize_opcode(opcode)

    if level == "opcode":
        # Strip type/width suffixes for invariance:
        # add-int, add-long, add-float -> 'add'
        # add-int/2addr -> 'add'
        base = re.split(r"[-/]", opcode)[0]
        return base

    if level == "opcode_api":
        # const-string: preserve string content (encrypted strings are a
        # key malware indicator)
        if _CONST_STRING_RE.match(stripped):
            # Extract the string literal
            str_match = re.search(r'"(.*)"', operands)
            if str_match:
                return f"CONST_STR \"{str_match.group(1)}\""
            return "CONST_STR"

        # invoke-*: preserve method reference
        if opcode.startswith("invoke"):
            ref = _METHOD_REF_RE.search(operands)
            if ref:
                return f"CALL {ref.group(1)}"
            return "CALL"

        # Field access: preserve field reference
        if opcode.startswith(("iget", "iput", "sget", "sput")):
            ref = _FIELD_REF_RE.search(operands)
            if ref:
                cat = "LOAD" if "get" in opcode else "STORE"
                return f"{cat} {ref.group(1)}"
            # Fallback: try space-separated format from androguard
            # e.g. "iget v0, p0, Lcom/Foo;->field Ljava/lang/String;"
            space_ref = re.search(
                r"(L[\w/$]+;->[\w]+)\s+([\w/$;\[]+)", operands
            )
            if space_ref:
                cat = "LOAD" if "get" in opcode else "STORE"
                return f"{cat} {space_ref.group(1)}:{space_ref.group(2)}"
            cat = "LOAD" if "get" in opcode else "STORE"
            return cat

        # new-instance: preserve allocated type
        if opcode.startswith("new-instance") or opcode == "new-array":
            ref = _CLASS_REF_RE.search(operands)
            if ref:
                return f"ALLOC {ref.group(1)}"
            return "ALLOC"

        # Everything else: just the category
        return categorize_opcode(opcode)

    # Unknown level: return raw opcode
    return opcode


def normalize_method_body(
    body: str, level: str = "opcode_api"
) -> List[str]:
    """Normalize all instructions in a smali method body.

    Filters out directives (.), labels (:), comments (#), and blank lines.
    Returns a list of normalized instruction strings.

    Args:
        body: Raw smali method body text.
        level: Normalization level (see normalize_instruction).

    Returns:
        List of normalized instruction strings (no empty strings).
    """
    normalized = []
    for line in body.split("\n"):
        stripped = line.strip()
        # Skip non-instructions
        if not stripped:
            continue
        if stripped.startswith((".",":", "#")):
            continue
        result = normalize_instruction(stripped, level)
        if result:
            normalized.append(result)
    return normalized