Olivier Billoint

35 papers A 3C 4Journal 3Unranked 25
YearRankTypeTitle / Venue / Authors
2025 conf
IMW
Tarcisius Januel, Olivier Billoint, Laurent Grenouillet, S. Martin, Jean-Michel Portal, Elisa Vianello
2025 C conf
DDECS
Claire Fenouillet-Béranger, Laurent Fesquet, Rihab Chouk, Gabriel Pares, Baudouin Martineau, Marie Claire Cyrille, Thierry Poiroux, Olivier Billoint, Dominique Noguet
2024 conf
IMW
Olivier Billoint, Simon Martin, J. Laguerre, L. Hosier, Jean Coignus, Catherine Carabasse, François Andrieu, Laurent Grenouillet
2023 conf
IMW
J. Laguerre, Marc Bocquet, Olivier Billoint, Simon Martin, Jean Coignus, Catherine Carabasse, Thomas Magis, T. Dewolf, François Andrieu, Laurent Grenouillet
2021 conf
IMW
Laurent Grenouillet, Niccolo Castellani, Alain Persico, Valentina Meli, Simon Martin, Olivier Billoint, R. Segaud, Stefania Bernasconi, C. Pellissier, Carine Jahan, Christelle Charpin-Nicolle, P. Dezest, Catherine Carabasse, Paul Besombes, Sebastien Ricavy, N. P. Tran, A. Magalhaes-Lucas, A. Roman, C. Boixaderas, Thomas Magis, Messaoud Bedjaoui, M. Tessaire, A. Seignard, F. Mazen, S. Landis, Elisa Vianello, Gabriel Molas, Fred Gaillard, Julien Arcamone, Etienne Nowak
2021 conf
MWSCAS
Behnam Samadpoor Rikan, Philipp Häfliger, Gerald Cibrario, Olivier Billoint, Mehdi Mouhdach
2020 A conf
DATE
Sébastien Thuries, Olivier Billoint, Sylvain Choisnet, Romain Lemaire, Pascal Vivet, Perrine Batude, Didier Lattard
2019 conf
3DIC
Olivier Billoint, Karim Azizi-Mourier, Gerald Cibrario, Didier Lattard, Mehdi Mouhdach, Sébastien Thuries, Pascal Vivet
2019 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Dimitri Galayko, Chuan Shan, Eldar Zianbetov, Mohammad Javidan, Anton Korniienko, François Anceau, Olivier Billoint, Éric Colinet, Elena Blokhina, Jérôme Juillard
2018 conf
ICICDT
François Andrieu, Perrine Batude, Laurent Brunet, Claire Fenouillet-Béranger, Didier Lattard, Sébastien Thuries, Olivier Billoint, Richard Fournel, Maud Vinet
2018 conf
ICECS
Pascal Vivet, Sébastien Thuries, Olivier Billoint, Sylvain Choisnet, Didier Lattard, Edith Beigné, Perrine Batude
2017 J jnl
Microelectron. J.
Hossam Sarhan, Sébastien Thuries, Olivier Billoint, Fabien Clermidy
2017 C conf
IOLTS
Ivan Miro Panades, Edith Beigné, Olivier Billoint, Yvain Thonnart
2017 conf
ISVLSI
Melanie Brocard, Benoît Mathieu, Jean-Philippe Colonna, Cristiano Santos, Claire Fenouillet-Béranger, Cao-Minh Vincent Lu, Gerald Cibrario, Laurent Brunet, Perrine Batude, François Andrieu, Sébastien Thuries, Olivier Billoint
2016 conf
3DIC
Gerald Cibrario, Nour Ben Salem, Joris Lacord, Karim Azizi-Mourier, Olivier Rozeau, Etienne Maurin, Olivier Billoint, Sébastien Thuries, Alexandre Valentian
2016 conf
ESSDERC
Melanie Brocard, Guillaume Berhault, Sébastien Thuries, Fabien Clermidy, Perrine Batude, Claire Fenouillet-Béranger, Laurent Brunet, François Andrieu, Fabien Deprat, Joris Lacord, Olivier Rozeau, Gerald Cibrario, Olivier Billoint
2016 conf
ESSDERC
Maud Vinet, Perrine Batude, Claire Fenouillet-Béranger, Laurent Brunet, Vincent Mazzocchi, Cao-Minh Vincent Lu, Fabien Deprat, Jessy Micout, Bernard Previtali, Paul Besombes, Nils Rambal, François Andrieu, Olivier Billoint, Melanie Brocard, Sébastien Thuries, Guillaume Berhault, Cristiano Lopes Dos Santos, Gerald Cibrario, Fabien Clermidy, Daniel Gitlin, Olivier Faynot
2016 conf
ICICDT
Claire Fenouillet-Béranger, Perrine Batude, Laurent Brunet, Vincent Mazzocchi, Cao-Minh Vincent Lu, Fabien Deprat, Jessy Micout, M.-P. Samson, Bernard Previtali, Paul Besombes, Nils Rambal, François Andrieu, Olivier Billoint, Melanie Brocard, Sébastien Thuries, Gerald Cibrario, Maud Vinet
2016 conf
3DIC
Cristiano Santos, Pascal Vivet, Sébastien Thuries, Olivier Billoint, Jean-Philippe Colonna, Perceval Coudrain, Lee Wang
2015 J jnl
IEEE J. Solid State Circuits
Edith Beigné, Alexandre Valentian, Ivan Miro Panades, Robin Wilson, Philippe Flatresse, Fady Abouzeid, Thomas Benoist, Christian Bernard, Sebastien Bernard, Olivier Billoint, Sylvain Clerc, Bastien Giraud, Anuj Grover, Julien Le Coz, Jean-Philippe Noel, Olivier Thomas, Yvain Thonnart
2015 A conf
DATE
Olivier Billoint, Hossam Sarhan, Iyad Rayane, Maud Vinet, Perrine Batude, Claire Fenouillet-Béranger, Olivier Rozeau, Gerald Cibrario, Fabien Deprat, A. Fustier, Julien Michallet, Olivier Faynot, Ogun Turkyilmaz, Jean-Frédéric Christmann, Sébastien Thuries, Fabien Clermidy
2015 conf
NEWCAS
Chuan Shan, Eldar Zianbetov, François Anceau, Olivier Billoint, Dimitri Galayko
2015 conf
ISVLSI
Hossam Sarhan, Sébastien Thuries, Olivier Billoint, Fabien Clermidy
2015 C conf
VLSI-SoC
Bartosz Boguslawski, Hossam Sarhan, Frédéric Heitzmann, Fabrice Seguin, Sébastien Thuries, Olivier Billoint, Fabien Clermidy
2015 conf
ISPD
Olivier Billoint, Hossam Sarhan, Iyad Rayane, Maud Vinet, Perrine Batude, Claire Fenouillet-Béranger, Olivier Rozeau, Gerald Cibrario, Fabien Deprat, Ogun Turkyilmaz, Sébastien Thuries, Fabien Clermidy
2015 conf
3DIC
Hossam Sarhan, Sébastien Thuries, Olivier Billoint, Fabien Deprat, Alexandre Ayres De Sousa, Perrine Batude, Claire Fenouillet-Béranger, Fabien Clermidy
2015 conf
ESSDERC
Edith Beigné, Jean-Frédéric Christmann, Alexandre Valentian, Olivier Billoint, Esteve Amat, Dominique Morche
2014 conf
ISSCC
Robin Wilson, Edith Beigné, Philippe Flatresse, Alexandre Valentian, Fady Abouzeid, Thomas Benoist, Christian Bernard, Sebastien Bernard, Olivier Billoint, Sylvain Clerc, Bastien Giraud, Anuj Grover, Julien Le Coz, Ivan Miro Panades, Jean-Philippe Noël, Bertrand Pelloux-Prayer, Philippe Roche, Olivier Thomas, Yvain Thonnart, David Turgis, Fabien Clermidy, Philippe Magarshack
2014 conf
ReCoSoC
Fabien Clermidy, O. Turkyimaz, Olivier Billoint, Pierre-Emmanuel Gaillardon
2014 conf
ASP-DAC
Hossam Sarhan, Sébastien Thuries, Olivier Billoint, Fabien Clermidy
2014 conf
ICICDT
Gerald Cibrario, Marjorie Gary, Fabien Gays, Karim Azizi-Mourier, Olivier Billoint, Ogun Turkyilmaz, Olivier Rozeau
2013 conf
CICC
Eldar Zianbetov, Dimitri Galayko, François Anceau, Mohammad Javidan, Chuan Shan, Olivier Billoint, Anton Korniienko, Éric Colinet, Gérard Scorletti, J. M. Akrea, Jérôme Juillard
2013 C conf
ISCAS
Jani Mäkipää, Olivier Billoint
2013 conf
ReConFig
Chuan Shan, Eldar Zianbetov, Weiqiang Yu, François Anceau, Olivier Billoint, Dimitri Galayko
2013 A conf
DATE
Edith Beigné, Alexandre Valentian, Bastien Giraud, Olivier Thomas, Thomas Benoist, Yvain Thonnart, Serge Bernard, Guillaume Moritz, Olivier Billoint, Y. Maneglia, Philippe Flatresse, Jean-Philippe Noel, Fady Abouzeid, Bertrand Pelloux-Prayer, Anuj Grover, Sylvain Clerc, Philippe Roche, Julien Le Coz, Sylvain Engels, Robin Wilson
redb/extractors/decompiler/apk/method_extractor.py
← Index redb/extractors/decompiler/apk/method_extractor.py python
"""Per-method content extraction, hashing, and similarity computation.

Handles SHA-256 content hashing, ssdeep/TLSH fuzzy hashing, MinHash
computation, and obfuscation indicator detection for APK methods.
"""

