Rafael Ballagas

36 papers A* 8A 3Misc 7Journal 7Unranked 11
YearRankTypeTitle / Venue / Authors
2019 J jnl
IEEE Pervasive Comput.
Rafael Ballagas, Jishang Wei, Mithra Vankipuram, Zhiyuan Li, Keanu Spies, Hiroshi Horii
2019 conf
CHI Extended Abstracts
Lars Erik Holmquist, Oren Zuckerman, Rafael Ballagas, Hiroshi Ishii, Kimiko Ryokai, Haiyan Zhang
2018 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Rafael Ballagas, Sarthak Ghosh, James A. Landay
2018 A* conf
UIST
Jackie (Junrui) Yang, Hiroshi Horii, Alexander Thayer, Rafael Ballagas
2014 J jnl
Comput. Entertain.
Glenda Revelle, Emily Reardon, Kristin Cook, Lori M. Takeuchi, Rafael Ballagas, Koichi Mori, Hiroshi Horii, Hayes Raffle, Maria Sandberg, Mirjana Spasojevic
2013 A conf
CSCW
Rafael Ballagas, Thérèse E. Dugan, Glenda Revelle, Koichi Mori, Maria Sandberg, Janet Go, Emily Reardon, Mirjana Spasojevic
2012 A conf
CSCW
Janet Go, Rafael Ballagas, Mirjana Spasojevic
2012 A conf
CSCW
Sean Follmer, Rafael Ballagas, Hayes Raffle, Mirjana Spasojevic, Hiroshi Ishii
2011 Misc conf
IDC
Rafael Ballagas, Glenda Revelle, Kyle Buza, Hiroshi Horii, Koichi Mori, Hayes Raffle, Mirjana Spasojevic, Janet Go, Kristin Cook, Emily Reardon, Yun-Ta Tsai, Christopher Paretti
2011 A* conf
CHI
Hayes Raffle, Glenda Revelle, Koichi Mori, Rafael Ballagas, Kyle Buza, Hiroshi Horii, Joseph Kaye, Kristin Cook, Natalie Freed, Janet Go, Mirjana Spasojevic
2011 A* conf
ACM Multimedia
Koichi Mori, Rafael Ballagas, Glenda Revelle, Hayes Raffle, Hiroshi Horii, Mirjana Spasojevic
2011 Misc conf
IDC
Hayes Raffle, Koichi Mori, Rafael Ballagas, Mirjana Spasojevic
2011 Misc conf
IDC
Hayes Raffle, Rafael Ballagas, Glenda Revelle, Koichi Mori, Hiroshi Horii, Christopher Paretti, Mirjana Spasojevic
2010 conf
Mobile HCI
Timothy Sohn, Vidya Setlur, Koichi Mori, Joseph Kaye, Hiroshi Horii, Agathe Battestini, Rafael Ballagas, Christopher Paretti, Mirjana Spasojevic
2010 A* conf
CHI
Hayes Raffle, Rafael Ballagas, Glenda Revelle, Hiroshi Horii, Sean Follmer, Janet Go, Emily Reardon, Koichi Mori, Joseph Kaye, Mirjana Spasojevic
2010 J jnl
IEEE Pervasive Comput.
Rafael Ballagas, Hayes Raffle, Janet Go, Glenda Revelle, Joseph Kaye, Morgan Ames, Hiroshi Horii, Koichi Mori, Mirjana Spasojevic
2010 Misc conf
IDC
Natalie Freed, Winslow Burleson, Hayes Raffle, Rafael Ballagas, Naomi Newman
2010 Misc conf
IDC
Sean Follmer, Hayes Raffle, Janet Go, Rafael Ballagas, Hiroshi Ishii
2009 conf
CHI Extended Abstracts
Timothy Sohn, Rafael Ballagas, Leila Takayama
2009 conf
CHI Extended Abstracts
Timothy Sohn, Leila Takayama, Dean Eckles, Rafael Ballagas
2009 Misc conf
IDC
Rafael Ballagas, Joseph Kaye, Morgan G. Ames, Janet Go, Hayes Raffle
2009 conf
INTERACT (1)
Arto Puikkonen, Jonna Häkkilä, Rafael Ballagas, Jani Mäntyjärvi
2009 conf
Mobile HCI
Arto Puikkonen, Jonna Häkkilä, Rafael Ballagas, Jani Mäntyjärvi
2009 A* conf
CHI
Sven G. Kratz, Rafael Ballagas
2008 conf
Pervasive
Rafael Ballagas, André Kuntze, Steffen P. Walz
2008 Misc conf
MuC
Christine Sutter, Jochen Müsseler, Laszlo Bardos, Rafael Ballagas, Jan O. Borchers
2007 conf
DiGRA Conference
Steffen P. Walz, Rafael Ballagas
2007 conf
CHI Extended Abstracts
Rafael Ballagas, Sven G. Kratz, Jan O. Borchers, Eugen Yu, Steffen P. Walz, Claudia O. Fuhr, Ludger Hovestadt, Martin Tann
2007 J jnl
IEEE Pervasive Comput.
John Krumm, Ken Anderson, Rodger Lea, Michael Blackstock, Mirjana Spasojevic, Mizuko Ito, Nancy A. Van House, Ilpo Koskinen, Fumitoshi Kato, Maribeth Back, Masatomi Inagaki, Kazunori Horikiri, Saadi Lahlou, Rafael Ballagas, Jeffrey Huang, Surapong Lertsithichai, Ame Elliott, Scott D. Mainwaring, Allison Woodruff, Phoebe Sengers, Thomas Riisgaard Hansen, Jakob E. Bardram, Ilkka Korhonen
2007 A* conf
CHI
Rafael Ballagas, Faraz Memon, René Reiners, Jan O. Borchers
2006 J jnl
IEEE Pervasive Comput.
Rafael Ballagas, Jan O. Borchers, Michael Rohs, Jennifer G. Sheridan
2005 conf
PERMID
Rafael Ballagas, Michael Rohs, Jennifer G. Sheridan
2005 J jnl
Commun. ACM
Trevor Pering, Rafael Ballagas, Roy Want
2005 conf
CHI Extended Abstracts
Rafael Ballagas, Michael Rohs, Jennifer G. Sheridan
2004 A* conf
PerCom
Rafael Ballagas, Andy Szybalski, Armando Fox
2003 A* conf
CHI
Rafael Ballagas, Meredith Ringel, Maureen C. Stone, Jan O. Borchers
tests/unit/test_decompile_medium_level.py
← Index tests/unit/test_decompile_medium_level.py python
# tests/unit/test_decompile_medium_level.py
"""Unit tests (mocked BN) for bninja/analysis/medium_level.py
   and bninja/analysis/medium_level_normalization.py."""
