Ian K. T. Tan

33 papers B 1C 3Journal 9Unranked 20
YearRankTypeTitle / Venue / Authors
2026 C conf
ICPRAM
Ian K. T. Tan, Zhen Hao Wee
2026 J jnl
Int. J. Comput. Intell. Syst.
Wing Kin Chong, Hu Ng, Timothy Tzen Vun Yap, Ian K. T. Tan, Vik Tor Goh, Lai Kuan Wong, Dong Theng Cher
2025 conf
ICCMS
Samsuddin Samsuddin Wira, Chee Keong Tan, Wai Peng Wong, Ian K. T. Tan
2025 J jnl
J. Supercomput.
Zi Hau Chin, Vishnu Monn Baskaran, Chee Keong Tan, Ian K. T. Tan, Timothy Tzen Vun Yap
2025 J jnl
Quantum Inf. Process.
Yong Qing Tiong, Kai Lin Ong, Ian K. T. Tan
2024 J jnl
J. Supercomput.
Yun Fen Yong, Chee Keong Tan, Ian K. T. Tan, Su Wei Tan
2024 J jnl
J. Ambient Intell. Humaniz. Comput.
Yun Fen Yong, Chee Keong Tan, Ian K. T. Tan, Su Wei Tan
2024 conf
CSAI
Pei Yee Liew, Ian K. T. Tan
2023 conf
CSAI
Wei Yuen Teh, Chern Hong Lim, Mei Kuan Lim, Ian K. T. Tan
2022 conf
ISPACS
Calvin Yap, KokSheik Wong, Ganesh Krishnasamy, Ian K. T. Tan
2022 B conf
EDM
Jih Soong Tan, Ian K. T. Tan, Lay-Ki Soon, Huey Fang Ong
2022 conf
ISPACS
Wei Yuen Teh, Ian K. T. Tan, Heng Kiat Tan
2022 conf
ISCIT
Yun Fen Yong, Chee Keong Tan, Ian K. T. Tan, Su Wei Tan
2022 C conf
ICPRAM
Jia-Ming Low, Ian K. T. Tan, Chern Hong Lim
2022 conf
ISPACS
Wei Yuen Teh, Ian K. T. Tan
2021 conf
MIWAI
Jih Soong Tan, Ian K. T. Tan
2021 C conf
IPCCC
Yun Fen Yong, Chee Keong Tan, Ian K. T. Tan
2020 conf
ACeS
Zi Hau Chin, Timothy Tzen Vun Yap, Ian K. T. Tan
2020 conf
BSCI
Zi Hau Chin, Timothy Tzen Vun Yap, Ian K. T. Tan
2019 conf
MIWAI
Cheng Yang Lim, Ian K. T. Tan, Bhawani Selvaretnam
2019 conf
ICME Workshops
Clarence Weihan Cheong, Ryan Woei-Sheng Lim, John See, Lai-Kuan Wong, Ian K. T. Tan
2019 conf
MIWAI
Jia-Ming Low, Ian K. T. Tan, Choo-Yee Ting
2019 J jnl
Comput. Electr. Eng.
Md. Mahedi Hassan, Ian K. T. Tan, Bhawani Selvaretnam, Poo Kuan Hoong
2018 conf
MMM (2)
Clarence Weihan Cheong, Ryan Woei-Sheng Lim, John See, Lai-Kuan Wong, Ian K. T. Tan, Azrin Aris
2017 conf
ICSIPA
Ryan Woei-Sheng Lim, Clarence Weihan Cheong, John See, Ian K. T. Tan, Lai-Kuan Wong, Huai-Qian Khor
2015 conf
IVIC
Ian K. T. Tan, Poo Kuan Hoong, Chin Hong Yap
2014 conf
PCM
Boon Yaik Ooi, Chee Siang Wong, Ian K. T. Tan, Chee Keong Lee
2014 conf
FCC
Ian K. T. Tan, Poo Kuan Hoong, Chee Ken Hong, Low Zhi Wen
2013 J jnl
Comput. Electr. Eng.
Ian K. T. Tan, Ian Chai, Poo Kuan Hoong
2012 J jnl
CoRR
Poo Kuan Hoong, Ian K. T. Tan, Chee Yik Keong
2012 conf
ICWCA
Alireza Beikverdi, Ian K. T. Tan
2012 conf
ICWCA
Poo Kuan Hoong, Ian K. T. Tan, Ong Kok Chien, Choo-Yee Ting
2008 J jnl
ACM SIGOPS Oper. Syst. Rev.
Chee Siang Wong, Ian K. T. Tan, Rosalind Deena Kumari, Fun Wey
tests/unit/test_apk_method_extractor.py
← Index tests/unit/test_apk_method_extractor.py python
"""
Unit tests for APK method-level content extraction, hashing, and similarity.

Tests SHA-256 normalization, ssdeep/TLSH computation, obfuscation detection,
and Dalvik-to-Java type conversion.
"""
import pytest

pytestmark = [pytest.mark.unit, pytest.mark.apk, pytest.mark.decompile]