import hashlib
import re
from typing import Dict, List, Optional

from redb.extractors.decompiler.apk.smali_normalization import (
    categorize_opcode,
    normalize_method_body,
)
from redb.extractors.decompiler.apk.smali_parser import SmaliParser


# ---------------------------------------------------------------------------
# Smali Prime Product — semantic primes matching Binary Ninja's LLIL primes
# ---------------------------------------------------------------------------
# Each Dalvik semantic category maps to the same prime its LLIL counterpart
# uses in cfg_features.py. This makes prime products semantically comparable
# for APK-vs-APK similarity (not numerically comparable to Binja values).

SMALI_OP_PRIMES = {
    "ALU": 37,       # ADD/SUB → same prime as LLIL_ADD
    "CONV": 131,     # Type conversions → same as LLIL_SX
    "CMP": 103,      # Comparisons → same as LLIL_CMP_E
    "MOV": 2,        # Register moves → same as LLIL_SET_REG
    "CONST": 2,      # Constants → SET_REG equivalent
    "LOAD": 5,       # Field/array reads → same as LLIL_LOAD
    "STORE": 7,      # Field/array writes → same as LLIL_STORE
    "CALL": 17,      # invoke-* → same as LLIL_CALL
    "BRANCH": 29,    # if-* → same as LLIL_IF
    "JMP": 31,       # goto → same as LLIL_GOTO
    "SWITCH": 151,   # switch → same as LLIL_JUMP_TO
    "RET": 23,       # return → same as LLIL_RET
    "ALLOC": 5,      # new-instance/new-array → LOAD-adjacent (heap access)
    "TYPE": 1,       # check-cast/instance-of → identity (metadata)
    "ARR": 5,        # array-length/fill-array → LOAD-adjacent
    "EXC": 23,       # throw → RET-adjacent (control transfer out)
    "SYNC": 1,       # monitor → identity (no LLIL equivalent)
    "OTHER": 1,      # Unknown → identity
}