# tests/unit/test_decompile_medium_level.py
import sys
from unittest.mock import MagicMock, patch

# Installa gli stubs BN
from tests.unit.conftest_binja_stubs import install_binja_stubs
install_binja_stubs()

# ── Definisci MockMLILInstruction PRIMA di importare il modulo ──
class MockMLILInstruction:
    def __init__(self, operation, address=0, operands=None):
        self.operation = operation
        self.address = address
        self.operands = operands or []

# ── Patcha il modulo BN in modo che isinstance() funzioni ──
sys.modules["binaryninja"].MediumLevelILInstruction = MockMLILInstruction
sys.modules["binaryninja"].SSAVariable = type("SSAVariable", (), {})
sys.modules["binaryninja"].Variable = type("Variable", (), {})
sys.modules["binaryninja"].ILIntrinsic = type("ILIntrinsic", (), {})

# Ora importa il modulo — vede già i tipi corretti
from redb.extractors.decompiler.bninja.analysis.medium_level_normalization import (
    MediumLevelNormalization,
)	

class MockMLILFunction:
    def __init__(self, instructions):
        self._instructions = instructions

    @property
    def instructions(self):
        return iter(self._instructions)

    @property
    def basic_blocks(self):
        # one block containing all instructions, good enough for MinHasher
        block = MagicMock()
        block.__iter__ = lambda self_: iter([])  # not used by MediumLevelAnalysis
        return [block]


class MockFunction:
    def __init__(self, name="func", start=0x1000, mlil=None):
        self.name = name
        self.start = start
        self.mlil = mlil



