Nathalia Yukie Crepaldi

11 papers Journal 2Unranked 9
YearRankTypeTitle / Venue / Authors
2022 conf
CENTERIS/ProjMAN/HCist
Nathalia Yukie Crepaldi, Vinícius Costa Lima, Filipe Andrade Bernardi, Domingos Alves
2022 conf
ICCS (3)
Isabelle Carvalho, Mariane Barros Neiva, Newton Shydeo Brandão Miyoshi, Nathalia Yukie Crepaldi, Filipe Andrade Bernardi, Vinícius Costa Lima, Ketlin Fabri dos Santos, Ana Clara de Andrade Mioto, Mariana Tavares Mozini, Rafael Mello Galliez, Mauro Niskier Sanchez, Afrânio Lineu Kritski, Domingos Alves
2021 conf
CENTERIS/ProjMAN/HCist
Isabelle Carvalho, Filipe Andrade Bernardi, Mariane Barros Neiva, Vinícius Costa Lima, Lariza Laura de Oliveira, Newton Shydeo Brandão Miyoshi, Tiago Lara Michelin Sanches, Francisco Barbosa-Junior, Nathalia Yukie Crepaldi, Diego Bettiol Yamada, Domingos Alves
2021 conf
CENTERIS/ProjMAN/HCist
Thomaz Felipe Soares Arnizant, Filipe Andrade Bernardi, Tiago Lara Michelin Sanches, Nathalia Yukie Crepaldi, Thiago Nascimento do Prado, Marcelle Temporim Novaes, Ethel Leonor Noia Maciel, Domingos Alves
2019 J jnl
Health Informatics J.
Rui Pedro Charters Lopes Rijo, Nathalia Yukie Crepaldi, Fernanda Bergamini Vicentine, Lídia Maria Lourençon Rodrigues, Inácia Bezerra de Lima, Gleici da Silva Castro Perdoná, Domingos Alves
2019 conf
CENTERIS/ProjMAN/HCist
Nathalia Yukie Crepaldi, Vinícius Costa Lima, Filipe Andrade Bernardi, Luiz Ricardo Albano Santos, Verena Hokino Yamaguti, Felipe Carvalho Pellison, Tiago Lara Michelin Sanches, Newton Shydeo Brandão Miyoshi, Antonio Ruffino-Netto, Rui Pedro Charters Lopes Rijo, Domingos Alves
2019 conf
CENTERIS/ProjMAN/HCist
Luiz Ricardo Albano dos Santos, Lívia M. P. Anselmo, Lucas S. Oliveira, Fernanda S. Merli, Carla C. Silva, Gabriela Cristina Silva Prado, Nathalia Yukie Crepaldi, Filipe Andrade Bernardi, Matheus Angerami Marçal, Antonio Ruffino-Netto, Rui Pedro Charters Lopes Rijo, Valdes Roberto Bollela, Domingos Alves
2019 conf
CENTERIS/ProjMAN/HCist
Luiz Ricardo Albano dos Santos, Filipe Andrade Bernardi, Gabriela Cristina Silva Prado, Vinícius Costa Lima, Nathalia Yukie Crepaldi, Matheus Angerami Marçal, Rui Pedro Charters Lopes Rijo, Rafael Mello Galliez, Antonio Ruffino-Netto, Domingos Alves
2018 conf
CENTERIS/ProjMAN/HCist
Verena Hokino Yamaguti, Rui Pedro Charters Lopes Rijo, Nathalia Yukie Crepaldi, Antonio Ruffino-Netto, Isabelle Carvalho, Domingos Alves
2018 conf
CENTERIS/ProjMAN/HCist
Vinícius Costa Lima, Domingos Alves, Felipe Carvalho Pellison, Vinicius Tohoru Yoshiura, Nathalia Yukie Crepaldi, Rui Pedro Charters Lopes Rijo
2018 J jnl
J. Medical Syst.
Nathalia Yukie Crepaldi, Inácia Bezerra de Lima, Fernanda Bergamini Vicentine, Lídia Maria Lourençon Rodrigues, Tiago Lara Michelin Sanches, Antonio Ruffino-Netto, Domingos Alves, Rui Pedro Charters Lopes Rijo
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