def compute_prime_product_smali(smali_body: str) -> int:
    """Multiplicative hash of normalized Dalvik opcodes. Mod 2^64.

    Same algorithm as cfg_features.compute_prime_product but using
    Dalvik semantic categories instead of LLIL operation enums.
    """
    if not smali_body:
        return 0

    product = 1
    for line in smali_body.splitlines():
        stripped = line.strip()
        if not stripped or stripped.startswith((".", ":", "#")):
            continue
        opcode = stripped.split()[0].split("/")[0] if stripped else ""
        category = categorize_opcode(opcode)
        prime = SMALI_OP_PRIMES.get(category, 1)
        product = (product * prime) % (2**64)

    return product


def count_call_instructions(smali_body: str) -> int:
    """Count invoke-* instructions in a smali method body."""
    if not smali_body:
        return 0
    count = 0
    for line in smali_body.splitlines():
        stripped = line.strip()
        if stripped.startswith("invoke-"):
            count += 1
    return count


def compute_sha256(content: str) -> str:
    """Compute SHA-256 hash of normalized content."""
    return hashlib.sha256(content.encode("utf-8")).hexdigest()


def compute_ssdeep(content: str) -> Optional[str]:
    """Compute ssdeep fuzzy hash of content."""
    try:
        import ppdeep
        data = content.encode("utf-8")
        if len(data) < 50:
            return None
        result = ppdeep.hash(data)
        return result if result else None
    except (ImportError, Exception):
        return None