class TestMediumLevelNormalization:
    def setup_method(self):
        from redb.extractors.decompiler.bninja.analysis.medium_level_normalization import (
            MediumLevelNormalization,
        )
        self.norm = MediumLevelNormalization()

    def test_normalize_skeleton_single_instruction(self):
        il = MockMLILInstruction(operation=42, operands=[])
        result = self.norm.normalize_instruction_all_levels(il)
        assert result == [42]

    def test_normalize_skeleton_nested(self):
        inner = MockMLILInstruction(operation=7, operands=[])
        outer = MockMLILInstruction(operation=1, operands=[inner])
        result = self.norm.normalize_instruction_all_levels(outer)
        assert result == [1, 7]

    def test_normalize_skeleton_with_list_operand(self):
        inner_a = MockMLILInstruction(operation=10, operands=[])
        inner_b = MockMLILInstruction(operation=11, operands=[])
        outer = MockMLILInstruction(operation=2, operands=[[inner_a, inner_b]])
        result = self.norm.normalize_instruction_all_levels(outer)
        assert result == [2, 10, 11]

    def test_normalize_skeleton_none(self):
        result = self.norm.normalize_instruction_all_levels(None)
        # collect on None should leave ops empty
        assert result == []

    def test_normalize_typed_appends_leaf_types(self):
        # operand is a plain int -> "CONST"
        il = MockMLILInstruction(operation=3, operands=[42])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [3, "CONST"]

    def test_normalize_typed_bool_before_int(self):
        # bool must be detected before int (since bool is an int subclass)
        il = MockMLILInstruction(operation=4, operands=[True])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [4, "BOOL"]

    def test_normalize_typed_float(self):
        il = MockMLILInstruction(operation=5, operands=[1.5])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [5, "FLOAT_CONST"]

    def test_normalize_typed_str(self):
        il = MockMLILInstruction(operation=6, operands=["hello"])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [6, "STR"]

    def test_normalize_typed_unknown_falls_back_to_typename(self):
        class Weird:
            pass
        il = MockMLILInstruction(operation=8, operands=[Weird()])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [8, "WEIRD"]

    def test_normalize_typed_nested_mlil(self):
        inner = MockMLILInstruction(operation=99, operands=[7])
        outer = MockMLILInstruction(operation=1, operands=[inner])
        result = self.norm.normalize_instr_with_operands(outer)
        assert result == [1, 99, "CONST"]

    def test_normalize_typed_list_mixed(self):
        inner = MockMLILInstruction(operation=50, operands=[])
        il = MockMLILInstruction(operation=2, operands=[[inner, 99]])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [2, 50, "CONST"]


class TestMediumLevelAnalysis:
    def _make_analysis(self, instructions=None, mlil=True, start=0x1000):
        from redb.extractors.decompiler.bninja.analysis.medium_level import (
            MediumLevelAnalysis,
        )
        mlil_func = MockMLILFunction(instructions or []) if mlil else None
        func = MockFunction(name="testfunc", start=start, mlil=mlil_func)
        bv = MagicMock()
        return MediumLevelAnalysis(func, bv, MagicMock())

    def test_collect_returns_empty_when_no_mlil(self):
        a = self._make_analysis(mlil=False)
        sk, sk_addr, ty, ty_addr = a._collect_mlil_skeleton_and_typed()
        assert sk == [] and sk_addr == [] and ty == [] and ty_addr == []

    def test_collect_skeleton_and_typed_basic(self):
        instrs = [
            MockMLILInstruction(operation=1, address=0x1000, operands=[]),
            MockMLILInstruction(operation=2, address=0x1004, operands=[42]),
        ]
        a = self._make_analysis(instructions=instrs, start=0x1000)
        sk, sk_addr, ty, ty_addr = a._collect_mlil_skeleton_and_typed()

        assert sk == [[1], [2]]
        assert ty == [[1], [2, "CONST"]]
        assert sk_addr == [(0, [1]), (4, [2])]
        assert ty_addr == [(0, [1]), (4, [2, "CONST"])]

    def test_collect_negative_offset_clamped_to_zero(self):
        instrs = [
            MockMLILInstruction(operation=1, address=0x900, operands=[]),
        ]
        a = self._make_analysis(instructions=instrs, start=0x1000)
        _, sk_addr, _, ty_addr = a._collect_mlil_skeleton_and_typed()
        assert sk_addr[0][0] == 0
        assert ty_addr[0][0] == 0

    def test_log_error_records_entry(self):
        a = self._make_analysis()
        a.log_error("boom", "fname", 0x1234, ValueError("x"), "loc")
        assert len(a.errors) == 1
        err = a.errors[0]
        assert err["function_name"] == "fname"
        assert err["function_address"] == "4660"  # hex 0x1234
        assert err["error_location"] == "loc"
        assert err["error_message"] == "boom"
        assert err["error_type"] == "ValueError"
        assert "timestamp" in err

    @patch(
        "redb.extractors.decompiler.bninja.analysis.medium_level.MinHasher"
    )
    def test_analyze_returns_expected_keys(self, mock_minhasher):
        mock_minhasher.return_value.calculateMinHash.return_value = [1, 2, 3]

        instrs = [
            MockMLILInstruction(operation=1, address=0x1000, operands=[]),
            MockMLILInstruction(operation=2, address=0x1004, operands=[42]),
            MockMLILInstruction(operation=3, address=0x1008, operands=[]),
        ]
        a = self._make_analysis(instructions=instrs, start=0x1000)
        result, errors = a.analyze()

        expected_keys = {
            "function_address",
            "body_mlil_skeleton_vector",
            "sha256_mlil_skeleton",
            "tlsh_mlil_skeleton",
            "minhash_mlil_skeleton",
            "body_mlil_typed_vector",
            "sha256_mlil_typed",
            "tlsh_mlil_typed",
            "minhash_mlil_typed",
        }
        assert set(result.keys()) == expected_keys
        assert result["function_address"] == 0x1000
        assert result["minhash_mlil_skeleton"] == [1, 2, 3]
        assert result["minhash_mlil_typed"] == [1, 2, 3]
        assert errors == []

    @patch(
        "redb.extractors.decompiler.bninja.analysis.medium_level.MinHasher"
    )
    def test_analyze_empty_mlil(self, mock_minhasher):
        mock_minhasher.return_value.calculateMinHash.return_value = []
        a = self._make_analysis(mlil=False)
        result, errors = a.analyze()
        assert result["body_mlil_skeleton_vector"] == []
        assert result["body_mlil_typed_vector"] == []
        assert errors == []

    @patch(
        "redb.extractors.decompiler.bninja.analysis.medium_level.MinHasher"
    )
    def test_analyze_sha256_differs_skeleton_vs_typed(self, mock_minhasher):
        mock_minhasher.return_value.calculateMinHash.return_value = []

        instrs = [
            MockMLILInstruction(operation=1, address=0x1000, operands=[42]),
            MockMLILInstruction(operation=2, address=0x1004, operands=["foo"]),
            MockMLILInstruction(operation=3, address=0x1008, operands=[True]),
        ]
        a = self._make_analysis(instructions=instrs)
        result, _ = a.analyze()
        # skeleton ignores operand leaves, typed includes them -> different hashes
        assert result["sha256_mlil_skeleton"] != result["sha256_mlil_typed"]


