Ihor Kulyniak

14 papers Misc 2Journal 2Unranked 10
YearRankTypeTitle / Venue / Authors
2025 J jnl
J. Internet Serv. Inf. Secur.
Marta Sarvas, Solomiya Ohinok, Ihor Kulyniak, Ivanna Havrylyuk
2024 J jnl
J. Internet Serv. Inf. Secur.
Yurii Dziurakh, Ihor Kulyniak, Hanna Sarkisian, Ivan Zhygalo, Bohdan Chepil, Khrystyna Vaskovych
2023 conf
COLINS (3)
Oleh Karyy, Ihor Novakivskyi, Yaroslav Kis, Ihor Kulyniak, Alexander Adamovsky
2023 conf
MoMLeT+DS
Nestor Shpak, Ihor Novakivskyi, Ihor Kulyniak, Viktoriya Kharchuk, Ihor Oleksiv
2023 conf
COLINS (3)
Nestor Shpak, Rafal Rebilas, Ihor Kulyniak, Roman Shulyar, Natalia Horbal
2022 Misc conf
CSIT
Ihor Kulyniak, Ihor Novakivskyi, Oleh Karyy, Liubov Halkiv, Solomiya Ohinok
2022 conf
COLINS
Liubov Halkiv, Oleh Karyy, Ihor Kulyniak, Yaroslav Kis, Alexander Adamovsky
2022 Misc conf
CSIT
Ihor Novakivskyi, Ihor Kulyniak, Yuliya Bondarenko, Yurii Dziurakh, Halyna Rachynska
2021 conf
ACIT
Oleh Karyy, Ihor Kulyniak, Natalya Struchok, Liubov Halkiv, Solomiya Ohinok
2021 conf
ACIT
Liubov Halkiv, Ihor Kulyniak, Nataliia Shevchuk, Liudmyla Kucher, Tetiana Horbenko
2021 conf
COLINS
Liubov Halkiv, Oleh Karyy, Ihor Kulyniak, Yaroslav Kis, Anastasiia Tsapulych
2020 conf
DSMP
Liubov Halkiv, Oleh Karyy, Ihor Kulyniak, Solomiya Ohinok
2020 conf
DSMP (Selected Papers)
Liubov Halkiv, Oleh Karyy, Ihor Kulyniak, Solomiya Ohinok
2020 conf
ISDMCI
Ihor Kulyniak, Solomiya Ohinok, Halyna Rachynska
tests/unit/test_decompile_strings.py
← Index tests/unit/test_decompile_strings.py python
"""Unit tests for bninja/analysis/strings.py — StringAnalysis."""
import pytest
import math
from unittest.mock import MagicMock


# StringAnalysis has no binaryninja imports, just collections and math
from redb.extractors.decompiler.bninja.analysis.strings import StringAnalysis


# ============================================================================
# Helper mocks
# ============================================================================

class MockStringEntry:
    """Mock for a Binary Ninja string reference."""
    def __init__(self, value, raw=None, start=0, length=0, type_name="Utf8String"):
        self.value = value
        self.raw = raw if raw is not None else (value.encode("utf-8") if isinstance(value, str) else value)
        self.start = start
        self.length = length if length else len(self.raw)
        self.type = MagicMock()
        self.type.name = type_name


class MockBinaryView:
    """Mock binary view with a strings list."""
    def __init__(self, strings=None):
        self.strings = strings or []


# ============================================================================
# 6a. StringAnalysis
# ============================================================================


class TestStringAnalysisEntropy:
    def setup_method(self):
        self.sa = StringAnalysis(bv=MockBinaryView(), functions=[])

    def test_entropy_empty_string(self):
        assert self.sa.entropy("") == 0.0

    def test_entropy_single_char(self):
        assert self.sa.entropy("aaaa") == 0.0

    def test_entropy_uniform_distribution(self):
        # "abcd" -> 4 unique chars, each p=1/4, entropy = log2(4) = 2.0
        result = self.sa.entropy("abcd")
        assert result == pytest.approx(2.0)

    def test_entropy_binary_string(self):
        # "ab" -> 2 unique chars, each p=1/2, entropy = log2(2) = 1.0
        result = self.sa.entropy("ab")
        assert result == pytest.approx(1.0)


class TestStringAnalysisAnalyze:
    def test_analyze_deduplication(self):
        """Duplicate (string, encoding) pairs -> only first kept."""
        entries = [
            MockStringEntry("hello", start=100, type_name="Utf8String"),
            MockStringEntry("hello", start=200, type_name="Utf8String"),
        ]
        bv = MockBinaryView(strings=entries)
        sa = StringAnalysis(bv=bv, functions=[])
        result = sa.analyze()
        assert len(result) == 1
        assert result[0]["string_offset"] == 100

    def test_analyze_sorted_by_address(self):
        """First occurrence (lowest offset) is the one kept."""
        entries = [
            MockStringEntry("world", start=500, type_name="Utf8String"),
            MockStringEntry("world", start=100, type_name="Utf8String"),
        ]
        bv = MockBinaryView(strings=entries)
        sa = StringAnalysis(bv=bv, functions=[])
        result = sa.analyze()
        assert len(result) == 1
        # The analyze() sorts by start, so 100 comes first
        assert result[0]["string_offset"] == 100

    def test_analyze_empty_bv(self):
        bv = MockBinaryView(strings=[])
        sa = StringAnalysis(bv=bv, functions=[])
        result = sa.analyze()
        assert result == []

    def test_analyze_output_schema(self):
        entries = [MockStringEntry("test_string", start=0, type_name="Utf8String")]
        bv = MockBinaryView(strings=entries)
        sa = StringAnalysis(bv=bv, functions=[])
        result = sa.analyze()
        assert len(result) == 1
        r = result[0]
        required_keys = [
            "string",
            "string_raw",
            "string_encoding",
            "string_offset",
            "string_length",
            "string_raw_length",
            "string_entropy",
        ]
        for key in required_keys:
            assert key in r, f"Missing key: {key}"