def compute_tlsh(content: str) -> Optional[str]:
    """Compute TLSH fuzzy hash of content."""
    try:
        import tlsh
        data = content.encode("utf-8")
        if len(data) < 50:
            return None
        result = tlsh.hash(data)
        return result if result else None
    except (ImportError, Exception):
        return None


def compute_minhash(
    content: str,
    n: int = 3,
    normalization_level: str = "opcode_api",
) -> Optional[List[int]]:
    """Compute MinHash signature from semantically normalized smali n-grams.

    Applies semantic normalization (analogous to Binary Ninja's LLIL) before
    computing the MinHash. This strips register allocation noise and
    instruction encoding variants while preserving operation semantics and
    API references.

    Uses the same algorithm and parameters as the Binary Ninja MinHasher
    (64 seeds from master seed 0xdeadbeef, 8-bit signature elements, mmh3)
    to ensure cross-platform similarity comparisons are compatible.

    Args:
        content: Raw smali method body.
        n: N-gram size (default 3).
        normalization_level: Normalization level for instructions.
            'opcode_api' (default) preserves API call/field references.
            'category' uses only semantic categories.
            'opcode' uses base opcodes without operands.
    """
    try:
        import mmh3
    except ImportError:
        return None

    HASH_MAX = 0xFFFFFFFF
    SIGNATURE_LENGTH = 64
    SIGNATURE_BITS = 8

    # Semantically normalize instructions (like LLIL for native code)
    lines = normalize_method_body(content, level=normalization_level)

    if len(lines) < n:
        return None

    # Build n-grams (tuples of normalized instruction strings)
    shingles = [tuple(lines[i:i + n]) for i in range(len(lines) - n + 1)]

    if not shingles:
        return None

    # Generate deterministic seeds matching the Binary Ninja pipeline
    import random
    rng = random.Random(0xDEADBEEF)
    seeds = [rng.randint(0, HASH_MAX) for _ in range(SIGNATURE_LENGTH)]

    # For each seed, hash all shingles and take the minimum
    signature = []
    for seed in seeds:
        min_val = HASH_MAX
        for shingle in shingles:
            text = "|".join(str(elem) for elem in shingle)
            h = mmh3.hash(text, seed) & HASH_MAX
            if h < min_val:
                min_val = h
        # Truncate to signature bits
        if SIGNATURE_BITS < 32:
            min_val %= (2 ** SIGNATURE_BITS)
        signature.append(min_val)

    return signature


def detect_obfuscation_indicators(
    method_name: str,
    class_name: str,
    smali_body: str,
    instruction_count: int,
) -> Dict[str, bool]:
    """Compute obfuscation indicators for a method.

    Returns dict with boolean indicators.
    """
    indicators = {}

    # Short method name (typical R8/ProGuard output)
    indicators["short_method_name"] = len(method_name) <= 2

    # Short class name — extract simple name from Dalvik descriptor
    simple_class = class_name
    if "/" in simple_class:
        simple_class = simple_class.rsplit("/", 1)[-1]
    simple_class = simple_class.rstrip(";")
    indicators["short_class_name"] = len(simple_class) <= 2

    # String encryption: const-string followed by decryption-pattern call
    indicators["has_string_encryption"] = _detect_string_encryption(smali_body)

    # Reflection calls
    indicators["has_reflection_calls"] = _detect_reflection_calls(smali_body)

    # Excessive goto count (control flow flattening)
    goto_count = _count_goto_instructions(smali_body)
    threshold = max(5, int(instruction_count * 0.15))
    indicators["excessive_goto_count"] = goto_count > threshold

    return indicators