class TestHashingFunctions:
    """Tests for hashing utility functions."""

    def test_sha256_deterministic(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_sha256
        h1 = compute_sha256("invoke-virtual {p0}, Lcom/Foo;->bar()V")
        h2 = compute_sha256("invoke-virtual {p0}, Lcom/Foo;->bar()V")
        assert h1 == h2

    def test_sha256_hex_length(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_sha256
        assert len(compute_sha256("test")) == 64

    def test_sha256_different_inputs(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_sha256
        assert compute_sha256("aaa") != compute_sha256("bbb")

    def test_ssdeep_none_for_short(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_ssdeep
        assert compute_ssdeep("short") is None

    def test_tlsh_none_for_short(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_tlsh
        assert compute_tlsh("x") is None


class TestObfuscationDetection:
    """Tests for obfuscation indicator detection."""

    def test_short_method_name_single_char(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        r = detect_obfuscation_indicators("a", "Lcom/Foo;", "", 10)
        assert r["short_method_name"] is True

    def test_short_method_name_two_chars(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        r = detect_obfuscation_indicators("ab", "Lcom/Foo;", "", 10)
        assert r["short_method_name"] is True

    def test_normal_method_name(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        r = detect_obfuscation_indicators("onCreate", "Lcom/Foo;", "", 10)
        assert r["short_method_name"] is False

    def test_short_class_name(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        r = detect_obfuscation_indicators("foo", "Lcom/a;", "", 10)
        assert r["short_class_name"] is True

    def test_normal_class_name(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        r = detect_obfuscation_indicators("foo", "Lcom/example/MainActivity;", "", 10)
        assert r["short_class_name"] is False

    def test_string_encryption_detected(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = (
            'const-string v0, "xyz"\n'
            'invoke-static {v0}, Lcom/Enc;->decrypt(Ljava/lang/String;)Ljava/lang/String;\n'
        )
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 10)
        assert r["has_string_encryption"] is True

    def test_no_string_encryption(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = 'const-string v0, "hello"\ninvoke-virtual {v0}, Ljava/lang/String;->length()I'
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 10)
        assert r["has_string_encryption"] is False

    def test_reflection_detected(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = 'invoke-virtual {v0, v1}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;'
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 10)
        assert r["has_reflection_calls"] is True

    def test_no_reflection(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = 'invoke-virtual {p0}, Lcom/Foo;->bar()V'
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 10)
        assert r["has_reflection_calls"] is False

    def test_excessive_goto_detected(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "\n".join(["goto :label"] * 10)
        # threshold = max(5, 20*0.15=3) = 5, 10 > 5
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 20)
        assert r["excessive_goto_count"] is True

    def test_no_excessive_goto(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "goto :label\nreturn-void"
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 100)
        assert r["excessive_goto_count"] is False

    def test_goto_16_counted(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "\n".join(["goto/16 :label"] * 10)
        r = detect_obfuscation_indicators("m", "Lcom/Foo;", smali, 20)
        assert r["excessive_goto_count"] is True


class TestDalvikTypeConversion:
    """Tests for Dalvik-to-Java type conversion."""

    def test_void(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_type_to_java
        assert dalvik_type_to_java("V") == "void"

    def test_primitives(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_type_to_java
        assert dalvik_type_to_java("I") == "int"
        assert dalvik_type_to_java("Z") == "boolean"
        assert dalvik_type_to_java("J") == "long"
        assert dalvik_type_to_java("F") == "float"
        assert dalvik_type_to_java("D") == "double"
        assert dalvik_type_to_java("B") == "byte"
        assert dalvik_type_to_java("S") == "short"
        assert dalvik_type_to_java("C") == "char"

    def test_object_type(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_type_to_java
        assert dalvik_type_to_java("Ljava/lang/String;") == "String"
        assert dalvik_type_to_java("Lcom/example/Foo;") == "Foo"

    def test_array_type(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_type_to_java
        assert dalvik_type_to_java("[I") == "int[]"
        assert dalvik_type_to_java("[Ljava/lang/String;") == "String[]"

    def test_empty_returns_void(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_type_to_java
        assert dalvik_type_to_java("") == "void"


class TestJavaPrototypeConversion:
    """Tests for method signature to Java prototype conversion."""

    def test_simple_method(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        assert dalvik_to_java_prototype("foo", "()V") == "void foo()"

    def test_method_with_params(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        result = dalvik_to_java_prototype("bar", "(ILjava/lang/String;)Z")
        assert result == "boolean bar(int, String)"

    def test_method_returning_object(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        result = dalvik_to_java_prototype("create", "()Lcom/example/Foo;")
        assert result == "Foo create()"

    def test_empty_signature(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        result = dalvik_to_java_prototype("m", "")
        assert "m()" in result


class TestDalvikParamParsing:
    """Tests for parsing Dalvik parameter descriptors."""

    def test_empty(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        assert _parse_dalvik_params("") == []

    def test_single_primitive(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        assert _parse_dalvik_params("I") == ["I"]

    def test_multiple_primitives(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        assert _parse_dalvik_params("IZJ") == ["I", "Z", "J"]

    def test_single_object(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        assert _parse_dalvik_params("Ljava/lang/String;") == ["Ljava/lang/String;"]

    def test_mixed(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("ILjava/lang/String;Z")
        assert result == ["I", "Ljava/lang/String;", "Z"]

    def test_arrays(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("[I[Ljava/lang/String;")
        assert result == ["[I", "[Ljava/lang/String;"]

    def test_two_objects(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("Landroid/os/Bundle;Ljava/lang/String;")
        assert len(result) == 2