class TestMinHasherMLILKinds:
    def _make_func(self, instrs):
        # MinHasher iterates basic_blocks then over each block
        block = MagicMock()
        block.__iter__ = lambda self_: iter(instrs)
        f = MagicMock()
        f.basic_blocks = [block]
        return f

    def test_mlil_skeleton_uses_medium_normalizer(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import (
            MinHasher, TokenKind,
        )
        instrs = [
            MockMLILInstruction(operation=i, operands=[]) for i in range(5)
        ]
        func = self._make_func(instrs)
        hasher = MinHasher(seed=42, il_function=func, kind=TokenKind.MLIL)
        result = hasher.calculateMinHash()
        # 5 instructions -> 3 trigrams -> non-empty signature
        assert result != []

    def test_typed_mlil_differs_from_skeleton(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import (
            MinHasher, TokenKind,
        )
        instrs = [
            MockMLILInstruction(operation=1, operands=[42]),
            MockMLILInstruction(operation=2, operands=["s"]),
            MockMLILInstruction(operation=3, operands=[True]),
            MockMLILInstruction(operation=4, operands=[1.5]),
        ]
        func = self._make_func(instrs)
        skel = MinHasher(seed=42, il_function=func, kind=TokenKind.MLIL).calculateMinHash()
        typed = MinHasher(seed=42, il_function=func, kind=TokenKind.TYPED_MLIL).calculateMinHash()
        # Same seed, same instructions, but typed has extra leaf tokens
        # -> hashes should generally differ
        assert skel != typed

    def test_mlil_too_few_instructions(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import (
            MinHasher, TokenKind,
        )
        instrs = [MockMLILInstruction(operation=1, operands=[])] * 2
        func = self._make_func(instrs)
        hasher = MinHasher(seed=42, il_function=func, kind=TokenKind.MLIL)
        assert hasher.calculateMinHash() == []

    def test_unsupported_kind_raises(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import MinHasher
        func = self._make_func([])
        hasher = MinHasher(seed=42, il_function=func, kind="bogus")
        with pytest.raises(ValueError):
            hasher.calculateMinHash()