def _detect_string_encryption(smali_body: str) -> bool:
    """Detect const-string followed by decryption-pattern calls."""
    lines = smali_body.split("\n")
    for i, line in enumerate(lines):
        stripped = line.strip()
        if stripped.startswith("const-string"):
            # Check the next 3 lines for invoke-* to potential decryption
            for j in range(i + 1, min(i + 4, len(lines))):
                next_line = lines[j].strip()
                if next_line.startswith("invoke-"):
                    # Common decryption patterns
                    if any(
                        pat in next_line
                        for pat in [
                            "decrypt",
                            "decode",
                            "Cipher",
                            "DES",
                            "AES",
                            "Base64",
                            "getBytes",
                        ]
                    ):
                        return True
    return False


def _detect_reflection_calls(smali_body: str) -> bool:
    """Detect use of Java reflection APIs."""
    reflection_patterns = [
        "Ljava/lang/reflect/",
        "Ljava/lang/Class;->forName",
        "Ljava/lang/Class;->getMethod",
        "Ljava/lang/Class;->getDeclaredMethod",
        "Ljava/lang/Class;->getField",
        "Ljava/lang/Class;->getDeclaredField",
    ]
    for pattern in reflection_patterns:
        if pattern in smali_body:
            return True
    return False


def _count_goto_instructions(smali_body: str) -> int:
    """Count goto/goto_16/goto_32 instructions."""
    count = 0
    for line in smali_body.split("\n"):
        stripped = line.strip()
        if stripped.startswith(("goto ", "goto/16 ", "goto/32 ")):
            count += 1
        elif stripped in ("goto", "goto/16", "goto/32"):
            count += 1
    return count


def dalvik_to_java_class(descriptor: str) -> str:
    """Convert Dalvik class descriptor to Java dot notation.

    Lcom/example/Foo; -> com.example.Foo
    """
    if descriptor.startswith("L") and descriptor.endswith(";"):
        return descriptor[1:-1].replace("/", ".")
    return descriptor.replace("/", ".")


def dalvik_type_to_java(type_desc: str) -> str:
    """Convert a Dalvik type descriptor to Java type name."""
    type_map = {
        "V": "void",
        "Z": "boolean",
        "B": "byte",
        "S": "short",
        "C": "char",
        "I": "int",
        "J": "long",
        "F": "float",
        "D": "double",
    }

    if not type_desc:
        return "void"

    if type_desc in type_map:
        return type_map[type_desc]

    if type_desc.startswith("["):
        return dalvik_type_to_java(type_desc[1:]) + "[]"

    if type_desc.startswith("L") and type_desc.endswith(";"):
        full = type_desc[1:-1].replace("/", ".")
        # Return simple name
        return full.rsplit(".", 1)[-1] if "." in full else full

    return type_desc


def dalvik_to_java_prototype(
    method_name: str, signature: str, class_name: str = ""
) -> str:
    """Convert Dalvik method signature to Java-style prototype.

    Input: method_name='onCreate', signature='(Landroid/os/Bundle;)V'
    Output: 'void onCreate(Bundle)'
    """
    # Parse return type and param types from signature
    if not signature or not signature.startswith("("):
        return f"void {method_name}()"

    close_paren = signature.find(")")
    if close_paren == -1:
        return f"void {method_name}()"

    params_str = signature[1:close_paren]
    return_type_str = signature[close_paren + 1:]

    return_type = dalvik_type_to_java(return_type_str)
    params = _parse_dalvik_params(params_str)
    param_java = ", ".join(dalvik_type_to_java(p) for p in params)

    return f"{return_type} {method_name}({param_java})"


def _parse_dalvik_params(params_str: str) -> List[str]:
    """Parse Dalvik parameter descriptor string into individual types."""
    params = []
    i = 0
    while i < len(params_str):
        ch = params_str[i]
        if ch in "VZBSCIJFD":
            params.append(ch)
            i += 1
        elif ch == "[":
            # Array — find the base type
            array_prefix = "["
            i += 1
            while i < len(params_str) and params_str[i] == "[":
                array_prefix += "["
                i += 1
            if i < len(params_str):
                if params_str[i] == "L":
                    end = params_str.find(";", i)
                    if end != -1:
                        params.append(array_prefix + params_str[i : end + 1])
                        i = end + 1
                    else:
                        break
                else:
                    params.append(array_prefix + params_str[i])
                    i += 1
        elif ch == "L":
            end = params_str.find(";", i)
            if end != -1:
                params.append(params_str[i : end + 1])
                i = end + 1
            else:
                break
        else:
            i += 1
    return params