summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2024-06-14 12:20:46 -0400
committerMason Reed <mason@vector35.com>2024-06-14 12:20:46 -0400
commit3c58f74fe8e8bb9029cfe560a836303a2ce3bbdb (patch)
tree8566be9997805944141e3c745c26fdbe4bc07b3e
parentf4eb81635006d8bbfe1a4a7550d62ae3163117a3 (diff)
Delete unmaintained test suite
-rw-r--r--suite/api_test.py3565
m---------suite/binaries0
-rwxr-xr-xsuite/generator.py471
-rw-r--r--suite/pwnadventurez.nesbin262160 -> 0 bytes
-rw-r--r--suite/testcommon.py2306
-rwxr-xr-xsuite/unit_api.py27
6 files changed, 0 insertions, 6369 deletions
diff --git a/suite/api_test.py b/suite/api_test.py
deleted file mode 100644
index 7054008a..00000000
--- a/suite/api_test.py
+++ /dev/null
@@ -1,3565 +0,0 @@
-import unittest
-import os
-
-import binaryninja as bn
-from binaryninja.binaryview import BinaryView, BinaryViewType
-from binaryninja.settings import Settings, SettingsScope
-from binaryninja.metadata import Metadata
-from binaryninja.demangle import demangle_gnu3, demangle_ms, get_qualified_name
-from binaryninja.architecture import Architecture
-from binaryninja.pluginmanager import RepositoryManager
-from binaryninja.platform import Platform
-from binaryninja.enums import (
- StructureVariant, NamedTypeReferenceClass, MemberAccess, MemberScope, ReferenceType, VariableSourceType,
- SymbolBinding, SymbolType, TokenEscapingType, InstructionTextTokenType, TypeDefinitionLineType
-)
-
-from binaryninja.types import (
- QualifiedName, Type, TypeBuilder, EnumerationMember, FunctionParameter, OffsetWithConfidence, BoolWithConfidence,
- EnumerationBuilder, NamedTypeReferenceBuilder, StructureBuilder, StructureMember, IntegerType, StructureType,
- Symbol, NameSpace, MutableTypeBuilder, NamedTypeReferenceType, QualifiedNameType, TypeDefinitionLine
-)
-from binaryninja.architecture import *
-from binaryninja.function import *
-from binaryninja.basicblock import *
-from binaryninja.binaryview import *
-from binaryninja.lowlevelil import *
-from binaryninja.mediumlevelil import *
-from binaryninja.highlevelil import *
-from binaryninja.variable import *
-from binaryninja.typecontainer import *
-from binaryninja.typeparser import *
-from binaryninja.typeprinter import *
-import zipfile
-from flaky import flaky
-
-
-class FileApparatus:
- test_store = "binaries/test_corpus"
-
- def __init__(self, filename):
- self.filename = filename
- if not os.path.exists(self.path):
- with zipfile.ZipFile(self.path + ".zip", "r") as zf:
- zf.extractall(path=os.path.dirname(__file__))
- assert os.path.exists(self.path)
-
- @property
- def path(self) -> str:
- return os.path.join(os.path.dirname(__file__), self.test_store, self.filename)
-
- def __del__(self):
- if os.path.exists(self.path):
- os.unlink(self.path)
-
- def __enter__(self):
- return self.path
-
- def __exit__(self, type, value, traceback):
- pass
-
-class Apparatus:
- def __init__(self, filename):
- with FileApparatus(filename) as path:
- bv = bn.load(os.path.relpath(path))
- assert bv is not None
- self.bv = bv
-
- def __del__(self):
- self.bv.file.close()
-
- def __enter__(self):
- return self.bv
-
- def __exit__(self, type, value, traceback):
- pass
-
-
-class TestWithBinaryView(unittest.TestCase):
- file_name = "helloworld"
-
- def setUp(self):
- self.apparatus = Apparatus(self.file_name)
- self.bv: BinaryView = self.apparatus.bv
- self.arch: Architecture = self.bv.arch
- self.plat: Platform = self.bv.platform
-
-
-class SettingsAPI(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- pass
-
- @classmethod
- def tearDownClass(cls):
- pass
-
- def test_settings_create(self):
- s1 = Settings()
- s2 = Settings(None)
- s3 = Settings("default")
- s4 = Settings("test")
- assert s1 == s2, "test_settings_create failed"
- assert s1 == s3, "test_settings_create failed"
- assert s1 != s4, "test_settings_create failed"
-
- def test_settings_defaults(self):
- settings = Settings()
- assert settings.contains("analysis.linearSweep.autorun"), "test_settings_defaults failed"
- assert settings.contains("analysis.unicode.blocks"), "test_settings_defaults failed"
- assert settings.contains("network.downloadProviderName"), "test_settings_defaults failed"
- assert settings.get_bool_with_scope("analysis.linearSweep.autorun", scope=SettingsScope.SettingsDefaultScope
- )[0], "test_settings_defaults failed"
- assert settings.get_bool_with_scope("analysis.linearSweep.autorun", scope=SettingsScope.SettingsDefaultScope
- )[1] == SettingsScope.SettingsDefaultScope, "test_settings_defaults failed"
-
- def test_settings_registration(self):
- settings = Settings("test")
- assert not settings.contains("testGroup.testSetting"), "test_settings_registration failed"
- assert settings.register_group("testGroup", "Title"), "test_settings_registration failed"
- assert settings.register_setting(
- "testGroup.testSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "boolean", "id" : "testSetting"}'
- ), "test_settings_registration failed"
- assert settings.contains("testGroup.testSetting"), "test_settings_registration failed"
-
- def test_settings_usage(self):
- settings = Settings("test")
- assert not settings.contains("testGroup.testSetting"), "test_settings_types failed"
- assert settings.register_group("testGroup", "Title"), "test_settings_types failed"
- assert not settings.register_setting(
- "testGroup.boolSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : 500, "type" : "boolean", "id" : "boolSetting"}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.boolSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "boolean", "id" : "boolSetting"}'
- ), "test_settings_types failed"
- assert not settings.register_setting(
- "testGroup.doubleSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "number", "id" : "doubleSetting"}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.doubleSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : 500, "type" : "number", "id" : "doubleSetting"}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.integerSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : 500, "type" : "number", "id" : "integerSetting"}'
- ), "test_settings_types failed"
- assert not settings.register_setting(
- "testGroup.stringSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : 500, "type" : "string", "id" : "stringSetting"}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.stringSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : "value", "type" : "string", "id" : "stringSetting"}'
- ), "test_settings_types failed"
- assert not settings.register_setting(
- "testGroup.stringListSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "array", "elementType" : "string", "id" : "stringListSetting"}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.stringListSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : ["value1", "value2"], "type" : "array", "elementType" : "string", "id" : "stringListSetting"}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.ignoreResourceBoolSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "boolean", "id" : "boolSetting", "ignore" : ["SettingsResourceScope"]}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.ignoreUserBoolSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "boolean", "id" : "boolSetting", "ignore" : ["SettingsUserScope"]}'
- ), "test_settings_types failed"
- assert settings.register_setting(
- "testGroup.readOnlyBoolSetting",
- '{"description" : "Test description.", "title" : "Test Title", "default" : true, "type" : "boolean", "id" : "boolSetting", "ignore" : ["SettingsResourceScope", "SettingsUserScope"]}'
- ), "test_settings_types failed"
-
- assert settings.contains("testGroup.boolSetting"), "test_settings_types failed"
- assert settings.contains("testGroup.doubleSetting"), "test_settings_types failed"
- assert settings.contains("testGroup.integerSetting"), "test_settings_types failed"
- assert settings.contains("testGroup.stringSetting"), "test_settings_types failed"
- assert settings.contains("testGroup.stringListSetting"), "test_settings_types failed"
-
- assert settings.get_bool("testGroup.boolSetting") == True, "test_settings_types failed"
- assert settings.get_double("testGroup.doubleSetting") == 500, "test_settings_types failed"
- assert settings.get_integer("testGroup.integerSetting") == 500, "test_settings_types failed"
- assert settings.get_string("testGroup.stringSetting") == "value", "test_settings_types failed"
- assert settings.get_string_list("testGroup.stringListSetting") == [
- "value1", "value2"
- ], "test_settings_types failed"
-
- assert settings.set_bool("testGroup.boolSetting", False), "test_settings_types failed"
- assert settings.set_double("testGroup.doubleSetting", 700), "test_settings_types failed"
- assert settings.set_integer("testGroup.integerSetting", 700), "test_settings_types failed"
- assert settings.set_string("testGroup.stringSetting", "value_user"), "test_settings_types failed"
- assert settings.set_string_list(
- "testGroup.stringListSetting", ["value3", "value4"]
- ), "test_settings_types failed"
-
- assert settings.get_bool("testGroup.boolSetting") == False, "test_settings_types failed"
- assert settings.get_double("testGroup.doubleSetting") == 700, "test_settings_types failed"
- assert settings.get_integer("testGroup.integerSetting") == 700, "test_settings_types failed"
- assert settings.get_string("testGroup.stringSetting") == "value_user", "test_settings_types failed"
- assert settings.get_string_list("testGroup.stringListSetting") == [
- "value3", "value4"
- ], "test_settings_types failed"
-
- assert settings.get_bool_with_scope("testGroup.boolSetting", scope=SettingsScope.SettingsDefaultScope
- )[0] == True, "test_settings_types failed"
- assert settings.get_double_with_scope("testGroup.doubleSetting", scope=SettingsScope.SettingsDefaultScope
- )[0] == 500, "test_settings_types failed"
- assert settings.get_integer_with_scope("testGroup.integerSetting", scope=SettingsScope.SettingsDefaultScope
- )[0] == 500, "test_settings_types failed"
- assert settings.get_string_with_scope("testGroup.stringSetting", scope=SettingsScope.SettingsDefaultScope
- )[0] == "value", "test_settings_types failed"
- assert settings.get_string_list_with_scope(
- "testGroup.stringListSetting", scope=SettingsScope.SettingsDefaultScope
- )[0] == ["value1", "value2"], "test_settings_types failed"
-
- assert settings.get_bool_with_scope("testGroup.boolSetting", scope=SettingsScope.SettingsUserScope
- )[0] == False, "test_settings_types failed"
- assert settings.get_double_with_scope("testGroup.doubleSetting", scope=SettingsScope.SettingsUserScope
- )[0] == 700, "test_settings_types failed"
- assert settings.get_integer_with_scope("testGroup.integerSetting", scope=SettingsScope.SettingsUserScope
- )[0] == 700, "test_settings_types failed"
- assert settings.get_string_with_scope("testGroup.stringSetting", scope=SettingsScope.SettingsUserScope
- )[0] == "value_user", "test_settings_types failed"
- assert settings.get_string_list_with_scope(
- "testGroup.stringListSetting", scope=SettingsScope.SettingsUserScope
- )[0] == ["value3", "value4"], "test_settings_types failed"
-
- raw_view = BinaryView.new(b'0x55')
- assert not settings.set_bool(
- "testGroup.ignoreResourceBoolSetting", False, scope=SettingsScope.SettingsDefaultScope
- ), "test_settings_types failed"
- assert not settings.set_bool(
- "testGroup.ignoreResourceBoolSetting", False, scope=SettingsScope.SettingsResourceScope
- ), "test_settings_types failed"
- assert not settings.set_bool(
- "testGroup.ignoreResourceBoolSetting", False, raw_view, scope=SettingsScope.SettingsResourceScope
- ), "test_settings_types failed"
- assert settings.set_bool(
- "testGroup.ignoreResourceBoolSetting", False, scope=SettingsScope.SettingsUserScope
- ), "test_settings_types failed"
- assert not settings.set_bool("testGroup.ignoreUserBoolSetting", False), "test_settings_types failed"
- assert settings.set_bool("testGroup.ignoreUserBoolSetting", False, raw_view), "test_settings_types failed"
- assert settings.set_bool(
- "testGroup.ignoreUserBoolSetting", False, raw_view, scope=SettingsScope.SettingsResourceScope
- ), "test_settings_types failed"
- assert not settings.set_bool("testGroup.readOnlyBoolSetting", False), "test_settings_types failed"
- assert not settings.set_bool(
- "testGroup.readOnlyBoolSetting", False, scope=SettingsScope.SettingsResourceScope
- ), "test_settings_types failed"
- assert not settings.set_bool(
- "testGroup.readOnlyBoolSetting", False, scope=SettingsScope.SettingsUserScope
- ), "test_settings_types failed"
-
- s2 = Settings("test2")
- assert s2.serialize_schema() == "", "test_settings_types failed"
- test_schema = settings.serialize_schema()
- assert test_schema != "", "test_settings_types failed"
- assert s2.deserialize_schema(test_schema), "test_settings_types failed"
-
- assert s2.get_bool("testGroup.boolSetting") == True, "test_settings_types failed"
- assert s2.get_double("testGroup.doubleSetting") == 500, "test_settings_types failed"
- assert s2.get_integer("testGroup.integerSetting") == 500, "test_settings_types failed"
- assert s2.get_string("testGroup.stringSetting") == "value", "test_settings_types failed"
- assert s2.get_string_list("testGroup.stringListSetting") == ["value1", "value2"], "test_settings_types failed"
-
- assert s2.deserialize_settings(
- settings.serialize_settings(scope=SettingsScope.SettingsUserScope), raw_view,
- SettingsScope.SettingsResourceScope
- ), "test_settings_types failed"
- assert s2.get_bool("testGroup.boolSetting", raw_view) == False, "test_settings_types failed"
- assert s2.get_double("testGroup.doubleSetting", raw_view) == 700, "test_settings_types failed"
- assert s2.get_integer("testGroup.integerSetting", raw_view) == 700, "test_settings_types failed"
- assert s2.get_string("testGroup.stringSetting", raw_view) == "value_user", "test_settings_types failed"
- assert s2.get_string_list("testGroup.stringListSetting",
- raw_view) == ["value3", "value4"], "test_settings_types failed"
-
- assert s2.reset_all(), "test_settings_types failed"
- assert s2.get_bool("testGroup.boolSetting") == True, "test_settings_types failed"
- assert s2.get_double("testGroup.doubleSetting") == 500, "test_settings_types failed"
- assert s2.get_integer("testGroup.integerSetting") == 500, "test_settings_types failed"
- assert s2.get_string("testGroup.stringSetting") == "value", "test_settings_types failed"
- assert s2.get_string_list("testGroup.stringListSetting") == ["value1", "value2"], "test_settings_types failed"
-
- s3 = Settings("test3")
- assert s3.deserialize_schema(test_schema, SettingsScope.SettingsResourceScope)
- assert not s3.contains("testGroup.ignoreResourceBoolSetting"), "test_settings_types failed"
- assert s3.contains("testGroup.ignoreUserBoolSetting"), "test_settings_types failed"
- assert not s3.contains("testGroup.readOnlyBoolSetting"), "test_settings_types failed"
-
- assert s3.deserialize_schema(test_schema, SettingsScope.SettingsUserScope, False)
- assert s3.contains("testGroup.ignoreResourceBoolSetting"), "test_settings_types failed"
- assert not s3.contains("testGroup.ignoreUserBoolSetting"), "test_settings_types failed"
- assert not s3.contains("testGroup.readOnlyBoolSetting"), "test_settings_types failed"
-
- assert s3.deserialize_schema(test_schema, SettingsScope.SettingsUserScope, False)
- assert s3.deserialize_schema(s3.serialize_schema(), SettingsScope.SettingsResourceScope, False)
- assert not s3.contains("testGroup.ignoreResourceBoolSetting"), "test_settings_types failed"
- assert not s3.contains("testGroup.ignoreUserBoolSetting"), "test_settings_types failed"
- assert not s3.contains("testGroup.readOnlyBoolSetting"), "test_settings_types failed"
-
- def test_load_settings(self):
- bvt_name = "Mapped (Python)" if "Mapped (Python)" in map(
- lambda bvt: bvt.name, list(BinaryViewType)
- ) else "Mapped"
- raw_view = BinaryView.new(b'0x55')
- assert raw_view.view_type == "Raw", "test_load_settings failed"
- mapped_view = BinaryViewType[bvt_name].create(raw_view)
- assert mapped_view.view_type == bvt_name, "test_load_settings failed"
- assert mapped_view.segments[0].start == 0, "test_load_settings failed"
- assert len(mapped_view) == 4, "test_load_settings failed"
- load_settings = BinaryViewType[bvt_name].get_load_settings_for_data(raw_view)
- assert load_settings is not None, "test_load_settings failed"
- assert load_settings.contains("loader.architecture"), "test_load_settings failed"
- assert load_settings.contains("loader.platform"), "test_load_settings failed"
- assert load_settings.contains("loader.imageBase"), "test_load_settings failed"
- assert load_settings.contains("loader.entryPointOffset"), "test_load_settings failed"
- load_settings.set_string("loader.architecture", 'x86_64')
- load_settings.set_integer("loader.imageBase", 0x500000)
- load_settings.set_integer("loader.entryPointOffset", 0)
- raw_view.set_load_settings(bvt_name, load_settings)
- mapped_view = BinaryViewType[bvt_name].create(raw_view)
- assert mapped_view.view_type == bvt_name, "test_load_settings failed"
- assert mapped_view.segments[0].start == 0x500000, "test_load_settings failed"
- assert len(mapped_view) == 4, "test_load_settings failed"
- assert raw_view.get_load_settings(bvt_name) == load_settings
- raw_view.set_load_settings(bvt_name, None)
- assert raw_view.get_load_settings(bvt_name) is None
-
-
-class MetaddataAPI(TestWithBinaryView):
- def test_metadata_basic_types(self):
- # Core is tested thoroughly through the C++ unit tests here we focus on the python api side
- md = Metadata(1)
- assert md.is_integer
- assert int(md) == 1
- assert md.value == 1
-
- md = Metadata(-1, signed=True)
- assert md.is_signed_integer
- assert int(md) == -1
- assert md.value == -1
- md = Metadata(1, signed=False)
- assert md.is_unsigned_integer
- assert int(md) == 1
- md = Metadata(3.14)
- assert md.is_float
- assert float(md) == 3.14
- assert md.value == 3.14
-
- md = Metadata("asdf")
- assert md.is_string
- assert str(md) == "asdf"
- assert len(md) == 4
- assert md.value == "asdf"
-
- md = Metadata(b"\x00\x00\x41\x00")
- assert len(md) == 4
- assert bytes(md) == b"\x00\x00\x41\x00"
-
- def test_metadata_compound_types(self):
- md = Metadata([1, 2, 3])
- assert md.is_array
- assert md.value == [1, 2, 3]
- assert len(md) == 3
- assert md[0] == 1
- assert md[1] == 2
- assert md[2] == 3
- assert isinstance(list(md), list)
- md.remove(0)
- assert len(md) == 2
- assert md == [2, 3]
-
- md = Metadata({"a": 1, "b": 2})
- assert md.is_dict
- assert len(md) == 2
- assert md.value == {"a": 1, "b": 2}
- assert md["a"] == 1
- assert md["b"] == 2
- md.remove("a")
- assert len(md) == 1
- assert md == {"b": 2}
-
- def test_metadata_equality(self):
- assert Metadata(1) == 1
- assert Metadata(1) != 0
- assert Metadata(1) == Metadata(1)
- assert Metadata(1) != Metadata(0)
-
- assert Metadata(3.14) == 3.14
- assert Metadata(3.14) == Metadata(3.14)
- assert Metadata(3.14) != 3.1
- assert Metadata(3.14) != Metadata(3.1)
-
- assert Metadata("asdf") == "asdf"
- assert Metadata("asdf") == Metadata("asdf")
- assert Metadata("asdf") != "qwer"
- assert Metadata("asdf") != Metadata("qwer")
-
- assert Metadata(b"as\x00df") == b"as\x00df"
- assert Metadata(b"as\x00df") == Metadata(b"as\x00df")
- assert Metadata(b"as\x00df") != b"qw\x00er"
- assert Metadata(b"as\x00df") != Metadata(b"qw\x00er")
-
- assert Metadata([1, 2, 3]) == [1, 2, 3]
- assert Metadata([1, 2, 3]) == Metadata([1, 2, 3])
- assert Metadata([1, 2, 3]) != [1, 2]
- assert Metadata([1, 2, 3]) != Metadata([1, 2])
-
- assert Metadata({"a": 1, "b": 2}) == {"a": 1, "b": 2}
- assert Metadata({"a": 1, "b": 2}) == Metadata({"a": 1, "b": 2})
- assert Metadata({"a": 1, "b": 2}) != {"a": 1}
- assert Metadata({"a": 1, "b": 2}) != Metadata({"a": 1})
-
- def test_binaryview_storage(self):
- data = b"some bytes\x00\xff\xff\xff\xfe\xff\xcd\xcc"
- self.bv.store_metadata("SomeKey", data)
- assert self.bv.query_metadata("SomeKey") == data
- assert bytes(self.bv.query_metadata("SomeKey")) == data
- self.bv.remove_metadata("SomeKey")
- self.assertRaises(KeyError, lambda: self.bv.query_metadata("SomeKey"))
-
-class DemanglerTest(unittest.TestCase):
- def get_type_string(self, t, n):
- out = ""
- if t is not None:
- out = str(t.get_string_before_name())
- if len(out) > 1 and out[-1] != ' ':
- out += " "
- out += get_qualified_name(n)
- out += str(t.get_string_after_name())
- return out
-
- def test_demangle_ms(self):
- tests = ("??_V@YAPAXI@Z", "??_U@YAPAXI@Z")
-
- oracle = ("void* __cdecl operator delete[](uint32_t)", "void* __cdecl operator new[](uint32_t)")
- for i, test in enumerate(tests):
- t, n = demangle_ms(Architecture['x86'], test)
- result = self.get_type_string(t, n)
- assert result == oracle[i], f"oracle: {oracle[i]}\nresult: {result}"
-
- def test_demangle_gnu3(self):
- tests = (
- "__ZN15BinaryNinjaCore12BinaryReader5Read8Ev", "__ZN5QListIP18QAbstractAnimationE18detach_helper_growEii",
- "__ZN13QStatePrivate22emitPropertiesAssignedEv",
- "__ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI14QItemSelectionLb1EE9ConstructEPvPKv",
- "__ZN18QSharedDataPointerI16QFileInfoPrivateE4dataEv", "__ZN26QAbstractNativeEventFilterD2Ev",
- "__ZN5QListIP14QAbstractStateE3endEv",
- "__ZNK15BinaryNinjaCore19ArchitectureWrapper22GetOpcodeDisplayLengthEv",
- "__ZN15BinaryNinjaCore17ScriptingInstance19SetCurrentSelectionEyy",
- "__ZN12_GLOBAL__N_114TypeDestructor14DestructorImplI11QStringListLb1EE8DestructEiPv",
- "__ZN13QGb18030Codec5_nameEv", "__ZN5QListIP7QObjectE6detachEv",
- "__ZN19QBasicAtomicPointerI9QFreeListI13QMutexPrivateN12_GLOBAL__N_117FreeListConstantsEEE17testAndSetReleaseEPS4_S6_",
- "__ZN12QJsonPrivate6Parser12reserveSpaceEi", "__ZN20QStateMachinePrivate12endMacrostepEb",
- "__ZN14QScopedPointerI20QTemporaryDirPrivate21QScopedPointerDeleterIS0_EED2Ev",
- "__ZN14QVariantIsNullIN12_GLOBAL__N_115CoreTypesFilterEE8delegateI10QMatrix4x4EEbPKT_",
- "__ZN26QAbstractProxyModelPrivateC2Ev",
- "__ZNSt3__110__function6__funcIZ26BNWorkerInteractiveEnqueueE4$_16NS_9allocatorIS2_EEFvvEEclEv"
- )
-
- oracle = (
- "int32_t BinaryNinjaCore::BinaryReader::Read8()",
- "int32_t QList<QAbstractAnimation*>::detach_helper_grow(int32_t, int32_t)",
- "int32_t QStatePrivate::emitPropertiesAssigned()",
- "int32_t QtMetaTypePrivate::QMetaTypeFunctionHelper<QItemSelection, true>::Construct(void*, void const*)",
- "int32_t QSharedDataPointer<QFileInfoPrivate>::data()",
- "void QAbstractNativeEventFilter::~QAbstractNativeEventFilter()", "int32_t QList<QAbstractState*>::end()",
- "int32_t BinaryNinjaCore::ArchitectureWrapper::GetOpcodeDisplayLength() const",
- "int32_t BinaryNinjaCore::ScriptingInstance::SetCurrentSelection(uint64_t, uint64_t)",
- "int32_t (anonymous namespace)::TypeDestructor::DestructorImpl<QStringList, true>::Destruct(int32_t, void*)",
- "int32_t QGb18030Codec::_name()", "int32_t QList<QObject*>::detach()",
- "int32_t QBasicAtomicPointer<QFreeList<QMutexPrivate, (anonymous namespace)::FreeListConstants> >::testAndSetRelease(QFreeList<QMutexPrivate, (anonymous namespace)::FreeListConstants>*, QFreeList<QMutexPrivate, (anonymous namespace)::FreeListConstants>*)",
- "int32_t QJsonPrivate::Parser::reserveSpace(int32_t)", "int32_t QStateMachinePrivate::endMacrostep(bool)",
- "void QScopedPointer<QTemporaryDirPrivate, QScopedPointerDeleter<QTemporaryDirPrivate> >::~QScopedPointer()",
- "bool QVariantIsNull<(anonymous namespace)::CoreTypesFilter>::delegate<QMatrix4x4>(QMatrix4x4 const*)",
- "void QAbstractProxyModelPrivate::QAbstractProxyModelPrivate()",
- "int32_t std::__1::__function::__func<BNWorkerInteractiveEnqueue::$_16, std::__1::allocator<BNWorkerInteractiveEnqueue::$_16>, void ()>::operator()()"
- )
-
- for i, test in enumerate(tests):
- t, n = demangle_gnu3(Architecture['x86'], test)
- result = self.get_type_string(t, n)
- assert result == oracle[i], f"oracle: '{oracle[i]}'\nresult: '{result}'"
-
-
-class PluginManagerTest(unittest.TestCase):
- @flaky(max_runs=4, min_passes=1)
- def test_install_plugin(self):
- mgr = RepositoryManager()
- assert mgr.check_for_updates()
- assert mgr.default_repository.path == 'community'
- assert 'community' in [r.path for r in mgr.repositories]
- assert 'official' in [r.path for r in mgr.repositories]
- assert 'Vector35_Z80' in [p.path for p in mgr['official'].plugins]
- try:
- plugin = mgr['official']['Vector35_Z80']
- assert plugin.dependencies == 'z80dis\n'
- assert plugin.name == 'Z80 Architecture Plugin'
- assert not plugin.installed
- assert not plugin.running
- assert not plugin.enabled
- assert not plugin.disable_pending
- plugin.install()
- plugin.enable()
- assert plugin.installed
- assert plugin.enabled
- finally:
- plugin.uninstall()
-
-
-class TypeParserTest(unittest.TestCase):
- def setUp(self):
- self.arch = 'x86_64'
- self.p = Platform[self.arch]
- self.parser = TypeParser['ClangTypeParser']
-
- def parse_types_from_source(self, source):
- (types, errors) = self.parser.parse_types_from_source(source, "types.hpp", self.p)
- if types is None:
- raise SyntaxError('\n'.join(str(e) for e in errors))
- return BasicTypeParserResult(
- types=dict(zip([t.name for t in types.types], [t.type for t in types.types])),
- variables=dict(zip([t.name for t in types.variables], [t.type for t in types.variables])),
- functions=dict(zip([t.name for t in types.functions], [t.type for t in types.functions])),
- )
-
- def test_integers(self):
- integers = [("a", "char a;", 1, True), ("b", "unsigned char b;", 1, False), ("c", "signed char c;", 1, True),
- ("d", "int8_t d;", 1, True), ("e", "uint8_t e;", 1, False), ("f", "short f;", 2, True),
- ("g", "unsigned short g;", 2, False), ("h", "signed short h;", 2, True),
- ("i", "short int i;", 2, True), ("j", "unsigned short int j;", 2, False),
- ("k", "signed short int k;", 2, True), ("l", "uint16_t l;", 2, False), ("m", "int16_t m;", 2, True),
- ("n", "int n;", 4, True), ("o", "unsigned int o;", 4, False), ("p", "signed int p;", 4, True),
- ("t", "int32_t t;", 4, True), ("u", "uint32_t u;", 4, False), ("q", "long int q;", 8, True),
- ("r", "unsigned long int r;", 8, False), ("s", "signed long int s;", 8, True),
- ("v", "long long v;", 8, True), ("w", "long long int w;", 8, True),
- ("x", "unsigned long long int x;", 8, False)]
-
- for name, definition, size, signed in integers:
- with self.subTest():
- result = self.parse_types_from_source(definition)
- var = result.variables[name]
- assert len(var) == size, f"Size for type: {definition} != {size} for arch {self.arch}"
- assert signed == var.signed, f"Sign for type: {definition} isn't {'signed' if signed else 'unsigned'}"
-
- def test_structures(self):
- structures = [("a", "struct a { uint32_t x; uint64_t y; };", 16, 8, 2),
- ("b", "struct b { uint64_t x; uint64_t y; };", 16, 8, 2),
- ("c", "struct c { uint64_t x; uint32_t y; };", 16, 8, 2), ]
- for name, definition, size, alignment, members in structures:
- with self.subTest():
- result = self.parse_types_from_source(definition)
- s = result.types[name]
- assert len(
- s
- ) == size, f"Structure property: 'size' {size} incorrect for {definition} got {len(s)} instead"
- assert s.alignment == alignment, f"Structure property: 'alignment' {alignment} incorrect for {definition} got {s.alignment} instead"
- assert len(
- s.members
- ) == members, f"Structure property: 'members' {members} incorrect for {definition} got {len(s.members)} instead"
-
- def test_alignment_packing(self):
- structures = [("a", "struct a { uint64_t a; uint64_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint64_t b; uint32_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint32_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint32_t b; uint32_t c; };", 0x10, (0x0, 0x8, 0xc)),
- ("a", "struct a { uint64_t a; uint64_t b; uint16_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint32_t b; uint16_t c; };", 0x10, (0x0, 0x8, 0xc)),
- ("a", "struct a { uint64_t a; uint16_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint16_t b; uint32_t c; };", 0x10, (0x0, 0x8, 0xc)),
- ("a", "struct a { uint64_t a; uint16_t b; uint16_t c; };", 0x10, (0x0, 0x8, 0xa)),
- ("a", "struct a { uint64_t a; uint64_t b; uint8_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint32_t b; uint8_t c; };", 0x10, (0x0, 0x8, 0xc)),
- ("a", "struct a { uint64_t a; uint16_t b; uint8_t c; };", 0x10, (0x0, 0x8, 0xa)),
- ("a", "struct a { uint64_t a; uint8_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint64_t a; uint8_t b; uint32_t c; };", 0x10, (0x0, 0x8, 0xc)),
- ("a", "struct a { uint64_t a; uint8_t b; uint16_t c; };", 0x10, (0x0, 0x8, 0xa)),
- ("a", "struct a { uint64_t a; uint8_t b; uint8_t c; };", 0x10, (0x0, 0x8, 0x9)),
- ("a", "struct a { uint32_t a; uint64_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint32_t a; uint32_t b; uint64_t c; };", 0x10, (0x0, 0x4, 0x8)),
- ("a", "struct a { uint32_t a; uint16_t b; uint64_t c; };", 0x10, (0x0, 0x4, 0x8)),
- ("a", "struct a { uint32_t a; uint8_t b; uint64_t c; };", 0x10, (0x0, 0x4, 0x8)),
- ("a", "struct a { uint16_t a; uint64_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint16_t a; uint32_t b; uint64_t c; };", 0x10, (0x0, 0x4, 0x8)),
- ("a", "struct a { uint16_t a; uint16_t b; uint64_t c; };", 0x10, (0x0, 0x2, 0x8)),
- ("a", "struct a { uint16_t a; uint8_t b; uint64_t c; };", 0x10, (0x0, 0x2, 0x8)),
- ("a", "struct a { uint8_t a; uint64_t b; uint64_t c; };", 0x18, (0x0, 0x8, 0x10)),
- ("a", "struct a { uint8_t a; uint32_t b; uint64_t c; };", 0x10, (0x0, 0x4, 0x8)),
- ("a", "struct a { uint8_t a; uint16_t b; uint64_t c; };", 0x10, (0x0, 0x2, 0x8)),
- ("a", "struct a { uint8_t a; uint8_t b; uint64_t c; };", 0x10, (0x0, 0x1, 0x8)),
- ("a", "struct a { uint8_t a; struct { uint64_t c; } b; };", 0x10, (0x0, 0x8)),
- ("a", "struct a { uint8_t a; struct { uint32_t c; } b; };", 0x8, (0x0, 0x4)),
- ("a", "struct a { uint8_t a; struct { uint16_t c; } b; };", 0x4, (0x0, 0x2)),
- ("a", "struct a { uint8_t a; struct { uint16_t c; uint16_t d; } b; };", 0x6, (0x0, 0x2)),
- ("a", "struct a { uint8_t a; struct { uint8_t c; uint16_t d; } b; };", 0x6, (0x0, 0x2)),
- ("a", "struct a { uint8_t a; struct { uint8_t c; uint8_t d; } b; };", 0x3, (0x0, 0x1)), ]
- for name, definition, size, member_offsets in structures:
- with self.subTest():
- result = self.parse_types_from_source(definition)
- s = result.types[name]
- assert len(
- s
- ) == size, f"Structure property: 'size' {size} incorrect for {definition} got {len(s)} instead"
- for expect_offset, member in zip(member_offsets, s.members):
- assert member.offset == expect_offset, f"Structure member property: 'offset' {expect_offset} incorrect for {member.name} in {definition} got {member.offset} instead"
-
- def test_escaping(self):
- escaped = [('test', 'test', 'test'), ('a0b', 'a0b', 'a0b'), ('a$b', 'a$b', '`a$b`'), ('a_b', 'a_b', 'a_b'),
- ('a@b', 'a@b', '`a@b`'), ('a!b', 'a!b', '`a!b`'), ('0a', '0a', '`0a`'), ('_a', '_a', '_a'),
- ('$a', '$a', '`$a`'), ('@a', '@a', '`@a`'), ('!a', '!a', '`!a`'), ('a::b', 'a::b', '`a::b`'),
- ('a b', 'a b', '`a b`'), ('a`b', 'a`b', '`a\\`b`'), ('a\\b', 'a\\b', '`a\\\\b`'),
- ('a\\`b', 'a\\`b', '`a\\\\\\`b`'), ('a\\\\`b', 'a\\\\`b', '`a\\\\\\\\\\`b`'), ]
- for source, expect_none, expect_backticks in escaped:
- got_none = QualifiedName.escape(source, TokenEscapingType.NoTokenEscapingType)
- assert got_none == expect_none, f"Escape test of {source} NoTokenEscapingType got {got_none} expected {expect_none}"
- got_backticks = QualifiedName.escape(source, TokenEscapingType.BackticksTokenEscapingType)
- assert got_backticks == expect_backticks, f"Escape test of {source} BackticksTokenEscapingType got {got_backticks} expected {expect_backticks}"
-
- got_unesc = QualifiedName.unescape(got_backticks, TokenEscapingType.BackticksTokenEscapingType)
- assert got_unesc == source, f"Escape test round trip for {source} got {got_unesc} from {got_backticks}, expected {source}"
-
- def test_escaped_parsing(self):
- valid = r'''
- typedef uint32_t `type name with space`;
- typedef `type name with space` `another name`;
- enum `space enum`
- {
- `space enum member 1` = 1,
- `space enum member 2` = 2,
- };
- struct `space struct`
- {
- `another name` `first member`;
- `another name`* `second member`;
- `another name` (*`third member`)(`another name` `argument name`);
- };
- '''
- types = self.parse_types_from_source(valid)
- assert types.types['type name with space'] == Type.int(4, False)
- assert types.types['another name'].name == QualifiedName(
- ['type name with space']
- ), f"Expected typedef, got {types.types['another name']}"
- assert len(types.types['space enum'].members) == 2
- assert len(types.types['space struct'].members) == 3
- assert types.types['space struct'].members[0].name == 'first member'
- assert types.types['space struct'].members[1].name == 'second member'
- assert types.types['space struct'].members[1].type.target.name == 'another name'
- assert types.types['space struct'].members[2].name == 'third member'
- assert len(types.types['space struct'].members[2].type.target.parameters) == 1
- assert types.types['space struct'].members[2].type.target.parameters[0].name == 'argument name'
-
- def test_parse_class(self):
- valid = r'''
- class foo;
- class bar
- {
- foo* foo;
- };
- class baz
- {
- class
- {
- bar m_bar;
- } bar;
- struct
- {
- baz* m_baz;
- } baz;
- };
- '''
- types = self.parse_types_from_source(valid)
- assert types.types['bar'].type_class == TypeClass.StructureTypeClass
- assert types.types['bar'].type == StructureVariant.ClassStructureType
- assert types.types['baz'].type_class == TypeClass.StructureTypeClass
- assert types.types['baz'].type == StructureVariant.ClassStructureType
- assert types.types['baz'].members[0].type.type_class == TypeClass.StructureTypeClass
- assert types.types['baz'].members[0].type.type == StructureVariant.ClassStructureType
- assert types.types['baz'].members[1].type.type_class == TypeClass.StructureTypeClass
- assert types.types['baz'].members[1].type.type == StructureVariant.StructStructureType
-
- def test_class_vs_struct(self):
- # Trying to use `class foo` as `struct foo`
-
- # Clang says (TIL):
- # "Class 'foo' was previously declared as a struct; this is valid, but may result in linker errors under the Microsoft C++ ABI"
- valid = [
- r'''
- class foo
- {
- int a;
- };
- class bar
- {
- struct foo foo;
- };
- ''', r'''
- struct foo
- {
- int a;
- };
- struct bar
- {
- class foo foo;
- };
- '''
- ]
- for source in valid:
- with self.subTest():
- types = self.parse_types_from_source(source)
-
-
- def test_parse_empty(self):
- valid = [
- # Forward declarations
- 'struct foo;',
- 'class foo;',
- 'union foo;',
- # Definition with no members
- 'struct foo {};',
- 'class foo {};',
- 'union foo {};',
- 'enum foo {};',
- # Inner structure is empty
- 'struct foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };',
- 'class foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };',
- 'union foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };',
- ]
- for source in valid:
- with self.subTest():
- types = self.parse_types_from_source(source)
-
- invalid = [
- # Forward declaration of enum is not allowed
- 'enum foo;'
- ]
- for source in invalid:
- with self.subTest():
- with self.assertRaises(SyntaxError):
- types = self.parse_types_from_source(source)
-
- def test_parse_nested(self):
- source = r'''
- struct foo
- {
- enum : uint32_t
- {
- a = 1,
- b = 2,
- c = 3
- } bar;
- struct
- {
- uint32_t a;
- } baz;
- class
- {
- uint32_t a;
- } alpha;
- union
- {
- uint32_t a;
- uint32_t b;
- } bravo;
- };
- '''
- types = self.parse_types_from_source(source)
- assert types.types['foo'].members[0].type.type_class == TypeClass.EnumerationTypeClass
- assert types.types['foo'].members[1].type.type_class == TypeClass.StructureTypeClass
- assert types.types['foo'].members[1].type.type == StructureVariant.StructStructureType
- assert types.types['foo'].members[2].type.type_class == TypeClass.StructureTypeClass
- assert types.types['foo'].members[2].type.type == StructureVariant.ClassStructureType
- assert types.types['foo'].members[3].type.type_class == TypeClass.StructureTypeClass
- assert types.types['foo'].members[3].type.type == StructureVariant.UnionStructureType
- assert types.types['foo'].members[0].type.members[0].name == 'a'
- assert types.types['foo'].members[0].type.members[1].name == 'b'
- assert types.types['foo'].members[0].type.members[2].name == 'c'
- assert types.types['foo'].members[1].type.members[0].name == 'a'
- assert types.types['foo'].members[2].type.members[0].name == 'a'
- assert types.types['foo'].members[3].type.members[0].name == 'a'
- assert types.types['foo'].members[3].type.members[1].name == 'b'
-
- def test_forward_declared(self):
- # Via #2431 with a little extra sauce on LIST_ENTRY1
- source = r'''
- struct _LIST_ENTRY;
- typedef struct _LIST_ENTRY LIST_ENTRY;
- typedef LIST_ENTRY LIST_ENTRY1;
- struct _LIST_ENTRY {
- LIST_ENTRY * ForwardLink;
- LIST_ENTRY * BackLink;
- };
-
- struct Test {
- long long Signature;
- LIST_ENTRY1 Link;
- int Action;
- short DefaultId;
- };
- '''
- types = self.parse_types_from_source(source)
- assert types.types['_LIST_ENTRY'].width == 0x10
- assert types.types['LIST_ENTRY'].width == 0x10
- assert types.types['LIST_ENTRY1'].width == 0x10
- assert types.types['Test'].width == 0x20
- assert types.types['Test'].members[2].offset == 0x18
-
- def test_custom_subclass(self):
- class MyTypeParser(TypeParser):
- name = "MyTypeParser"
-
- def preprocess_source(
- self, source: str, file_name: str, platform: binaryninja.Platform,
- existing_types: Optional[List[QualifiedNameTypeAndId]],
- options: Optional[List[str]], include_dirs: Optional[List[str]]
- ) -> Tuple[Optional[str], List[TypeParserError]]:
- return (
- source,
- [
- TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1)
- ]
- )
-
- def parse_types_from_source(
- self,
- source: str,
- file_name: str,
- platform: binaryninja.Platform,
- existing_types: Optional[List[QualifiedNameTypeAndId]],
- options: Optional[List[str]],
- include_dirs: Optional[List[str]],
- auto_type_source: str = ""
- ) -> Tuple[Optional[TypeParserResult], List[TypeParserError]]:
- return (
- TypeParserResult(
- [
- ParsedType("my_type", Type.int(4, False), True)
- ], [
- ParsedType("my_variable", Type.int(4, False), True)
- ], [
- ParsedType("my_function", Type.function(Type.void(), []), True)
- ]
- ),
- [
- TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1)
- ]
- )
-
- def parse_type_string(
- self, source: str, platform: binaryninja.Platform,
- existing_types: Optional[List[QualifiedNameTypeAndId]]
- ) -> Tuple[Optional[Tuple[QualifiedNameType, binaryninja.Type]],
- List[TypeParserError]]:
- return (
- ("my_type", Type.int(4, False)),
- [
- TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1)
- ]
- )
-
- MyTypeParser().register()
-
- tp = TypeParser['MyTypeParser']
- (result, errors) = tp.preprocess_source('some test source', 'source.h', Platform['windows-x86'])
- assert result is not None
- assert result == 'some test source'
-
- assert errors is not None
- assert len(errors) == 1
-
- assert errors[0].severity == TypeParserErrorSeverity.WarningSeverity
- assert errors[0].message == "Test Warning"
- assert errors[0].file_name == "sources.hpp"
- assert errors[0].line == 1
- assert errors[0].column == 1
-
- (result, errors) = tp.parse_types_from_source('some test source', 'source.h', Platform['windows-x86'])
- assert result is not None
- assert len(result.types) == 1
- assert len(result.variables) == 1
- assert len(result.functions) == 1
-
- assert result.types[0].name == 'my_type'
- assert result.types[0].type == Type.int(4, False)
- assert result.types[0].is_user
-
- assert result.variables[0].name == 'my_variable'
- assert result.variables[0].type == Type.int(4, False)
- assert result.variables[0].is_user
-
- assert result.functions[0].name == 'my_function'
- assert result.functions[0].type == Type.function(Type.void(), [])
- assert result.functions[0].is_user
-
- assert errors is not None
- assert len(errors) == 1
-
- assert errors[0].severity == TypeParserErrorSeverity.WarningSeverity
- assert errors[0].message == "Test Warning"
- assert errors[0].file_name == "sources.hpp"
- assert errors[0].line == 1
- assert errors[0].column == 1
-
- (result, errors) = tp.parse_type_string('some test source', Platform['windows-x86'])
- assert result is not None
- assert result[0] == 'my_type'
- assert result[1] == Type.int(4, False)
-
- assert errors is not None
- assert len(errors) == 1
-
- assert errors[0].severity == TypeParserErrorSeverity.WarningSeverity
- assert errors[0].message == "Test Warning"
- assert errors[0].file_name == "sources.hpp"
- assert errors[0].line == 1
- assert errors[0].column == 1
-
-
-class TestTypePrinter(unittest.TestCase):
- def test_getlines(self):
- arch = 'x86'
- platform = Platform['windows-x86']
- bv = BinaryView.new()
- bv.platform = platform
-
- types = [
- (Type.int(4), 'basic_int', 'typedef int32_t basic_int;\n'),
- (Type.array(Type.int(4), 4), 'basic_array', 'typedef int32_t basic_array[0x4];\n'),
- (Type.pointer(platform.arch, Type.array(
- Type.int(4), 4
- )), 'pointer_array', 'typedef int32_t (* pointer_array)[0x4];\n'),
- (Type.array(
- Type.pointer(platform.arch, Type.int(4)), 4
- ), 'array_pointer', 'typedef int32_t* array_pointer[0x4];\n'),
- (Type.function(
- Type.int(4), []
- ), 'basic_func', 'typedef int32_t basic_func();\n'),
- (Type.function(
- Type.int(4), [], platform.fastcall_calling_convention
- ), 'convention_func', 'typedef int32_t __fastcall convention_func();\n'),
- (Type.pointer(platform.arch, Type.function(
- Type.int(4), []
- ), True), 'const_func_pointer', 'typedef int32_t (* const const_func_pointer)();\n'),
- (Type.pointer(platform.arch, Type.function(
- Type.int(4), []
- )), 'basic_func_pointer', 'typedef int32_t (* basic_func_pointer)();\n'),
- (Type.function(
- Type.pointer(platform.arch, Type.int(4)), []
- ), 'func_returning_ptr', 'typedef int32_t* func_returning_ptr();\n'),
- (Type.structure([
- (Type.int(4), 'foo')
- ]), 'basic_struct', 'struct basic_struct\n{\n int32_t foo;\n};\n'),
- (Type.pointer(platform.arch, Type.structure([
- (Type.int(4), 'foo')
- ])), 'pointer_struct', 'typedef struct { int32_t foo; }* pointer_struct;\n'),
- (Type.pointer(platform.arch, Type.structure([
- (Type.pointer(platform.arch, Type.int(4)), 'foo')
- ])), 'pointer_in_pointer_struct', 'typedef struct { int32_t* foo; }* pointer_in_pointer_struct;\n'),
- (Type.pointer(platform.arch, Type.structure([
- (Type.pointer(platform.arch, Type.structure([
- (Type.pointer(platform.arch, Type.int(4)), 'foo')
- ])), 'foo')
- ])), 'nested_pointer_struct', 'typedef struct { struct { int32_t* foo; }* foo; }* nested_pointer_struct;\n'),
- (Type.pointer(platform.arch, Type.structure([
- (Type.pointer(platform.arch, Type.function(Type.int(4), [('param', Type.int(4))])), 'foo')
- ])), 'pointer_function_struct', 'typedef struct { int32_t (* foo)(int32_t param); }* pointer_function_struct;\n'),
- (Type.pointer(platform.arch, Type.enumeration(platform.arch, [
- ('one', 1)
- ])), 'pointer_enumeration', 'typedef enum {}* pointer_enumeration;\n'),
- ]
-
- for t in types:
- with self.subTest(t[1]):
- lines = t[0].get_lines(bv, t[1])
- text = ""
- for l in lines:
- for tok in l.tokens:
- text += tok.text
- text += "\n"
- assert text == t[2], f"Invalid printing of type, got {text} expected {t[2]}"
-
-
- def test_custom_subclass(self):
- class MyTypePrinter(TypePrinter):
- name = "MyTypePrinter"
-
- def get_type_tokens(self, type: types.Type, platform: Optional[Platform], name: types.QualifiedName,
- base_confidence: int, escaping: TokenEscapingType) -> List[InstructionTextToken]:
- return [
- InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0),
- InstructionTextToken(InstructionTextTokenType.TypeNameToken, str(name), 0),
- InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0)
- ]
-
- def get_type_tokens_before_name(self, type: types.Type, platform: Optional[Platform], base_confidence: int,
- parent_type: Optional[types.Type], escaping: TokenEscapingType) -> List[
- InstructionTextToken]:
- return [
- InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0),
- ]
-
- def get_type_tokens_after_name(self, type: types.Type, platform: Optional[Platform], base_confidence: int,
- parent_type: Optional[types.Type], escaping: TokenEscapingType) -> List[InstructionTextToken]:
- return [
- InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0),
- ]
-
- def get_type_string(self, type: types.Type, platform: Optional[Platform], name: types.QualifiedName,
- escaping: TokenEscapingType) -> str:
- return f"the type is: {name} bottom text"
-
- def get_type_string_before_name(self, type: types.Type, platform: Optional[Platform],
- escaping: TokenEscapingType) -> str:
- return f"the type is: "
-
- def get_type_string_after_name(self, type: types.Type, platform: Optional[Platform],
- escaping: TokenEscapingType) -> str:
- return f" bottom text"
-
- def get_type_lines(self, type: types.Type, container: typecontainer.TypeContainer, name: types.QualifiedName,
- padding_cols, collapsed, escaping: TokenEscapingType) -> List[types.TypeDefinitionLine]:
- return [
- TypeDefinitionLine(TypeDefinitionLineType.TypedefLineType, [
- InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0),
- InstructionTextToken(InstructionTextTokenType.TypeNameToken, str(name), 0),
- InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0)
- ], type, type, type, '', 0, 1),
- ]
-
- MyTypePrinter().register()
-
- tp = TypePrinter['MyTypePrinter']
- result = tp.get_type_tokens(Type.void(), None, QualifiedName(['test']), 255, TokenEscapingType.NoTokenEscapingType)
- assert result is not None
- assert len(result) == 3
- assert result[0].text == "the type is: "
- assert result[1].text == "test"
- assert result[2].text == " bottom text"
- result = tp.get_type_tokens_before_name(Type.void())
- assert result is not None
- assert len(result) == 1
- assert result[0].text == "the type is: "
- result = tp.get_type_tokens_after_name(Type.void())
- assert result is not None
- assert len(result) == 1
- assert result[0].text == " bottom text"
- result = tp.get_type_string(Type.void(), None, QualifiedName(['test']))
- assert result is not None
- assert result == "the type is: test bottom text"
- result = tp.get_type_string_before_name(Type.void())
- assert result is not None
- assert result == "the type is: "
- result = tp.get_type_string_after_name(Type.void())
- assert result is not None
- assert result == " bottom text"
- bv = BinaryView.new(b'')
- bv.platform = Platform['windows-x86_64']
- result = tp.get_type_lines(Type.void(), bv.type_container, QualifiedName(['test']), bv.platform)
- assert result is not None
- assert len(result) == 1
- assert len(result[0].tokens) == 3
- assert result[0].tokens[0].text == "the type is: "
- assert result[0].tokens[1].text == "test"
- assert result[0].tokens[2].text == " bottom text"
-
-
-class TestQualifiedName(unittest.TestCase):
- def test_constructors_and_equality(self):
- assert QualifiedName("name").name == ["name"]
- assert QualifiedName(b"name").name == ["name"]
- assert QualifiedName(QualifiedName("name")).name == ["name"]
- assert QualifiedName(["name1", "name2"]).name == ["name1", "name2"]
- assert QualifiedName([b"name1", b"name2"]).name == ["name1", "name2"]
-
- def test_comparison(self):
- assert QualifiedName("a") == "a"
- assert QualifiedName(["a", "b"]) == "a::b"
- assert QualifiedName("a") == ["a"]
- assert QualifiedName("a") == QualifiedName("a")
- assert QualifiedName("a").__eq__(None) == NotImplemented
- assert QualifiedName(["a", "b"]) != "a::a"
- assert QualifiedName("a") != ["b"]
- assert QualifiedName("a") != QualifiedName("b")
- assert QualifiedName("a").__ne__(None) == NotImplemented
-
- assert QualifiedName("a") < QualifiedName("b")
- assert QualifiedName("a").__lt__(None) == NotImplemented
- assert QualifiedName("a") <= QualifiedName("a")
- assert QualifiedName("a").__le__(None) == NotImplemented
- assert QualifiedName("b") > QualifiedName("a")
- assert QualifiedName("a").__gt__(None) == NotImplemented
- assert QualifiedName("a") >= QualifiedName("a")
- assert QualifiedName("a").__ge__(None) == NotImplemented
-
- def test_accessors(self):
- assert QualifiedName("a")[0] == "a"
- name = ["a", "b", "c"]
- q = QualifiedName(name)
- it = iter(q)
- assert next(it) == "a"
- assert next(it) == "b"
- assert next(it) == "c"
- assert q.name == name
- q.name = list(reversed(name))
- assert q.name == list(reversed(name))
-
- def test_str(self):
- name = ["a", "b", "c"]
- q = QualifiedName(name)
- assert str(q) == "::".join(name)
-
- def test_len(self):
- name = ["a", "b", "c"]
- assert len(QualifiedName(name)) == 3
-
-
-class TypeTest(unittest.TestCase):
- def setUp(self) -> None:
- self.arch = Architecture['x86_64']
- self.plat = Platform['x86_64']
- self.cc = self.plat.calling_conventions[0]
-
- def test_IntegerBuilder(self):
- ib = TypeBuilder.int(4)
- ib.const = True
- ib.volatile = False
- ib.alternate_name = "billy bob"
- ib.signed = True
- assert ib.const
- assert not ib.volatile
- assert ib.alternate_name == "billy bob"
- assert ib.signed
- assert len(ib) == 4
- assert ib == ib.immutable_copy().mutable_copy(), "IntegerBuilder failed to round trip mutability"
- assert repr(ib).startswith("<type:")
-
- def test_CharBuilder(self):
- b = TypeBuilder.char("my_char")
- b.const = True
- b.volatile = False
- assert b.alternate_name == "my_char"
- b.alternate_name = "my_char2"
- assert b.const
- assert not b.volatile
- assert b.alternate_name == "my_char2"
- assert b == b.immutable_copy().mutable_copy(), "CharBuilder failed to round trip mutability"
-
- def test_FloatBuilder(self):
- b = TypeBuilder.float(4, "half")
- b.const = True
- b.volatile = False
- assert b.const
- assert not b.volatile
- assert b.alternate_name == "half"
- assert b == b.immutable_copy().mutable_copy(), "FloatBuilder failed to round trip mutability"
-
- def test_WideCharBuilder(self):
- b = TypeBuilder.wide_char(4, "wchar32_t")
- b.const = True
- b.volatile = False
- assert b.const
- assert not b.volatile
- assert b.alternate_name == "wchar32_t"
- assert b == b.immutable_copy().mutable_copy(), "WideCharBuilder failed to round trip mutability"
-
- def test_PointerBuilder(self):
- ib = TypeBuilder.int(4)
- b = TypeBuilder.pointer(self.arch, ib, 4)
- b.const = True
- b.volatile = False
- assert ib.immutable_copy() == b.immutable_target
- assert ib == b.target
- assert ib.immutable_copy() == b.child.immutable_copy()
- assert b == b.immutable_copy().mutable_copy(), "PointerBuilder failed to round trip mutability"
-
- b = TypeBuilder.pointer_of_width(4, ib)
- b.const = True
- b.volatile = False
- assert len(b) == 4
- assert ib.immutable_copy() == b.immutable_target
- assert ib == b.target
- assert ib.immutable_copy() == b.child.immutable_copy()
- assert b == b.immutable_copy().mutable_copy(), "PointerBuilder failed to round trip mutability"
- assert b.mutable_copy() == b
- assert TypeBuilder.create() == NotImplemented
-
- def test_VoidBuilder(self):
- b = TypeBuilder.void()
- assert b == b.immutable_copy().mutable_copy(), "VoidBuilder failed to round trip mutability"
-
- def test_BoolBuilder(self):
- b = TypeBuilder.bool()
- assert b == b.immutable_copy().mutable_copy(), "VoidBuilder failed to round trip mutability"
-
- def test_FunctionBuilder(self):
- bb = TypeBuilder.bool()
- ib = TypeBuilder.int(4)
- pb = TypeBuilder.pointer(self.arch, ib, 4)
- vb = TypeBuilder.void()
- b = TypeBuilder.function(vb, [FunctionParameter(pb, "arg1"), ("arg2", pb)], self.cc)
- assert b.system_call_number is None
- b.system_call_number = 1
- assert b.system_call_number == 1
- b.clear_system_call()
- assert b.system_call_number is None
- b.system_call_number = 1
-
- assert b == b.immutable_copy().mutable_copy(), "FunctionBuilder failed to round trip mutability"
- assert b.immutable_return_value == vb.immutable_copy()
- assert b.return_value == vb
- b.return_value = b
- b.append(bb)
- b.append(FunctionParameter(pb, "arg3"))
- assert b.calling_convention == self.cc
- assert b.can_return
- b.can_return = False
- assert not b.can_return
- assert b.stack_adjust == 0
- assert len(b.parameters) == 4
- assert b.parameters[0].type == pb.immutable_copy()
- assert b.parameters[0].name == "arg1"
- assert b.parameters[2].type == bb.immutable_copy()
- assert b.parameters[2].name == ""
- assert b.parameters[3].type == pb.immutable_copy()
- assert b.parameters[3].name == "arg3"
- assert b.stack_adjust.value == 0
- assert not b.variable_arguments
- b.parameters = [FunctionParameter(pb, "arg1")]
- assert b.parameters[0].type == pb.immutable_copy()
- assert b.parameters[0].name == "arg1"
- assert len(b.parameters) == 1
-
- b = TypeBuilder.function()
- assert len(b.parameters) == 0
- assert b.return_value == TypeBuilder.void()
- assert b == b.immutable_copy().mutable_copy(), "FunctionBuilder failed to round trip mutability"
-
- def test_ArrayBuilder(self):
- ib = TypeBuilder.int(4)
- b = TypeBuilder.array(ib, 4)
- assert len(b) == len(ib) * 4
- assert b.count == 4
- assert b.element_type == ib
- assert b == b.immutable_copy().mutable_copy(), "ArrayBuilder failed to round trip mutability"
-
- def test_StructureBuilder(self):
- ib = TypeBuilder.int(4)
- b = TypeBuilder.structure([StructureMember(ib, "name", 0), Type.bool()])
- b.members = [*b.members, StructureMember(ib, "name2", 8)]
- assert not b.union
- b.type = StructureVariant.UnionStructureType
- assert b.union
- b.type = StructureVariant.StructStructureType
- assert b['name'].name == "name"
- assert b['name'].type == ib.immutable_copy()
-
- assert b["doesnt exist"] is None
-
- it = iter(b)
- mem = next(it)
- assert mem.name == "name"
- assert mem.type == ib.immutable_copy()
- mem = next(it)
- assert mem.name == "field_4"
- assert mem.type == Type.bool()
- mem = next(it)
- assert mem.name == "name2"
- assert mem.type == ib.immutable_copy()
-
- assert len(b) == 12
- assert b.member_at_offset(0x1000) == None
- assert b.member_at_offset(0).name == "name"
- assert b.member_at_offset(0).type == ib.immutable_copy()
- assert b.member_at_offset(4).name == "field_4"
- assert b.member_at_offset(4).type == Type.bool()
- assert b.member_at_offset(8).name == "name2"
- assert b.member_at_offset(8).type == ib.immutable_copy()
- assert b.index_by_name("name") == 0
- assert b.index_by_name("name2") == 2
- assert b.index_by_name("doesn't exist") is None
- assert b.index_by_offset(0) == 0
- assert b.index_by_offset(4) == 1
- assert b.index_by_offset(8) == 2
- assert b.index_by_offset(0x10000) is None
- b.add_member_at_offset("foo", Type.int(4), 0x20)
- mem = b.member_at_offset(0x20)
- assert mem.name == "foo"
- assert mem.type == Type.int(4)
- assert b == b.immutable_copy().mutable_copy(), "StructureBuilder failed to round trip mutability"
-
- assert len(StructureMember(Type.int(4), "foo", 0)) == len(Type.int(4))
-
- b = TypeBuilder.union([StructureMember(ib, "name", 0), StructureMember(ib, "name2", 0)])
- assert b.type == StructureVariant.UnionStructureType
-
- b = TypeBuilder.class_type([StructureMember(ib, "name", 0), StructureMember(ib, "name2", 4)])
- assert b.type == StructureVariant.ClassStructureType
-
- def test_EnumerationBuilder(self):
- b = EnumerationBuilder.create([("Member1", 1)], 4, None, False)
- assert not b.signed
- b.signed = True
- assert b.signed
- assert len(b.members) == 1
- assert b.members[0].name == "Member1"
- assert b.members[0].value == 1
- b.members = [("Member0", 0), ("Member1")]
- assert b.members[0].name == "Member0"
- assert b.members[0].value == 0
- assert b.members[1].name == "Member1"
- assert b.members[1].value == None
-
- b.append("NewMember")
- assert b.members[2].name == "NewMember"
- assert b.members[2].value == None
- it = iter(b)
- mem = next(it)
- assert mem.name == "Member0"
- assert mem.value == 0
- mem = next(it)
- assert mem.name == "Member1"
- assert mem.value == None
- mem = next(it)
- assert mem.name == "NewMember"
- assert mem.value == None
-
- assert b["Member0"].name == "Member0"
- assert b["Member0"].value == 0
- assert b["Member1"].name == "Member1"
- assert b["Member1"].value == None
- assert b["NewMember"].name == "NewMember"
- assert b["NewMember"].value == None
- assert b[0].name == "Member0"
- assert b[0].value == 0
- assert b[1].name == "Member1"
- assert b[1].value == None
-
- mem0, mem1 = b[0:2]
- assert mem0.name == "Member0"
- assert mem0.value == 0
- assert mem1.name == "Member1"
- assert mem1.value == None
- self.assertRaises(ValueError, lambda: b[None])
-
- b["Member0"] = 4
- assert b["Member0"].value == 4
- b[1] = EnumerationMember("Member10", 10)
- assert b[1].name == "Member10"
- assert b[1].value == 10
- assert b["Member_doesn't exist"] == None
- self.assertRaises(ValueError, lambda: b.__setitem__(None, None))
-
- e1 = EnumerationMember("Member10", 10)
- assert e1.value == 10
- assert e1.name == "Member10"
- assert int(e1) == 10
- assert repr(e1).endswith("<Member10 = 0xa>")
-
- def test_NamedTypeReferenceBuilder(self):
- b = TypeBuilder.named_type_reference(NamedTypeReferenceClass.UnknownNamedTypeClass, "foo")
- assert b.name == "foo"
- assert b.named_type_class == NamedTypeReferenceClass.UnknownNamedTypeClass
-
- b = TypeBuilder.named_type_from_type("foobar", NamedTypeReferenceClass.UnknownNamedTypeClass)
- assert b.name == "foobar"
- assert b.id == b.type_id
- assert b.named_type_class == NamedTypeReferenceClass.UnknownNamedTypeClass
- assert b == b.immutable_copy().mutable_copy(), "NamedTypeReferenceBuilder failed to round trip mutability"
-
- b = TypeBuilder.named_type_from_type_and_id("type_id", QualifiedName(b"name"), Type.int(4))
- assert b.name == "name"
- assert b.id == "type_id"
- assert b.named_type_class == NamedTypeReferenceClass.TypedefNamedTypeClass
- assert repr(b).startswith("<type: mutable:NamedTypeReferenceClass 'typedef")
-
- b = TypeBuilder.named_type_from_type_and_id("type_id", QualifiedName(b"name"))
- assert b.name == "name"
- assert b.id == "type_id"
- assert b.named_type_class == NamedTypeReferenceClass.UnknownNamedTypeClass
- assert repr(b).startswith("<type: mutable:NamedTypeReferenceClass 'unknown")
-
- enm = TypeBuilder.enumeration(self.arch, [("Member1", 0)], 4, False)
- b = TypeBuilder.named_type_from_type_and_id("type_id", QualifiedName(b"name"), enm)
- assert b.name == "name"
- assert b.id == "type_id"
- assert b.named_type_class == NamedTypeReferenceClass.EnumNamedTypeClass
- assert repr(b).startswith("<type: mutable:NamedTypeReferenceClass 'enum")
-
- str = TypeBuilder.structure([], True, StructureVariant.StructStructureType)
- b = TypeBuilder.named_type_from_type_and_id("type_id", QualifiedName(b"name"), str)
- assert b.name == "name"
- assert b.id == "type_id"
- assert b.named_type_class == NamedTypeReferenceClass.StructNamedTypeClass
- assert repr(b).startswith("<type: mutable:NamedTypeReferenceClass 'struct")
-
- str = TypeBuilder.structure([], True, StructureVariant.ClassStructureType)
- b = TypeBuilder.named_type_from_type_and_id("type_id", QualifiedName(b"name"), str)
- assert b.name == "name"
- assert b.id == "type_id"
- assert b.named_type_class == NamedTypeReferenceClass.ClassNamedTypeClass
- assert repr(b).startswith("<type: mutable:NamedTypeReferenceClass 'class")
-
- str = TypeBuilder.structure([], True, StructureVariant.UnionStructureType)
- b = TypeBuilder.named_type_from_type_and_id("type_id", QualifiedName([b"name", b"name"]), str)
- assert b.name == QualifiedName(["name", "name"])
- assert b.id == "type_id"
- assert b.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass
- assert repr(b).startswith("<type: mutable:NamedTypeReferenceClass 'union")
-
- b = NamedTypeReferenceBuilder.named_type(b, 4, 4)
- assert b.width == 4
- assert b.alignment == 4
-
- b = NamedTypeReferenceBuilder.named_type_from_type("name")
- b.named_type_class == NamedTypeReferenceClass.UnknownNamedTypeClass
-
- # need binary view for this one
- #b = NamedTypeReferenceBuilder.named_type_from_registered_type(bv, )
-
- def test_IntegerType(self):
- t = IntegerType.create(2, False, "", self.plat, 0)
- assert t.width == 2
- assert len(t) == 2
- assert t.alignment == 2
- assert t.__ne__(None) == NotImplemented
- assert t.offset == 0
- assert t.confidence == 0
- assert [str(i) for i in t.get_tokens()] == ["uint16_t"]
- assert [str(i) for i in t.get_tokens_before_name()] == ["uint16_t"]
- assert [str(i) for i in t.get_tokens_after_name()] == []
- assert t.platform == self.plat
- tc = t.with_confidence(255)
- assert tc.confidence == 255
-
- t = Type.int(4)
- assert t.width == 4
- assert len(t) == 4
- assert t.alignment == 4
- assert t.altname == ""
- assert t.mutable_copy().immutable_copy() == t
-
- def test_VoidType(self):
- t = Type.void()
- assert t.width == 0
- assert t.altname == ""
- assert t.mutable_copy().immutable_copy() == t
-
- def test_BoolType(self):
- t = Type.bool()
- assert t.width == 1
- assert t.altname == ""
- assert t.mutable_copy().immutable_copy() == t
-
- def test_CharType(self):
- t = Type.char()
- assert t.width == 1
- assert t.altname == ""
- assert t.mutable_copy().immutable_copy() == t
-
- t = Type.char("char_alt_name")
- assert t.width == 1
- assert t.altname == "char_alt_name"
- assert t.mutable_copy().immutable_copy() == t
-
- def test_FloatType(self):
- t = Type.float(2)
- assert str(t.tokens[0]) == "float16"
- assert len(t) == 2
- t = Type.float(4)
- assert str(t.tokens[0]) == "float"
- assert len(t) == 4
- t = Type.float(8)
- assert str(t.tokens[0]) == "double"
- assert len(t) == 8
- t = Type.float(10)
- assert str(t.tokens[0]) == "long double"
- assert len(t) == 10
- t = Type.float(16)
- assert str(t.tokens[0]) == "float128"
- assert len(t) == 16
- assert t.mutable_copy().immutable_copy() == t
-
- def test_WideCharType(self):
- t = Type.wide_char(4)
- assert len(t) == 4
- assert str(t.tokens[0]) == "wchar32"
- assert t.mutable_copy().immutable_copy() == t
-
- def test_PointerType(self):
- t = Type.pointer(self.arch, Type.int(4), True, True)
- assert t.const
- assert t.volatile
- assert t.target == Type.int(4)
- assert t.mutable_copy().immutable_copy() == t
- assert t.ref_type == ReferenceType.PointerReferenceType
- t = Type.pointer_of_width(4, Type.int(4))
- assert len(t) == 4
-
- def test_ArrayType(self):
- element_type = Type.int(4)
- t = Type.array(element_type, 4)
- assert t.count == 4
- assert len(t) == 16
- assert t.element_type == element_type
- assert t.mutable_copy().immutable_copy() == t
-
- def test_StructureType(self):
- t = Type.structure_type(StructureBuilder.create([Type.int(1)]))
- assert t.mutable_copy().immutable_copy() == t
- t = Type.structure()
- assert t.mutable_copy().immutable_copy() == t
- assert t.mutable_copy().immutable_copy() == t
- t = Type.structure([Type.int(4)])
- assert t.mutable_copy().immutable_copy() == t
- t1 = t
- t = Type.structure([
- StructureMember(Type.int(4), "first", 0, MemberAccess.PublicAccess, MemberScope.StaticScope),
- StructureMember(Type.int(4), "second", 4, MemberAccess.PublicAccess, MemberScope.StaticScope)
- ])
- t2 = t
- self.assertRaises(ValueError, lambda: Type.structure([None]))
- assert hash(t1) != hash(t2)
- assert t["first"].name == "first"
- assert t["second"].name == "second"
- self.assertRaises(ValueError, lambda: t["not there"])
- mem = t.member_at_offset(0)
- assert mem.name == "first"
- assert mem.type == Type.int(4)
- assert mem.access == MemberAccess.PublicAccess
- assert mem.scope == MemberScope.StaticScope
- self.assertRaises(ValueError, lambda: t.member_at_offset(-1))
- assert not t.packed
-
- t = Type.union([
- StructureMember(Type.int(4), "first", 0, MemberAccess.PublicAccess, MemberScope.StaticScope),
- StructureMember(Type.int(4), "second", 4, MemberAccess.PublicAccess, MemberScope.StaticScope)
- ])
- ntr = t.generate_named_type_reference("guid", "name")
- assert ntr.name == "name"
-
- t = Type.class_type([
- StructureMember(Type.int(4), "first", 0, MemberAccess.PublicAccess, MemberScope.StaticScope),
- StructureMember(Type.int(4), "second", 4, MemberAccess.PublicAccess, MemberScope.StaticScope)
- ])
- ntr = t.generate_named_type_reference("guid", "name")
- assert ntr.name == "name"
-
- def test_NamedTypeReferenceType(self):
- t = Type.named_type(
- NamedTypeReferenceBuilder.create(NamedTypeReferenceClass.UnknownNamedTypeClass, "id", "name")
- )
- assert t.mutable_copy().immutable_copy() == t
- t = Type.named_type_from_type_and_id("id2", ["qualified", "name"])
- assert t.mutable_copy().immutable_copy() == t
- t = Type.generate_named_type_reference("guid", [b"byte", b"name"])
- assert t.mutable_copy().immutable_copy() == t
-
- b = Type.named_type_reference(NamedTypeReferenceClass.UnknownNamedTypeClass, "name")
- assert b.name == "name"
- assert b.named_type_class == NamedTypeReferenceClass.UnknownNamedTypeClass
- assert repr(b).startswith("<type: immutable:NamedTypeReferenceClass 'unknown")
-
- b = Type.named_type_reference(NamedTypeReferenceClass.EnumNamedTypeClass, "name")
- assert b.name == "name"
- assert b.named_type_class == NamedTypeReferenceClass.EnumNamedTypeClass
- assert repr(b).startswith("<type: immutable:NamedTypeReferenceClass 'enum")
-
- b = Type.named_type_reference(NamedTypeReferenceClass.StructNamedTypeClass, "name")
- assert b.name == "name"
- assert b.named_type_class == NamedTypeReferenceClass.StructNamedTypeClass
- assert repr(b).startswith("<type: immutable:NamedTypeReferenceClass 'struct")
-
- b = Type.named_type_reference(NamedTypeReferenceClass.ClassNamedTypeClass, "name")
- assert b.name == "name"
- assert b.named_type_class == NamedTypeReferenceClass.ClassNamedTypeClass
- assert repr(b).startswith("<type: immutable:NamedTypeReferenceClass 'class")
-
- b = Type.named_type_reference(NamedTypeReferenceClass.UnionNamedTypeClass, "name")
- assert b.name == "name"
- assert b.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass
- assert repr(b).startswith("<type: immutable:NamedTypeReferenceClass 'union")
-
- b = NamedTypeReferenceType.generate_auto_type_ref(NamedTypeReferenceClass.UnionNamedTypeClass, "foo", "bar")
- assert b.type_id.startswith("foo")
- assert b.name == "bar"
- assert b.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass
- b = NamedTypeReferenceType.generate_auto_demangled_type_ref(NamedTypeReferenceClass.UnionNamedTypeClass, "bar")
- assert b.type_id.startswith("demange")
-
- def test_EnumerationType(self):
- t = Type.enumeration_type(self.arch, EnumerationBuilder.create([("Member1", 1)]))
- t2 = Type.enumeration_type(self.arch, EnumerationBuilder.create([("Member2", 2)]))
- assert t.mutable_copy().immutable_copy() == t
- assert t.members[0].name == "Member1"
- assert t.members[0].value == 1
- self.assertRaises(ValueError, lambda: Type.enumeration())
- self.assertRaises(ValueError, lambda: Type.enumeration(width=0))
- t = t.generate_named_type_reference("guid", "name")
- assert t.type_id == "guid"
- assert t.name == "name"
- assert hash(t2) != hash(t)
- assert Type.enumeration(members=[EnumerationMember("asdf")], width=4).members[0].value is None
-
- def test_FunctionType(self):
- t = Type.function()
- assert t.mutable_copy().immutable_copy() == t
- self.assertRaises(ValueError, lambda: t.mutable_copy() == t)
-
- vnt = VariableNameAndType(VariableSourceType.StackVariableSourceType, 0, 0, "arg1", Type.int(4))
- param1 = FunctionParameter(Type.int(4), "arg1", vnt)
- vnt = VariableNameAndType(VariableSourceType.RegisterVariableSourceType, 0, 0, "arg2", Type.int(4))
- param2 = FunctionParameter(Type.int(4), "arg2", vnt)
- vnt = VariableNameAndType(VariableSourceType.FlagVariableSourceType, 0, 0, "arg3", Type.int(4))
- param3 = FunctionParameter(Type.int(4), "arg3", vnt)
- t = Type.function(Type.void(), [param1, param2, param3], self.cc)
- assert param3 == param3.mutable_copy().immutable_copy()
- assert repr(param3).endswith(param3.name)
- assert t.mutable_copy().immutable_copy() == t
- assert t.stack_adjustment == 0
- assert t.return_value == Type.void()
- assert t.calling_convention == self.cc
- assert not t.has_variable_arguments
- assert t.can_return
-
-
-class TestOffsetWithConfidence(unittest.TestCase):
- def test_constructor(self):
- o = OffsetWithConfidence(0)
- assert o.value == 0
- assert o.confidence == 255
- assert int(o) == 0
- assert o == 0
- assert o == OffsetWithConfidence(0)
- assert o != OffsetWithConfidence(0, 0)
- assert o < 1
- assert o <= 0
- assert o > -1
- assert o >= 0
-
-
-class TestBoolWithConfidence(unittest.TestCase):
- def test_constructor(self):
- o = BoolWithConfidence(True)
- assert o.value == True
- assert o.confidence == 255
- assert bool(o) == True
- assert o == True
- assert o == BoolWithConfidence(True)
- assert o != BoolWithConfidence(True, 0)
-
-
-class TestSymbols(unittest.TestCase):
- def test_CoreSymbol(self):
- with Apparatus("helloworld") as bv:
- assert len(bv.symbols) == 56
- sym = bv.symbols["_Jv_RegisterClasses"][0]
- sym2 = bv.symbols['__elf_header'][0]
- assert repr(sym).startswith('<ExternalSymbol: "_Jv_RegisterClasses" @ 0x11038>')
- assert sym == sym
- assert sym != sym2
- assert sym.__eq__(None) == NotImplemented
- assert sym.__ne__(None) == NotImplemented
- assert hash(sym) != hash(sym2)
- assert sym.binding == SymbolBinding.WeakBinding
- assert sym.short_name == "_Jv_RegisterClasses"
- assert sym.full_name == "_Jv_RegisterClasses"
- assert sym.raw_name == "_Jv_RegisterClasses"
- assert sym.raw_bytes == b"_Jv_RegisterClasses"
- assert sym.ordinal == 0
- assert sym.auto
- sym = Symbol(
- "DataSymbol", 0, "short_name", "full_name", "raw_name", SymbolBinding.GlobalBinding,
- NameSpace("BN_INTERNAL_NAMESPACE"), 2
- )
- assert sym.binding == SymbolBinding.GlobalBinding
- assert sym.short_name == "short_name"
- assert sym.full_name == "full_name"
- assert sym.raw_name == "raw_name"
- assert sym.raw_bytes == b"raw_name"
- assert sym.ordinal == 2
- assert not sym.auto
-
- def test_NameSpace(self):
- ns = NameSpace("BN_INTERNAL_NAMESPACE")
- assert str(ns) == str(NameSpace._from_core_struct(ns._to_core_struct()))
-
-
-class TestTypes(TestWithBinaryView):
- def test_named_type_from_registered_type(self):
- n = Type.named_type_from_registered_type(self.bv, "Elf32_Dyn")
- assert n.name == "Elf32_Dyn"
-
- def test_attributes(self):
- t = self.bv.types["Elf32_Dyn"]
- assert t.confidence == 255
- assert t.platform == self.bv.platform
- t.confidence = 0
- assert t.confidence == 0
- p = Platform["windows-x86"]
- t.platform = p
- assert t.platform == p
- with t.get_builder(self.bv) as s:
- assert isinstance(s, StructureBuilder)
-
- s = self.bv.types["Elf32_Dyn"]
- n = s.registered_name
- assert s == n.target(self.bv)
- unregistered_ntr = NamedTypeReferenceType.generate_auto_demangled_type_ref(
- NamedTypeReferenceClass.EnumNamedTypeClass, "foobar"
- )
- assert unregistered_ntr.target(self.bv) == None
-
- def test_enum_printing(self):
- """
- Make sure that printing different size/signedness enum values do the right thing
- """
-
- def type_to_def(bv: 'BinaryView', ty: 'Type') -> str:
- lines = ty.get_lines(bv, 'foo')
- defn = ""
- for line in lines:
- line_str = ""
- for token in line.tokens:
- if token.type == InstructionTextTokenType.IndentationToken:
- line_str += "\t"
- else:
- line_str += token.text
- if defn != "":
- defn += "\n"
- defn += line_str
- return defn
-
- with Apparatus("helloworld") as bv:
- # 0
- i8_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 1, sign=True))
- assert type_to_def(bv, i8_0) == "enum foo : char\n{\n\tfoo = 0x0\n};"
- i16_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 2, sign=True))
- assert type_to_def(bv, i16_0) == "enum foo : int16_t\n{\n\tfoo = 0x0\n};"
- i32_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 4, sign=True))
- assert type_to_def(bv, i32_0) == "enum foo : int32_t\n{\n\tfoo = 0x0\n};"
- i64_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 8, sign=True))
- assert type_to_def(bv, i64_0) == "enum foo : int64_t\n{\n\tfoo = 0x0\n};"
-
- u8_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 1, sign=False))
- assert type_to_def(bv, u8_0) == "enum foo : uint8_t\n{\n\tfoo = 0x0\n};"
- u16_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 2, sign=False))
- assert type_to_def(bv, u16_0) == "enum foo : uint16_t\n{\n\tfoo = 0x0\n};"
- u32_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 4, sign=False))
- assert type_to_def(bv, u32_0) == "enum foo : uint32_t\n{\n\tfoo = 0x0\n};"
- u64_0 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0)], 8, sign=False))
- assert type_to_def(bv, u64_0) == "enum foo : uint64_t\n{\n\tfoo = 0x0\n};"
-
- # Most positive integer
- i8_imax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x7f)], 1, sign=True))
- assert type_to_def(bv, i8_imax) == "enum foo : char\n{\n\tfoo = 0x7f\n};"
- i16_imax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x7fff)], 2, sign=True))
- assert type_to_def(bv, i16_imax) == "enum foo : int16_t\n{\n\tfoo = 0x7fff\n};"
- i32_imax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x7fffffff)], 4, sign=True))
- assert type_to_def(bv, i32_imax) == "enum foo : int32_t\n{\n\tfoo = 0x7fffffff\n};"
- i64_imax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x7fffffffffffffff)], 8, sign=True))
- assert type_to_def(bv, i64_imax) == "enum foo : int64_t\n{\n\tfoo = 0x7fffffffffffffff\n};"
-
- u8_umax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0xff)], 1, sign=False))
- assert type_to_def(bv, u8_umax) == "enum foo : uint8_t\n{\n\tfoo = 0xff\n};"
- u16_umax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0xffff)], 2, sign=False))
- assert type_to_def(bv, u16_umax) == "enum foo : uint16_t\n{\n\tfoo = 0xffff\n};"
- u32_umax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0xffffffff)], 4, sign=False))
- assert type_to_def(bv, u32_umax) == "enum foo : uint32_t\n{\n\tfoo = 0xffffffff\n};"
- u64_umax = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0xffffffffffffffff)], 8, sign=False))
- assert type_to_def(bv, u64_umax) == "enum foo : uint64_t\n{\n\tfoo = 0xffffffffffffffff\n};"
-
- # -1
- i8_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -1)], 1, sign=True))
- assert type_to_def(bv, i8_n1) == "enum foo : char\n{\n\tfoo = -0x1\n};"
- i16_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -1)], 2, sign=True))
- assert type_to_def(bv, i16_n1) == "enum foo : int16_t\n{\n\tfoo = -0x1\n};"
- i32_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -1)], 4, sign=True))
- assert type_to_def(bv, i32_n1) == "enum foo : int32_t\n{\n\tfoo = -0x1\n};"
- i64_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -1)], 8, sign=True))
- assert type_to_def(bv, i64_n1) == "enum foo : int64_t\n{\n\tfoo = -0x1\n};"
-
- # Unsigned equivalent of -1
- u8_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x80)], 1, sign=False))
- assert type_to_def(bv, u8_n1) == "enum foo : uint8_t\n{\n\tfoo = 0x80\n};"
- u16_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x8000)], 2, sign=False))
- assert type_to_def(bv, u16_n1) == "enum foo : uint16_t\n{\n\tfoo = 0x8000\n};"
- u32_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x80000000)], 4, sign=False))
- assert type_to_def(bv, u32_n1) == "enum foo : uint32_t\n{\n\tfoo = 0x80000000\n};"
- u64_n1 = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", 0x8000000000000000)], 8, sign=False))
- assert type_to_def(bv, u64_n1) == "enum foo : uint64_t\n{\n\tfoo = 0x8000000000000000\n};"
-
- # Most negative integer
- i8_imin = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -0x80)], 1, sign=True))
- assert type_to_def(bv, i8_imin) == "enum foo : char\n{\n\tfoo = -0x80\n};"
- i16_imin = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -0x8000)], 2, sign=True))
- assert type_to_def(bv, i16_imin) == "enum foo : int16_t\n{\n\tfoo = -0x8000\n};"
- i32_imin = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -0x80000000)], 4, sign=True))
- assert type_to_def(bv, i32_imin) == "enum foo : int32_t\n{\n\tfoo = -0x80000000\n};"
- i64_imin = Type.enumeration_type(bv.arch, EnumerationBuilder.create([("foo", -0x8000000000000000)], 8, sign=True))
- assert type_to_def(bv, i64_imin) == "enum foo : int64_t\n{\n\tfoo = -0x8000000000000000\n};"
-
-
-class TestMutableTypeBuilder(TestWithBinaryView):
- def test_MutableTypeBuilder(self):
- with Type.builder(self.bv, "Elf32_Dyn") as b:
- assert isinstance(b, StructureBuilder)
- b.append(Type.int(4), "test_field")
-
- b = self.bv.types["Elf32_Dyn"]
- assert isinstance(b, StructureType)
- assert b.member_at_offset(8).name == "test_field"
-
- self.assertRaises(ValueError, lambda: Type.builder(self.bv, None))
-
- with Type.builder(self.bv, None, 'elf:["Elf32_Dyn"]') as b:
- assert isinstance(b, StructureBuilder)
- b.append(Type.int(4), "test_field2")
-
- b = self.bv.types["Elf32_Dyn"]
- assert isinstance(b, StructureType)
- assert b.member_at_offset(12).name == "test_field2"
-
- self.assertRaises(ValueError, lambda: Type.builder(self.bv, None, 'not - elf:["Elf32_Dyn"]'))
- self.assertRaises(ValueError, lambda: Type.builder(self.bv, 'not - elf:["Elf32_Dyn"]'))
-
- with MutableTypeBuilder(self.bv.types["Elf32_Dyn"].mutable_copy(), self.bv, "Elf32_Dyn", None, 255, False) as b:
- b.append(Type.int(4), "test_field2")
-
-
-class TestWithFunction(TestWithBinaryView):
- def setUp(self):
- super().setUp()
- self.func = self.bv.get_functions_by_name("main")[0]
-
- def test_equality(self):
- func1 = self.func
- func2 = self.bv.get_function_at(0x0000848c)
- assert func1 == func1
- assert func1 != func2
- assert func1.start < 0x0000848c
- assert func1 < func2
- assert func1 <= func2
- assert func2 > func1
- assert func2 >= func1
-
- def test_getters(self):
- assert isinstance(self.func[0], BasicBlock)
- it = iter(self.func)
- assert isinstance(next(it), BasicBlock)
- assert next(it) in self.func
- assert self.func.start in self.func
-
- def test_str(self):
- assert str(self.func) == "int32_t main(int32_t argc, char** argv, char** envp)"
-
- def test_indexing(self):
- first_block = self.func[0]
- assert first_block.start == self.func.start
- assert first_block.start == 0x8440
-
- second_third = self.func[1:3]
- assert second_third[0].start == 0x846c
- assert second_third[1].start == 0x8460
-
- self.assertRaises(IndexError, lambda: self.func[5])
- self.assertRaises(IndexError, lambda: self.func[3:6])
- self.assertRaises(ValueError, lambda: self.func['beans'])
-
- def test_name_symbol(self):
- assert self.func.name == "main"
- my_name = "my_name"
- my_name2 = "my_name"
- self.func.name = my_name
- assert self.func.name == my_name
- self.func.name = Symbol(SymbolType.FunctionSymbol, self.func.start, my_name2)
- assert self.func.name == my_name2
- self.func.name = None
- assert self.func.name == "main"
-
- sym = self.func.symbol
- assert sym.type == SymbolType.FunctionSymbol
- assert sym.address == self.func.start
- assert sym.name == self.func.name
-
- def test_view_arch_platform(self):
- assert isinstance(self.bv, BinaryView)
- assert isinstance(self.arch, Architecture)
- assert isinstance(self.plat, Platform)
-
- def test_size_and_addresses(self):
- assert self.func.total_bytes == 68
- assert self.func.lowest_address == 0x8440
- assert self.func.highest_address == 0x8483
- assert len(self.func.address_ranges) == 1
- assert self.func.address_ranges[0].start == 0x8440
- assert self.func.address_ranges[0].end == 0x8484
-
- def test_auto(self):
- assert not self.func.auto
- assert not self.func.has_user_annotations
- # cause a user annotation
- self.func.parameter_vars[0].name = "arg_count"
- assert self.func.has_user_annotations
-
- def test_no_return(self):
- assert self.func.can_return
- self.func.can_return = False
- self.bv.update_analysis_and_wait()
- assert not self.func.can_return
- self.func.can_return = True
- self.bv.update_analysis_and_wait()
- assert self.func.can_return
-
- def test_explicitly_defined_types(self):
- assert self.func.explicitly_defined_type
- func2 = self.bv.get_function_at(0x0000840c)
- assert not func2.explicitly_defined_type
-
- def test_needs_update(self):
- assert not self.func.needs_update
-
- def test_comments(self):
- assert self.func.comments == {}
- self.func.set_comment(0x00008470, "my_comment")
- assert self.func.comments == {0x00008470: 'my_comment'}
- self.func.comment = "Function Level Comment"
- assert self.func.comment == "Function Level Comment"
-
- msg = "A Comment"
- addr = 0x0000845c
- self.func.set_comment_at(addr, msg)
- assert self.func.get_comment_at(addr) == msg
-
- def test_create_tag(self):
- msg1 = "Bugs here"
- msg2 = "Crashes here"
- msg3 = "Library here"
- msg4 = "Important here"
- name1 = "Bugs"
- name2 = "Crashes"
- name3 = "Library"
- name4 = "Important"
- tt1 = self.bv.tag_types[name1]
- tt2 = self.bv.tag_types[name2]
- tt3 = self.bv.tag_types[name3]
- tt4 = self.bv.tag_types[name4]
- tag1 = self.func.create_tag(tt1, msg1, True)
- tag2 = self.func.create_user_tag(tt2, msg2)
- tag3 = self.func.create_auto_tag(tt3, msg3)
- tag4 = self.func.create_auto_tag(tt4, msg4)
-
- assert len(self.func.function_tags) == 0
- self.func.add_user_function_tag(tag1)
- self.func.add_user_function_tag(tag2)
- self.func.add_user_function_tag(tag3)
- t = self.func.create_user_function_tag(tt4, msg4, True)
- t = self.func.create_user_function_tag(tt4, msg4, True)
- tags = self.func.function_tags
- assert len(tags) == 4 == len(self.func.user_function_tags)
- assert tags[0].data == msg1
- assert tags[0].type == tt1
- assert tags[1].data == msg2
- assert tags[1].type == tt2
- assert tags[2].data == msg3
- assert tags[2].type == tt3
- assert tags[3].data == msg4
- assert tags[3].type == tt4
- assert tags[3] == t
-
- assert 1 == len(self.func.get_function_tags_of_type(tt3))
- assert 1 == len(self.func.get_user_function_tags_of_type(tt4))
- assert 0 == len(self.func.get_auto_function_tags_of_type(tt4))
-
- self.func.remove_user_function_tag(tags[0])
- self.func.remove_user_function_tag(tags[1])
- self.func.remove_user_function_tag(tags[2])
- self.func.remove_user_function_tag(tags[3])
- assert len(self.func.function_tags) == 0
-
- addr = self.func.start + 4
-
- assert len(self.func.address_tags) == 0
- self.func.add_user_address_tag(addr, tag1)
- tags = self.func.address_tags
- assert len(tags) == 1
- _, addr, tag = tags[0]
- assert addr == addr
- assert tag.data == msg1
- assert tag.type == tt1
- self.func.remove_user_address_tag(addr, tag)
- assert len(self.func.address_tags) == 0
-
- self.assertRaises(TypeError, lambda: self.func.create_user_address_tag(0, None, None))
-
- t = self.func.create_user_address_tag(addr, tt1, msg1, True)
- t = self.func.create_user_address_tag(addr, tt1, msg1, True)
- tags = self.func.address_tags
- assert len(tags) == 1
- _, addr, tag = tags[0]
- assert t == tag
- assert tag.data == msg1
- assert tag.type == tt1
- self.func.remove_user_address_tag(addr, tag)
- assert len(self.func.address_tags) == 0
-
- assert len(self.func.function_tags) == 0
- self.func.add_auto_function_tag(tag1)
- t = self.func.create_auto_function_tag(tt2, msg2, True)
- t = self.func.create_auto_function_tag(tt2, msg2, True)
- tags = self.func.function_tags
- assert len(tags) == 2 == len(self.func.auto_function_tags)
- assert tags[0].data == msg1
- assert tags[0].type == tt1
- assert tags[1].data == msg2
- assert tags[1].type == tt2
- assert tags[1] == t
- self.func.remove_auto_function_tag(tags[0])
- self.func.remove_auto_function_tag(tags[1])
- assert len(self.func.function_tags) == 0
-
- assert len(self.func.address_tags) == 0
- self.func.add_auto_address_tag(addr, tag1)
- t = self.func.create_auto_address_tag(addr, tt2, msg2, True)
- t = self.func.create_auto_address_tag(addr, tt2, msg2, True)
- tags = self.func.address_tags
- assert len(tags) == 2
- assert t == tags[1][2]
- assert tags[0][2].data == msg1
- assert tags[0][2].type == tt1
- assert tags[1][2].data == msg2
- assert tags[1][2].type == tt2
-
- self.func.get_address_tags_at(addr, self.func.arch)
- assert len(tags) == 2
- assert t == tags[1][2]
- assert tags[0][2].data == msg1
- assert tags[0][2].type == tt1
- assert tags[1][2].data == msg2
- assert tags[1][2].type == tt2
-
- self.func.remove_auto_address_tag(addr, tags[0][2])
- self.func.remove_auto_address_tag(addr, tags[1][2])
- assert len(self.func.address_tags) == 0
-
- t = self.func.create_auto_address_tag(addr, tt2, msg2, True)
- t = self.func.create_auto_address_tag(addr + 4, tt2, msg2, True)
- t = self.func.create_user_address_tag(addr, tt1, msg1, True)
-
- assert 2 == len(self.func.auto_address_tags)
- assert 1 == len(self.func.user_address_tags)
-
- range = variable.AddressRange(addr, 0x8480)
- all_at = self.func.get_address_tags_in_range(range)
- auto_at = self.func.get_auto_address_tags_in_range(range)
- user_at = self.func.get_user_address_tags_in_range(range)
-
- assert len(all_at) == 3
- assert len(auto_at) == 2
- assert len(user_at) == 1
-
- assert 1 == len(self.func.get_auto_address_tags_at(addr))
- assert 1 == len(self.func.get_user_address_tags_at(addr))
-
- assert 1 == len(self.func.get_address_tags_of_type(addr, tt2))
- assert 0 == len(self.func.get_user_address_tags_of_type(addr, tt2))
- assert 1 == len(self.func.get_address_tags_of_type(addr, tt1))
- assert 0 == len(self.func.get_auto_address_tags_of_type(addr, tt1))
-
- t = self.func.create_user_address_tag(addr, tt2, msg1, True)
- self.func.remove_user_address_tags_of_type(addr, tt2)
- assert 0 == len(self.func.get_user_address_tags_of_type(addr, tt2))
- assert 1 == len(self.func.get_user_address_tags_of_type(addr, tt1))
-
- self.func.remove_auto_address_tags_of_type(addr, tt2)
- assert 0 == len(self.func.get_auto_address_tags_of_type(addr, tt2))
-
-
- def test_il_properties(self):
- lifted_il = self.func.lifted_il
- assert isinstance(lifted_il, LowLevelILFunction)
- assert lifted_il == self.func.lifted_il_if_available
-
- llil = self.func.low_level_il
- assert isinstance(llil, LowLevelILFunction)
- assert llil == self.func.llil
- assert llil == self.func.llil_if_available
-
- mlil = self.func.medium_level_il
- assert isinstance(mlil, MediumLevelILFunction)
- assert mlil == self.func.mlil
- assert mlil == self.func.mlil_if_available
-
- mmlil = self.func.llil.mapped_medium_level_il
- assert isinstance(mmlil, MediumLevelILFunction)
- assert mmlil == self.func.mmlil
- assert mmlil == self.func.mmlil_if_available
-
- hlil = self.func.high_level_il
- assert isinstance(hlil, HighLevelILFunction)
- assert hlil == self.func.hlil
- assert hlil == self.func.hlil_if_available
-
- def test_misc_properties(self):
- callees = self.func.callees
- assert len(callees) == 2
-
- callers = self.func.callers
- assert len(callers) == 2
- assert callees[0].start == 0x82dc
- assert callees[1].start == 0x82dc
-
- def test_function_type(self):
- ft = self.func.function_type
- assert ft.return_value == Type.int(4)
- ftm = ft.mutable_copy()
- ftm.return_value = Type.int(4, False)
- assert not ft.user_type
- self.func.function_type = ftm
- assert ft.user_type
- self.func.view.update_analysis_and_wait()
- assert self.func.function_type.return_value == Type.int(4, False), f"{self.func.function_type.return_value} != {Type.int(4, False)}"
- func_str = "int32_t main(int32_t argc, char** argv, char** envp)"
- self.func.function_type = func_str
- self.func.view.update_analysis_and_wait()
- ft1 = self.func.function_type
- ft2 = self.bv.parse_type_string(func_str)[0]
- # ft2's calling convention is None and thus not expected to persist
- assert (ft1.return_value, ft1.parameters) == (ft2.return_value, ft2.parameters), f"{ft1} != {ft2}"
-
- def test_stack_layout(self):
- assert len(self.func.stack_layout) == 5
- assert len(self.func.core_var_stack_layout) == 5
- assert isinstance(self.func.stack_layout[0], Variable)
- assert isinstance(self.func.core_var_stack_layout[0], CoreVariable)
-
- def test_vars(self):
- assert len(self.func.vars) == 10
- assert len(self.func.core_vars) == 10
- assert isinstance(self.func.vars[0], Variable)
- assert isinstance(self.func.core_vars[0], CoreVariable)
-
- def test_indirect_branches(self):
- assert len(self.func.indirect_branches) == 0
- assert len(self.func.unresolved_indirect_branches) == 0
- assert not self.func.has_unresolved_indirect_branches
-
- def test_session_data(self):
- # TODO
- pass
-
- def test_analysis_performance_info(self):
- # TODO is there any better way to test this?
- assert isinstance(self.func.analysis_performance_info['Total'], float)
-
- def test_types(self):
- assert str(self.func.type_tokens[0]) == "int32_t"
- assert str(self.func.type_tokens[2]) == "main"
-
- assert self.func.return_type == Type.int(4, True)
- self.func.return_type = Type.void()
- self.bv.update_analysis_and_wait()
- assert self.func.return_type == Type.void()
- self.func.return_type = "uint64_t"
- self.bv.update_analysis_and_wait()
- assert self.func.return_type == Type.int(8, False)
- self.func.return_type = Type.int(4, True)
- self.bv.update_analysis_and_wait()
- assert self.func.return_type == Type.int(4, True)
- assert len(self.func.return_regs.regs) == 1
- assert self.func.return_regs.regs[0] == "r0"
-
- cc = self.func.calling_convention
- assert cc.name == 'cdecl'
- # clearing the calling convention makes analysis
- self.func.calling_convention = None
- self.bv.update_analysis_and_wait()
- assert self.func.calling_convention != None, f"{self.func.calling_convention} is None"
- self.func.calling_convention = cc
- self.bv.update_analysis_and_wait()
- assert self.func.calling_convention == cc
- self.func.mark_recent_use()
-
- def test_refs(self):
- from_addr = 0x0000843c
- to_addr = 0x00008440
- self.func.add_user_code_ref(from_addr, to_addr)
- refs = list(self.func.view.get_code_refs(from_addr))
-
- f = self.bv.get_functions_by_name("puts")[0]
- refs = list(f.caller_sites)
- assert len(refs) == 2
- assert str(refs[0].llil) == 'call(0x82dc)'
- assert str(refs[1].llil) == 'call(0x82dc)'
-
- assert str(refs[0].mlil) == '0x82dc("helloworld")'
- assert str(refs[1].mlil) == '0x82dc("goodbyeworld")'
-
- assert str(refs[0].hlil) == 'puts("helloworld")'
- assert str(refs[1].hlil) == 'puts("goodbyeworld")'
-
- def test_reg_values(self):
- r0 = self.bv.arch.get_reg_index('r0')
- r3 = self.bv.arch.get_reg_index('r3')
-
- r3_after = self.func.get_reg_value_after(0x8474, r3);
- r0_after = self.func.get_reg_value_after(0x8478, r0);
- r3_at = self.func.get_reg_value_at(0x847c, r3);
- r0_at = self.func.get_reg_value_at(0x847c, r0);
-
- assert r0_after == r0_at
- assert r0_at == 0
-
- assert r3_after == r3_at
- assert r3_at == 0
-
- def test_pvs(self):
- func = self.func
-
- def first_var_by_name(name):
- return [v for v in func.vars if v.name == name][0]
-
- var_10 = first_var_by_name('var_10')
- r3 = first_var_by_name('r3')
-
- func.set_user_var_value(var_10, 0x8450, PossibleValueSet.constant_ptr(0x100))
- func.set_user_var_value(r3, 0x8454, PossibleValueSet.constant(0))
-
- all_vals = func.get_all_user_var_values()
- assert len(all_vals) == 2
- assert all_vals[var_10][ArchAndAddr(func.arch, 0x8450)] == PossibleValueSet.constant_ptr(0x100)
- assert all_vals[r3][ArchAndAddr(func.arch, 0x8454)] == PossibleValueSet.constant(0)
-
- func.clear_user_var_value(var_10, 0x8450)
- all_vals = func.get_all_user_var_values()
- assert len(all_vals) == 1
-
- func.set_user_var_value(var_10, 0x8450, PossibleValueSet.constant_ptr(0x100))
- all_vals = func.get_all_user_var_values()
- assert len(all_vals) == 2
-
- func.clear_all_user_var_values()
- all_vals = func.get_all_user_var_values()
- assert len(all_vals) == 0
-
- def test_auto_user(self):
- params = self.func.parameter_vars
- assert params[0].name == "argc"
- assert params[1].name == "argv"
- assert params[2].name == "envp"
-
- # Parameter variables
- new_params = params[0:2]
- self.func.set_auto_parameter_vars(new_params)
- self.bv.update_analysis()
- assert len(self.func.parameter_vars) == 2
- assert self.func.parameter_vars[0] == new_params[0]
- assert self.func.parameter_vars[1] == new_params[1]
-
- self.func.parameter_vars = [params[2]]
- self.bv.update_analysis_and_wait()
- assert len(self.func.parameter_vars) == 1
- assert self.func.parameter_vars[0] == params[2]
-
- # Can return
- self.func.set_auto_can_return(False)
- self.bv.update_analysis()
- assert self.func.can_return == False
-
- self.func.can_return = True
- self.bv.update_analysis_and_wait()
- assert self.func.can_return == True
-
- # Has variable arguments
- self.func.set_auto_has_variable_arguments(False)
- self.bv.update_analysis()
- assert self.func.has_variable_arguments == False
-
- self.func.has_variable_arguments = True
- self.bv.update_analysis_and_wait()
- assert self.func.has_variable_arguments == True
-
- # Stack adjustment
- self.func.set_auto_stack_adjustment(2)
- self.bv.update_analysis()
- assert self.func.stack_adjustment == 2
-
- self.func.stack_adjustment = 4
- self.bv.update_analysis_and_wait()
- assert self.func.stack_adjustment == 4
-
- # Return type
- rt = Type.int(2)
- rt2 = Type.int(4)
- self.func.set_auto_return_type(rt)
- assert self.func.return_type == rt
- self.func.return_type = rt2
- self.bv.update_analysis_and_wait()
- assert self.func.return_type == rt2
-
- # Indirect branches
- self.func.set_auto_indirect_branches(0x844c, [(self.func.arch, 0x842c)])
- assert len(self.func.indirect_branches) >= 1
- self.func.set_user_indirect_branches(0x844c, [(self.func.arch, 0x8428), (self.func.arch, 0x842c)])
- assert len(self.func.indirect_branches) >= 2
-
- def test_text_renderer(self):
- opts = DisassemblySettings()
- opts.width = 160
- opts.set_option(DisassemblyOption.ShowOpcode)
- assert opts.width == 160
- assert opts.is_option_set(DisassemblyOption.ShowOpcode) == True
-
- dtr = DisassemblyTextRenderer(self.func.hlil, opts)
- assert dtr.il_function == self.func.hlil
- dtr = DisassemblyTextRenderer(self.func.mlil, opts)
- assert dtr.il_function == self.func.mlil
- dtr = DisassemblyTextRenderer(self.func.llil, opts)
- assert dtr.il_function == self.func.llil
- assert dtr.function == self.func
- assert dtr.il == True
-
- annotations = dtr.get_instruction_annotations(0)
- assert annotations != None
-
- (line, _) = next(dtr.get_instruction_text(0))
- assert line
-
- (line, _) = next(dtr.get_disassembly_text(0))
- assert line
-
- pp_lines = dtr.post_process_lines(0, 160, [line])
- assert pp_lines != None
-
- itt = InstructionTextToken(InstructionTextTokenType.TextToken, "beans")
- dtr.add_integer_token(line.tokens, itt, 0)
- dtr.wrap_comment(line.tokens, line, "beans", False)
-
-
-class TestBinaryView(TestWithBinaryView):
- def setUp(self):
- # Switch to clang by default for these tests, since they rely on it
- self.original_parser = Settings().get_string("analysis.types.parserName")
- Settings().set_string("analysis.types.parserName", "ClangTypeParser")
- super().setUp()
-
- def tearDown(self) -> None:
- Settings().set_string("analysis.types.parserName", self.original_parser)
- super().tearDown()
-
- def test_TagType(self):
- tt = self.bv.tag_types["Crashes"]
- t2 = self.bv.tag_types["Bugs"]
- assert repr(tt).startswith("<tag type Crashes: 🛑>")
- assert tt == tt
- assert tt != t2
- assert not (tt == t2)
- assert not (tt != tt)
- assert tt.__eq__(None) == NotImplemented
- assert tt.__ne__(None) == NotImplemented
- assert hash(tt) != hash(t2)
- assert len(tt.id) == len('796636ee-f2c3-4f67-a15e-20571fe37db2')
- assert tt.name == "Crashes"
- tt.name = "More Crashes"
- assert tt.name == "More Crashes"
- assert tt.icon == '🛑'
- tt.icon = '👀'
- assert tt.icon == '👀'
- assert tt.visible
- tt.visible = False
- assert not tt.visible
- assert tt.type == TagTypeType.UserTagType
- tt.type = TagTypeType.NotificationTagType
- assert tt.type == TagTypeType.NotificationTagType
- tt.type = TagTypeType.UserTagType
- assert tt.type == TagTypeType.UserTagType
-
- def test_Tag(self):
- func = self.bv.get_function_at(0x0000836c)
- assert len(func.address_tags) == 1
- arch, addr, tag = func.address_tags[0]
- assert repr(tag).startswith("<tag ")
- assert arch == func.arch
- assert addr == 0x00008390
- assert tag.data == 'Non-code call target 0x0'
- assert tag.type == self.bv.tag_types['Non-code Branch']
- func = self.bv.get_function_at(0x000083a4)
- assert len(func.address_tags) == 1
- _, _, other_tag = func.address_tags[0]
- assert tag == tag
- assert tag != other_tag
- assert tag.__eq__(None) == NotImplemented
- assert tag.__ne__(None) == NotImplemented
- assert hash(tag) != hash(other_tag)
-
- def test_log_api(self):
- bn.log.log_info("If this doesn't work then you `from .log import log` somewhere you shouldn't`")
- assert bn.log.is_output_redirected_to_log
- logger = bn.log.Logger(0, "test_logger")
- logger.log(LogLevel.DebugLog, "debug log")
- logger.log_info("log info")
- logger.log_debug("log debug")
-
- def test_sections(self):
- sections = self.bv.sections
- assert len(sections) == 25, f"section count is {len(sections)} not 25"
- section = sections['.ARM.exidx']
- section2 = sections['.bss']
- assert repr(section) == "<section .ARM.exidx: 0x851c-0x8524>"
- assert len(section) == 8
- assert section == section
- assert section != section2
- assert hash(section) != hash(section2)
- assert hash(section) == hash(section)
- assert section.start in section
- assert section.name == '.ARM.exidx'
- assert section.start == 0x851c
- assert section.linked_section == '.text'
- assert section.info_section == ''
- assert section.info_data == 0
- assert section.align == 4
- assert section.entry_size == 0
- assert section.semantics == SectionSemantics.ReadOnlyDataSectionSemantics
- assert section.auto_defined
- assert section.end == 0x8524
- assert section.type == ''
-
- def test_segments(self):
- segments = self.bv.segments
- segment = segments[0]
- assert len(segments) == 3
- assert len(segment) == 1320
- assert segment == segment
- assert segment != segments[1]
- assert segment.start in segment
- assert segment.start == 0x8000
- assert segment.end == 0x8528
- assert segment.readable
- assert not segment.writable
- assert segment.executable
- assert segment.data_length == 0x528
- assert segment.data_offset == 0x0
- assert segment.data_end == 0x8528
- assert segment.auto_defined
- assert segment.relocation_count == 0
- s2 = segments[1]
- assert s2.relocation_count == 5
- assert s2.relocation_ranges == [(69644, 69648), (69648, 69652), (69652, 69656), (69656, 69660), (69660, 69664)]
- assert s2.relocation_ranges_at(69644) == [(69644, 69648)]
- assert hash(segment) != hash(s2)
-
- def test_binary_data_nofification_default(self):
- bv = self.bv
-
- global results
- results = None
- def simple_complete(self):
- global results
- results = "analysis complete"
- event = bn.AnalysisCompletionEvent(bv, simple_complete)
- bv.update_analysis_and_wait()
- assert results == "analysis complete"
-
- class NotifyTest(bn.BinaryDataNotification):
- pass
-
- test = NotifyTest()
- bv.register_notification(test)
- sacrificial_addr = 0x84fc
-
- type, name = bv.parse_type_string("int foo")
- type_id = Type.generate_auto_type_id("source", name)
-
- bv.define_type(type_id, name, type) # trigger type_defined
- bv.undefine_type(type_id) # trigger type_undefined
- bv.insert(sacrificial_addr, b"AAAA") # trigger data_inserted
- bv.define_data_var(sacrificial_addr, bn.types.Type.int(4)) # trigger data_var_added
- bv.write(sacrificial_addr, b"BBBB") # trigger data_written
- bv.add_function(sacrificial_addr) # trigger function_added
- bv.remove_function(bv.get_function_at(sacrificial_addr)) # trigger function_removed
- bv.undefine_data_var(sacrificial_addr) # trigger data_var_removed
- bv.remove(sacrificial_addr, 4) # trigger data_removed
-
- type, _ = bv.parse_type_string("struct { uint64_t bar; }")
- bv.define_user_type('foo', type)
- bv.define_user_type('bar', "struct { uint64_t bas; }")
- func = bv.get_function_at(0x8440)
- func.return_type = bn.Type.named_type_from_type('foo', type)
- func.name = "foobar" # trigger symbol_added
- func.name = "" # trigger symbol_removed
-
- msg1 = "Bugs here"
- name1 = "Bugs"
- tt1 = self.bv.tag_types[name1]
- tag1 = func.create_tag(tt1, msg1, True)
-
- assert len(func.function_tags) == 0
- func.add_user_function_tag(tag1)
- t = func.create_user_function_tag(tt1, msg1, True)
- tags = func.function_tags
- assert tags[0].data == msg1
- assert tags[0].type == tt1
- func.remove_user_function_tag(tags[0])
-
- bv.update_analysis_and_wait()
- bv.unregister_notification(test)
-
- def test_strings(self):
- string = self.bv.strings[0]
- assert repr(string) == '<AsciiString: 0x8154, len 0x12>', repr(string)
- assert string.value == '/lib/ld-linux.so.3'
- assert string.value == str(string)
- assert len(string) == 18
- assert isinstance(string.raw, bytes)
- assert string.type == StringType.AsciiString
- assert string.length == 18
- assert string.view.name == self.bv.name
-
- def test_analysis_info(self):
- ap = self.bv.analysis_progress
- assert str(ap) == "Idle"
- assert repr(ap) == "<progress: Idle>"
- ai = self.bv.analysis_info
- assert repr(ai) == "<AnalysisInfo 2, analysis_time 0, active_info []>"
- ap = AnalysisProgress(AnalysisState.InitialState, 0, 0)
- assert str(ap) == "Initial"
- ap = AnalysisProgress(AnalysisState.HoldState, 0, 0)
- assert str(ap) == "Hold"
- ap = AnalysisProgress(AnalysisState.DisassembleState, 0, 0)
- assert str(ap).startswith("Disassembling")
- ap = AnalysisProgress(AnalysisState.AnalyzeState, 0, 0)
- assert str(ap).startswith("Analyzing")
- ap = AnalysisProgress(-1, 0, 0)
- assert str(ap) == "Extended Analysis"
-
- def test_symbolmapping(self):
- syms = self.bv.symbols
- assert repr(syms).startswith('<SymbolMapping ')
- assert next(self.bv.symbols)[0].name == "__elf_header"
- assert next(iter(self.bv.symbols)) == "__elf_header"
- assert "__elf_header" in syms
- for a in self.bv.symbols.keys():
- assert a == "__elf_header"
- break
- for a in self.bv.symbols.values():
- assert a[0].name == "__elf_header"
- break
- for a, b in self.bv.symbols.items():
- assert a == b[0].name
- break
- assert syms.get("__elf_header")[0].name == "__elf_header"
- assert syms.get("not_a_symbol", 0x41414141) == 0x41414141
- assert "foobar" not in syms
-
- def test_typemapping(self):
- tm = self.bv.types
- assert repr(tm).startswith("<TypeMapping")
- self.assertRaises(KeyError, lambda: tm["not a type"])
- self.assertRaises(KeyError, lambda: self.bv.types["not a type"])
- assert next(iter(tm))[0] == 'Elf32_Dyn'
- assert 'Elf32_Dyn' in self.bv.types
- assert 'asldkfjasd' not in self.bv.types
- assert tm == tm
- assert not (tm != tm)
- for a in self.bv.types.keys():
- assert a == "Elf32_Dyn"
- break
- for a in self.bv.types.values():
- assert a.registered_name.name == "Elf32_Dyn"
- break
- for a, b in self.bv.types.items():
- assert a == b.registered_name.name
- break
- assert tm.get("Elf32_Dyn").registered_name.name == "Elf32_Dyn"
- assert tm.get("not a type", 0x41414141) == 0x41414141
-
- def test_functionlist(self):
- bv = self.bv
- assert bv.functions[0] == bv.functions[0:1][0]
- self.assertRaises(IndexError, lambda: bv.functions[100000000])
- self.assertRaises(IndexError, lambda: bv.functions[0:100000000])
- self.assertRaises(ValueError, lambda: bv.functions["asdf"])
-
- def test_datavariable(self):
- dv = self.bv.data_vars[0x11048] #extern puts
- dv2 = self.bv.data_vars[0x1100c] # .got entry puts
- dv3 = self.bv.data_vars[0x8000] # elf header
-
- assert list(dv.data_refs) == [0x1100c]
- assert list(dv2.data_refs_from) == [0x11048]
- ref = list(dv2.code_refs)[0]
- assert ref.address == 0x82e4
- assert len(dv2) == 4
- assert dv.value is None
- assert dv2.value == dv.address
- assert dv2.type.type_class == TypeClass.PointerTypeClass
- assert dv3['ident']['os'].value == 0
- assert dv3.value["ident"]["os"] == 0
- dv3['ident']['os'].value = 1
- assert dv3['ident']['os'].value == 1
- assert dv3.symbol.name == "__elf_header"
- assert dv3.name == dv3.symbol.name
- dv3.name = "foo"
- assert dv3.name == "foo"
- dv3.name = ""
- assert dv3.name == "__elf_header"
- assert dv3.symbol.type == SymbolType.DataSymbol
- dv3.symbol = Symbol(SymbolType.ImportedDataSymbol, dv3.address, "foobar")
- assert dv3.name == "foobar"
- assert dv3.symbol.type == SymbolType.ImportedDataSymbol
- assert len(dv3._accessor) == 52
- dv.type = dv2.type
- assert dv.type.type_class == dv2.type.type_class
- assert dv.auto_discovered
- dv4 = self.bv.data_vars[0x00010f14]
- assert dv4.value == 0
- dv4.value = 1
- assert dv4.value == 1
- assert self.bv.data_vars[0x0000850c].name is None
-
- here = 0x10fd8
- self.bv.define_data_var(here, "float16")
- assert self.bv.data_vars[here].value == 0.0
- assert len(self.bv.data_vars[here]) == 2
- self.bv.data_vars[here].value = 2.0
- assert self.bv.data_vars[here].value == 2.0
- self.bv.data_vars[here].value = 0.0
- self.bv.define_data_var(here, "float")
- assert self.bv.data_vars[here].value == 0.0
- assert len(self.bv.data_vars[here]) == 4
- self.bv.data_vars[here].value = 2.0
- assert self.bv.data_vars[here].value == 2.0
- self.bv.data_vars[here].value = 0.0
- self.bv.define_data_var(here, "double")
- assert self.bv.data_vars[here].value == 0.0
- assert len(self.bv.data_vars[here]) == 8
- self.bv.data_vars[here].value = 2.0
- assert self.bv.data_vars[here].value == 2.0
- self.bv.data_vars[here].value = 0.0
-
- self.bv.define_data_var(here, "bool")
- assert not self.bv.data_vars[here].value
- self.bv.data_vars[here].value = True
- assert self.bv.data_vars[here].value
- self.bv.data_vars[here].value = False
-
- self.bv.define_data_var(here, "wchar16 foo[4]")
- self.bv.data_vars[here].value = "fooo".encode("utf-16-le")
- assert self.bv.data_vars[here].value == "fooo"
- self.bv.data_vars[here].value = b"\x00" * 8
-
- self.bv.define_data_var(here, "wchar16")
- self.bv.data_vars[here].value = "A".encode("utf-16-le")
- assert self.bv.data_vars[here].value == "A"
- self.bv.data_vars[here].value = b"\x00"
-
- self.bv.define_data_var(here, "struct marplehead { int x; int y;}") # Stella named this type
- assert self.bv.data_vars[here]["x"].value == 0
- self.bv.data_vars[here]["x"].value = -1
- assert self.bv.data_vars[here]["x"].value == -1
- self.bv.data_vars[here]["x"].value = 0
- assert self.bv.data_vars[here].value["x"] == 0
-
- self.bv.define_data_var(here, "enum barplehead : uint64_t { FOO = 0, BAR = 2 }") # Stella named this type
- assert self.bv.data_vars[here].value.value == 0
- self.bv.data_vars[here].value = 2
- assert self.bv.data_vars[here].value.value == 2
- self.bv.data_vars[here].value = 0
-
- self.bv.define_data_var(here, "uint8_t farplehead[8]") # Stella named this type
- assert self.bv.data_vars[here].value == b"\x00" * 8
- self.bv.data_vars[here].value = b"\xff" * 8
- assert self.bv.data_vars[here].value == b"\xff" * 8
- self.bv.data_vars[here].value = b"\x00" * 8
-
- self.bv.define_data_var(here, "int32_t garplehead[2]") # Stella named this type
- assert self.bv.data_vars[here].value == [0, 0]
- assert self.bv.data_vars[here][0].value == 0
- self.bv.data_vars[here].value = b"\xff" * 8
- assert self.bv.data_vars[here].value == [-1, -1]
- assert self.bv.data_vars[here][0].value == -1
- self.bv.data_vars[here].value = b"\x00" * 8
-
- def test_libraries(self):
- assert self.bv.libraries == ['libc.so.6']
-
- def test_reader_writer(self):
- r = self.bv.reader(self.bv.start)
- w = self.bv.writer(self.bv.start)
- r2 = self.bv.reader(self.bv.end)
- assert not self.bv.modified
- assert r.read8(self.bv.start) == 127
- assert r.read16(self.bv.start) == 17791
- assert r.read32(self.bv.start) == 1179403647
- assert r.read64(self.bv.start) == 282579962709375
- assert r.read(8, self.bv.start) == b'\x7fELF\x01\x01\x01\x00'
-
- # Also test the bv.__getitem__ as its very similar
- assert self.bv[self.bv.start:self.bv.start+8] == b'\x7fELF\x01\x01\x01\x00'
- assert self.bv[self.bv.start] == b'\x7f'
- assert self.bv[(self.bv.start + 1, self.bv.start + 3)] == b'EF'
- self.assertRaises(IndexError, lambda:self.bv[0:1:4])
- assert self.bv[self.bv.start + 8:self.bv.start + 0] == b''
- assert self.bv[-5:-1] == b'\x00\x00\x00\x00'
- self.assertRaises(IndexError, lambda: self.bv[-1000000000000])
- self.assertRaises(IndexError, lambda: self.bv[0x8529]) # past the end of a segment
- self.assertRaises(IndexError, lambda: self.bv[0x8529-self.bv.end]) # past the end of a segment
- assert 0x8527 in self.bv
- assert 0x8529 not in self.bv
-
- assert r.read16le(self.bv.start) == 17791
- assert r.read32le(self.bv.start) == 1179403647
- assert r.read64le(self.bv.start) == 282579962709375
- assert r.read16be(self.bv.start) == 32581
- assert r.read32be(self.bv.start) == 2135247942
- assert r.read64be(self.bv.start) == 9170820079758147840
-
- assert r.endianness == Endianness.LittleEndian
- r.endianness = Endianness.BigEndian
- assert r.endianness == Endianness.BigEndian
-
- assert r.read8(self.bv.start) == 127
- assert r.read16(self.bv.start) == 32581
- assert r.read32(self.bv.start) == 2135247942
- assert r.read64(self.bv.start) == 9170820079758147840
- assert r.read(8, self.bv.start) == b'\x7fELF\x01\x01\x01\x00'
- assert r.read16le(self.bv.start) == 17791
- assert r.read32le(self.bv.start) == 1179403647
- assert r.read64le(self.bv.start) == 282579962709375
- assert r.read16be(self.bv.start) == 32581
- assert r.read32be(self.bv.start) == 2135247942
- assert r.read64be(self.bv.start) == 9170820079758147840
-
- assert r.read8(self.bv.end) is None
- assert r.read16(self.bv.end) is None
- assert r.read32(self.bv.end) is None
- assert r.read64(self.bv.end) is None
- assert r.read(8, self.bv.end) is None
- assert r.read16le(self.bv.end) is None
- assert r.read32le(self.bv.end) is None
- assert r.read64le(self.bv.end) is None
- assert r.read16be(self.bv.end) is None
- assert r.read32be(self.bv.end) is None
- assert r.read64be(self.bv.end) is None
-
- assert r == r
- assert r != r2
- assert hash(r) == hash(r)
- assert hash(r) != hash(r2)
- r.offset = self.bv.start
- assert r.offset == self.bv.start
- r.read8()
- assert r.offset == self.bv.start + 1
- r.offset += 1
- assert r.offset == self.bv.start + 2
- assert not r.eof
- r.offset = self.bv.end
- assert r.eof
- r.seek(self.bv.start)
- assert r.offset == self.bv.start
- r.seek_relative(1)
- assert r.offset == self.bv.start + 1
-
- w2 = self.bv.writer(self.bv.end)
- assert w == w
- assert w != w2
- assert hash(w) != hash(w2)
- assert w.endianness == Endianness.LittleEndian
-
- w.write8(0x41, self.bv.start)
- assert r.read8(self.bv.start) == 0x41
- w.write16(0x4242, self.bv.start)
- assert r.read16(self.bv.start) == 0x4242
- w.write32(0x43434343, self.bv.start)
- assert r.read32(self.bv.start) == 0x43434343
- w.write64(0x4444444444444444, self.bv.start)
- assert r.read64(self.bv.start) == 0x4444444444444444
-
- w.offset = self.bv.start
- assert w.offset == self.bv.start
- w.write8(4)
- assert w.offset == self.bv.start + 1
- w.offset += 1
- assert w.offset == self.bv.start + 2
- w.seek(self.bv.start)
- assert w.offset == self.bv.start
- w.seek_relative(1)
- assert w.offset == self.bv.start + 1
-
- w.write8(0x41, self.bv.start)
- assert r.read8(self.bv.start) == 0x41
- w.write16(0x4242, self.bv.start)
- assert r.read16(self.bv.start) == 0x4242
- w.write32(0x43434343, self.bv.start)
- assert r.read32(self.bv.start) == 0x43434343
- w.write64(0x4444444444444444, self.bv.start)
- assert r.read64(self.bv.start) == 0x4444444444444444
- assert self.bv.read_int(self.bv.start, 8, False, Endianness.LittleEndian) == 0x4444444444444444
- assert self.bv.read_pointer(self.bv.start) == 0x44444444
-
- value = b'\x45\x46\x47\x48'
- self.bv[self.bv.start + 0: self.bv.start + 4] = value
- assert self.bv[self.bv.start + 0: self.bv.start + 4] == value
- self.assertRaises(IndexError, lambda: self.bv[0:4:2])
- assert self.bv[self.bv.start + 4: self.bv.start + 0] == b""
- self.bv[-len(self.bv)] = b'\x01'
- assert self.bv[-len(self.bv)] == b'\x01'
-
- w.write16le(0x4142, self.bv.start)
- assert r.read16le(self.bv.start) == 0x4142
- w.write32le(0x43444546, self.bv.start)
- assert r.read32le(self.bv.start) == 0x43444546
- w.write64le(0x4748494a4b4c4d4e, self.bv.start)
- assert r.read64le(self.bv.start) == 0x4748494a4b4c4d4e
-
- w.write16be(0x4142, self.bv.start)
- assert r.read16be(self.bv.start) == 0x4142
- w.write32be(0x43444546, self.bv.start)
- assert r.read32be(self.bv.start) == 0x43444546
- w.write64be(0x4748494a4b4c4d4e, self.bv.start)
- assert r.read64be(self.bv.start) == 0x4748494a4b4c4d4e
-
- assert w.endianness == Endianness.LittleEndian
- w.endianness = Endianness.BigEndian
- assert r.endianness == Endianness.BigEndian
-
- w.write8(0x41, self.bv.start)
- assert r.read8(self.bv.start) == 0x41
- w.write16(0x4242, self.bv.start)
- assert r.read16be(self.bv.start) == 0x4242
- w.write32(0x43434343, self.bv.start)
- assert r.read32be(self.bv.start) == 0x43434343
- w.write64(0x4444444444444444, self.bv.start)
- assert r.read64be(self.bv.start) == 0x4444444444444444
-
- w.write16le(0x4142, self.bv.start)
- assert r.read16le(self.bv.start) == 0x4142
- w.write32le(0x43444546, self.bv.start)
- assert r.read32le(self.bv.start) == 0x43444546
- w.write64le(0x4748494a4b4c4d4e, self.bv.start)
- assert r.read64le(self.bv.start) == 0x4748494a4b4c4d4e
-
- w.write16be(0x4142, self.bv.start)
- assert r.read16be(self.bv.start) == 0x4142
- w.write32be(0x43444546, self.bv.start)
- assert r.read32be(self.bv.start) == 0x43444546
- w.write64be(0x4748494a4b4c4d4e, self.bv.start)
- assert r.read64be(self.bv.start) == 0x4748494a4b4c4d4e
-
- reloc_start = self.bv.relocation_ranges[0][0]
- self.assertRaises(RelocationWriteException, lambda: w.write(b'1', reloc_start, except_on_relocation=True))
- self.assertRaises(RelocationWriteException, lambda: w.write8(1, reloc_start, except_on_relocation=True))
- self.assertRaises(RelocationWriteException, lambda: w.write16(1, reloc_start, except_on_relocation=True))
- self.assertRaises(RelocationWriteException, lambda: w.write32(1, reloc_start, except_on_relocation=True))
- self.assertRaises(RelocationWriteException, lambda: w.write64(1, reloc_start, except_on_relocation=True))
-
- # Ensure these don't raise
- w.write(b'1', reloc_start, except_on_relocation=False)
- w.write8(1, reloc_start, except_on_relocation=False)
- w.write16(1, reloc_start, except_on_relocation=False)
- w.write32(1, reloc_start, except_on_relocation=False)
- w.write64(1, reloc_start, except_on_relocation=False)
-
- assert self.bv.modified
-
- def test_parse_expression(self):
- assert self.bv.eval("0x10 + 0x10") == 0x20
- self.assertRaises(ValueError, lambda: self.bv.eval("asdflkja + wlekjlxkj"))
-
- def test_load_settings_type_names(self):
- assert self.bv.get_load_settings_type_names() == []
-
- def test_bv_comments(self):
- self.bv.set_comment_at(self.bv.start, "This is a comment")
- assert self.bv.get_comment_at(self.bv.start) == "This is a comment"
- assert self.bv.address_comments == {self.bv.start : "This is a comment"}
-
- def test_bv_sections(self):
- assert self.bv.get_unique_section_names(['foo', 'foo']) == ["foo", "foo#1"]
- sec = self.bv.get_section_by_name('.ARM.exidx')
- assert sec.name == '.ARM.exidx'
- assert self.bv.get_section_by_name("Not a section") is None
- assert self.bv.get_sections_at(sec.start)[0].name == sec.name
- self.bv.add_user_section("foo", sec.start, len(sec))
- assert "foo" in [s.name for s in self.bv.get_sections_at(sec.start)]
- self.bv.remove_user_section("foo")
- assert "foo" not in [s.name for s in self.bv.get_sections_at(sec.start)]
-
- self.bv.add_auto_section("foo", sec.start, len(sec))
- assert "foo" in [s.name for s in self.bv.get_sections_at(sec.start)]
- self.bv.remove_auto_section("foo")
- assert "foo" not in [s.name for s in self.bv.get_sections_at(sec.start)]
-
- def test_get_data_offset_for_address(self):
- assert self.bv.get_data_offset_for_address(self.bv.start) == 0
- assert self.bv.get_data_offset_for_address(-1) is None
- assert self.bv.get_address_for_data_offset(0) == self.bv.start
- assert self.bv.get_address_for_data_offset(-1) is None
-
- def test_bv_segments(self):
- seg_start = self.bv.end
- seg_len = 0x1000
- orig_seg_count = len(self.bv.segments)
- assert self.bv.get_segment_at(-1) is None
- self.bv.add_user_segment(seg_start, seg_len, 0, 0, SegmentFlag.SegmentReadable)
- seg = self.bv.get_segment_at(seg_start)
- assert orig_seg_count + 1 == len(self.bv.segments)
- assert seg.start == seg_start
- assert seg.end == seg_start + seg_len
- assert seg.data_offset == 0
- assert seg.data_length == 0
- assert seg.readable and not seg.writable and not seg.executable
- assert self.bv.end == seg_start + seg_len
- self.bv.remove_user_segment(seg_start, seg_len)
- assert self.bv.end == seg_start
- assert orig_seg_count == len(self.bv.segments)
-
-
- self.bv.add_auto_segment(seg_start, seg_len, 0, 0, SegmentFlag.SegmentReadable)
- seg = self.bv.get_segment_at(seg_start)
- assert orig_seg_count + 1 == len(self.bv.segments)
- assert seg.start == seg_start
- assert seg.end == seg_start + seg_len
- assert seg.data_offset == 0
- assert seg.data_length == 0
- assert seg.readable and not seg.writable and not seg.executable
- assert self.bv.end == seg_start + seg_len
- self.bv.remove_auto_segment(seg_start, seg_len)
- assert self.bv.end == seg_start
- assert orig_seg_count == len(self.bv.segments)
-
-
- def test_rebase(self):
- rebase_addr = self.bv.start + 0x1000
- rebased_bv = self.bv.rebase(rebase_addr)
- assert rebased_bv.start == rebase_addr
-
- # TODO: Figure out why this code doesn't work
- # called_back = False
- # def progress(cur, total):
- # global called_back
- # called_back = True
- # return True
- # bv2 = self.bv.rebase(self.bv.start + 0x1000, True, progress)
- # bv2.update_analysis_and_wait()
- # assert called_back
-
- def test_reanalyze(self):
- assert self.bv.reanalyze() is None
-
- def test_properties(self):
- assert not self.bv.parse_only
- limit = self.bv.preload_limit
- assert isinstance(limit, int)
- self.bv.preload_limit = 10
- assert self.bv.preload_limit == 10
- self.bv.preload_limit = limit
- assert self.bv.parent_view.parent_view is None
- assert not self.bv.has_database
- assert self.bv.view == 'Hex:Raw'
- self.bv.view = 'Linear:ELF'
- assert self.bv.view == 'Hex:Raw' # Apparently these aren't settable from a headless script
- assert self.bv.offset == 0
- self.bv.offset = self.bv.start + 8
- assert self.bv.offset == 0 # Apparently these aren't settable from a headless script
- assert not self.bv.relocatable
- assert self.bv.executable
- assert self.bv.has_functions
- assert self.bv.has_data_variables
- assert self.bv.saved # TODO I assume this API is broken as it returns true even when not the file hasn't been saved
- assert self.bv.has_symbols
- assert self.bv.type_names[0] == 'Elf32_Dyn'
- assert self.bv.global_pointer_value.type == RegisterValueType.UndeterminedValue
-
- def test_blocks(self):
- assert isinstance(next(self.bv.basic_blocks), BasicBlock)
- assert isinstance(next(self.bv.llil_basic_blocks), LowLevelILBasicBlock)
- assert isinstance(next(self.bv.mlil_basic_blocks), MediumLevelILBasicBlock)
- assert isinstance(next(self.bv.hlil_basic_blocks), HighLevelILBasicBlock)
- tokens, addr = next(self.bv.instructions)
- assert isinstance(addr, int)
- assert isinstance(tokens[0], InstructionTextToken)
-
- def test_instructions(self):
- assert isinstance(next(self.bv.llil_instructions), LowLevelILInstruction)
- assert isinstance(next(self.bv.mlil_instructions), MediumLevelILInstruction)
- assert isinstance(next(self.bv.hlil_instructions), HighLevelILInstruction)
-
- def test_functions(self):
- assert isinstance(next(self.bv.mlil_functions()), MediumLevelILFunction)
- assert isinstance(next(self.bv.hlil_functions()), HighLevelILFunction)
-
- def test_define_types(self):
- self.bv.define_user_type("foo", "int")
- self.bv.define_user_type(None, type_obj="int bas")
- self.assertRaises(SyntaxError, lambda:self.bv.define_user_type(None, type_obj="a"))
- assert self.bv.get_type_by_name("foo") == Type.int(4, True)
- assert self.bv.get_type_by_name("bas") == Type.int(4, True)
- self.bv.rename_type("foo", "bar")
- assert self.bv.get_type_by_name("bar") == Type.int(4, True)
- self.bv.undefine_user_type("bar")
- assert self.bv.get_type_by_name("bar") is None
-
- type_id = "some unique string"
- type_name = "some name"
- self.bv.define_type(type_id, type_name, "int")
- assert self.bv.get_type_by_name(type_name) == Type.int(4, True)
- assert self.bv.is_type_auto_defined(type_name)
- t = self.bv.get_type_by_name(type_name)
- assert type_id == self.bv.get_type_id(type_name)
- assert self.bv.get_type_name_by_id(type_id) == type_name
-
- def test_type_libraries(self):
- tl = self.bv.get_type_library('libc_armv7.so.6')
- assert tl.name == 'libc_armv7.so.6'
- assert self.bv.get_type_library('not a type library') is None
- self.assertRaises(ValueError, lambda: self.bv.add_type_library("asdf"))
- self.bv.add_type_library(tl)
- assert self.bv.type_libraries[0].name == tl.name
-
- def test_parse_types(self):
- source = r"""
- int foo;
- struct baz { int x; int y; };
- int bar(int bas) { return bas; }
- """
- result = self.bv.parse_types_from_string(source)
- assert result.variables["foo"] == Type.int(4)
- s = result.types["baz"]
- s2 = Type.structure([(Type.int(4), "x"), (Type.int(4), "y")])
- assert s.members == s2.members
- a = Type.function(Type.int(4), [("bas", Type.int(4))], calling_convention=self.bv.platform.default_calling_convention)
- b = result.functions["bar"]
- assert a.calling_convention == b.calling_convention
- assert a.return_value == b.return_value
- assert a.parameters == b.parameters
-
- self.assertRaises(ValueError, lambda: self.bv.parse_type_string(None))
- self.assertRaises(SyntaxError, lambda: self.bv.parse_type_string("a"))
- self.assertRaises(ValueError, lambda: self.bv.parse_types_from_string(None))
- self.assertRaises(SyntaxError, lambda: self.bv.parse_types_from_string("a"))
-
- def test_disassembly_tokens(self):
- address = self.bv.get_symbols_by_name("main")[0].address
- tokens, size = next(self.bv.disassembly_tokens(address))
- assert size == 4
- assert str(tokens[0]) == "push"
- string, size = next(self.bv.disassembly_text(address))
- assert size == 4
- assert string.startswith("push")
- assert self.bv.get_disassembly(address).startswith("push")
-
- def test_is_offset_x(self):
- writable_addr = 0x00010f0c
- sec_addr = self.bv.sections['.text'].start
- extern_seg = self.bv.segments[-1].start
- writable_semantics = 0x00011028
- assert self.bv.is_valid_offset(self.bv.start)
- assert not self.bv.is_valid_offset(self.bv.end)
-
- assert self.bv.is_offset_readable(self.bv.start)
- assert not self.bv.is_offset_readable(self.bv.end)
-
- assert self.bv.is_offset_writable(writable_addr)
- assert not self.bv.is_offset_writable(self.bv.start)
-
- assert self.bv.is_offset_executable(self.bv.start)
- assert not self.bv.is_offset_executable(extern_seg)
-
- assert self.bv.is_offset_code_semantics(sec_addr)
- assert not self.bv.is_offset_code_semantics(0x00008154)
-
- assert self.bv.is_offset_extern_semantics(extern_seg)
- assert not self.bv.is_offset_extern_semantics(self.bv.start)
-
- assert self.bv.is_offset_writable_semantics(writable_semantics)
- assert not self.bv.is_offset_writable_semantics(extern_seg)
-
-
-class TestBinaryViewType(unittest.TestCase):
- def test_binaryviewtype(self):
- self.assertRaises(KeyError, lambda: bn.BinaryViewType['not_a_binary_view'])
- bvt = BinaryViewType["PE"]
- bvt2 = BinaryViewType["ELF"]
- assert repr(bvt) == "<view type: 'PE'>"
- assert bvt == bvt
- assert bvt != bvt2
- assert hash(bvt) != hash(bvt2)
- assert bvt.name == "PE"
- assert bvt.long_name == "PE"
- assert not bvt.is_deprecated
- assert bvt2.get_arch(3, Endianness.LittleEndian) == Architecture["x86"]
- assert bvt2.get_platform(0, Architecture["x86"]) == Platform["linux-x86"]
- with FileApparatus("helloworld") as filename:
- with bn.load(filename) as bv:
- assert bvt2.is_valid_for_data(bv.parent_view)
- assert isinstance(bvt2.parse(bv.parent_view), BinaryView)
-
-
-class TestArchitecture(TestWithBinaryView):
- def test_available_patches_x86(self):
- x86 = binaryninja.Architecture["x86"]
-
- je_0 = x86.assemble("je 0")
- call_0 = x86.assemble("call 0")
- jmp_eax = x86.assemble("jmp eax")
-
- assert x86.is_never_branch_patch_available(je_0, 0) == True
- assert x86.is_never_branch_patch_available(call_0, 0) == False
-
- assert x86.is_always_branch_patch_available(je_0, 0) == True
- assert x86.is_always_branch_patch_available(call_0, 0) == False
-
- assert x86.is_invert_branch_patch_available(je_0, 0) == True
- assert x86.is_invert_branch_patch_available(call_0, 0) == False
-
- assert x86.is_skip_and_return_zero_patch_available(call_0, 0) == True
- assert x86.is_skip_and_return_zero_patch_available(jmp_eax, 0) == False
-
- assert x86.is_skip_and_return_value_patch_available(call_0, 0) == True
- assert x86.is_skip_and_return_value_patch_available(jmp_eax, 0) == False
-
- assert x86.convert_to_nop(je_0, 0) == b'\x90\x90\x90\x90\x90\x90'
- assert x86.always_branch(je_0, 0) == b'\x90\xe9\xfa\xff\xff\xff'
- assert x86.invert_branch(je_0, 0) == b'\x0f\x85\xfa\xff\xff\xff'
- assert x86.skip_and_return_value(je_0, 0, 0) == b'\xb8\x00\x00\x00\x00\x90'
-
- def test_available_typelibs(self):
- assert len(self.bv.arch.type_libraries) > 0
-
-
-class LowLevelILTests(TestWithBinaryView):
- def setUp(self):
- super().setUp()
- self.assertEqual(self.bv.arch.name, Architecture['armv7'].name, "hello-world is not armv7?")
- self.func = self.bv.get_functions_by_name("main")[0]
- self.llil = self.func.low_level_il
-
- def assertIsOptionalInstance(self, item, optional_type):
- assert (isinstance(item, optional_type) or item is None)
-
- def test_dataclasses(self):
- llil_label = LowLevelILLabel()
- self.assertIsNotNone(llil_label.handle)
-
- sem_flag_class = ILSemanticFlagClass(Architecture['aarch64'], 1)
- self.assertIsInstance(sem_flag_class.__str__(), str)
- self.assertEqual(sem_flag_class.__str__(), sem_flag_class.name)
- self.assertIsInstance(sem_flag_class.__repr__(), str)
- self.assertIsInstance(sem_flag_class.__int__(), int)
-
- sem_flag_group = ILSemanticFlagGroup(Architecture['aarch64'], 1)
- self.assertIsInstance(sem_flag_group.__str__(), str)
- self.assertEqual(sem_flag_group.__str__(), sem_flag_group.name)
- self.assertIsInstance(sem_flag_group.__repr__(), str)
- self.assertIsInstance(sem_flag_group.__int__(), int)
-
- intrinsic = ILIntrinsic(Architecture['aarch64'], 0)
- self.assertIsInstance(intrinsic.__str__(), str)
- self.assertIsInstance(intrinsic.__repr__(), str)
- self.assertIsInstance(intrinsic.name, str)
-
- func = LowLevelILFunction(arch=Architecture['aarch64'])
- const = func.const(8, 0x1111)
- func.append(const)
- const = func.const(8, 0x2222)
- func.append(const)
- const = func.const(8, 0x1111)
- func.append(const)
- func.finalize()
-
- const_1 = func.basic_blocks[0].disassembly_text[0].il_instruction
- const_2 = func.basic_blocks[0].disassembly_text[1].il_instruction
- const_3 = func.basic_blocks[0].disassembly_text[2].il_instruction
-
- self.assertTrue(const_1)
- self.assertEqual(int(const_1), 0x1111)
- self.assertEqual(const_1, const_3)
- self.assertNotEqual(const_1, const_2)
- self.assertLess(const_1, const_2)
- self.assertLessEqual(const_1, const_3)
- self.assertGreater(const_2, const_1)
- self.assertGreaterEqual(const_1, const_3)
- self.assertIsInstance(const_1.__hash__(), int)
-
- def test_ILRegister(self):
- x86_reg_0 = ILRegister(arch=Architecture['x86'], index=RegisterIndex(0))
- x86_reg_0_dup = ILRegister(arch=Architecture['x86'], index=RegisterIndex(0))
- x86_reg_1 = ILRegister(arch=Architecture['x86'], index=RegisterIndex(1))
- arm_reg_0 = ILRegister(arch=Architecture['armv7'], index=RegisterIndex(0))
- arm_reg_1 = ILRegister(arch=Architecture['armv7'], index=RegisterIndex(1))
- arm_reg_bad = ILRegister(arch=Architecture['armv7'], index=None)
-
- self.assertEqual(x86_reg_0.index, int(x86_reg_0))
-
- self.assertEqual(x86_reg_0, x86_reg_0_dup, "Register equality not properly implemented")
- self.assertNotEqual(x86_reg_0, x86_reg_1, "Register inequality not properly implemented")
- self.assertNotEqual(x86_reg_0, arm_reg_0, "Register inequality not properly implemented")
- self.assertEqual(arm_reg_0, "r0", "Register equality when 'other' is a string not properly implemented")
- self.assertEqual(arm_reg_0.__eq__(["definitely", "not", "a", "reg", "or", "string"]), NotImplemented)
- self.assertEqual(arm_reg_0.name, 'r0', "Passthrough of arm register zero name is incorrect")
-
- self.assertEqual(arm_reg_0.info.index, 0, "Register Info Index is incorrect")
- self.assertEqual(arm_reg_1.info.index, 1, "Register Info Index is incorrect")
-
- def test_LLILInstruction(self):
- create_instr = LowLevelILInstruction.create(self.func.low_level_il, 1)
-
- self.assertIsNotNone(create_instr)
-
- instrs = list(self.llil.instructions)
- instr = list(self.llil.instructions)[1]
- self.assertEqual(instr.__eq__("not_a_llil_instruction"), NotImplemented)
- self.assertEqual(instr.__ne__("not_a_llil_instruction"), NotImplemented)
- self.assertEqual(instr.__lt__("not_a_llil_instruction"), NotImplemented)
- self.assertEqual(instr.__le__("not_a_llil_instruction"), NotImplemented)
- self.assertEqual(instr.__gt__("not_a_llil_instruction"), NotImplemented)
- self.assertEqual(instr.__ge__("not_a_llil_instruction"), NotImplemented)
-
- self.assertEqual(instr, instrs[1])
- self.assertNotEqual(instr, instrs[0])
-
- self.assertLess(instr, instrs[2])
- self.assertLessEqual(instr, instrs[1])
-
- self.assertGreater(instr, instrs[0])
- self.assertGreaterEqual(instr, instrs[1])
-
- self.assertNotEqual(hash(instr), 0)
-
- self.assertEqual(instr.size, 4) # armv7, all ins are length 4
-
- self.assertEqual(instr.operation, LowLevelILOperation.LLIL_PUSH)
-
- self.assertGreater(instr.il_basic_block.length, 0)
- self.assertIsNotNone(instr.il_basic_block.source_block)
-
- self.assertIsNotNone(instr.mmlil)
-
- pv = instr.get_possible_values()
- self.assertIsNotNone(pv)
- self.assertIsInstance(pv, PossibleValueSet)
-
- rv = instr.get_reg_value(RegisterIndex(0))
- self.assertIsInstance(rv, RegisterValue)
-
- rva = instr.get_reg_value_after(RegisterIndex(0))
- self.assertIsInstance(rva, RegisterValue)
-
- prv = instr.get_possible_reg_values(RegisterIndex(0))
- self.assertIsNotNone(prv)
- self.assertIsInstance(prv, PossibleValueSet)
-
- prva = instr.get_possible_reg_values_after(RegisterIndex(0))
- self.assertIsNotNone(prva)
- self.assertIsInstance(prva, PossibleValueSet)
-
- reg_ssa_list = instr._get_reg_ssa_list(0)
- self.assertIsInstance(reg_ssa_list, list)
- for item in reg_ssa_list:
- self.assertIsInstance(item, SSARegister)
-
- reg_stack_ssa_list = instr._get_reg_stack_ssa_list(0)
- self.assertIsInstance(reg_stack_ssa_list, list)
- for item in reg_stack_ssa_list:
- self.assertIsInstance(item, SSARegisterStack)
-
- flag_ssa_list = instr._get_flag_ssa_list(0)
- self.assertIsInstance(flag_ssa_list, list)
- for item in flag_ssa_list:
- self.assertIsInstance(item, SSAFlag)
-
- reg_or_flag_ssa_list = instr._get_reg_or_flag_ssa_list(0)
- self.assertIsInstance(reg_or_flag_ssa_list, list)
- for item in reg_or_flag_ssa_list:
- self.assertIsInstance(item, SSARegisterOrFlag)
-
- def test_LLILFunction(self):
- arch = self.bv.arch
- source_func = self.func
-
- # func_no_handle = LowLevelILFunction(arch=arch, handle=None, source_func=source_func)
- func_no_source_func = LowLevelILFunction(arch=arch, handle=core.BNCreateLowLevelILFunction(arch.handle, self.func.handle), source_func=None)
- # func_no_arch = LowLevelILFunction(arch=None, handle=core.BNCreateLowLevelILFunction(arch.handle, self.func.handle), source_func=source_func)
-
- assert len(list(self.func.llil_instructions)) != 0
- assert len(self.llil) == len(list(self.llil.instructions))
-
- self.assertRaises(Exception, lambda: LowLevelILFunction())
-
- ins_count: ExpressionIndex = len(self.llil)
- self.assertRaises(IndexError, lambda: self.llil[1:3])
- self.assertRaises(IndexError, lambda: self.llil[ins_count])
- self.assertRaises(IndexError, lambda: self.llil[(-ins_count) - 1])
- self.assertEqual(self.llil[ins_count-1], self.llil[-1])
- self.assertRaises(IndexError, lambda: self.llil.__setitem__('a', 'b'))
-
- addr = self.llil.current_address
- self.assertIsInstance(addr, int)
- self.llil.current_address = addr + 8
- self.assertEqual(self.llil.current_address, addr + 8)
- self.llil.current_address = addr
-
- self.llil.set_current_address(addr + 16, arch=None)
- self.assertEqual(self.llil.current_address, addr + 16)
- self.llil.current_address = addr
- self.llil.set_current_address(addr + 32)
- self.assertEqual(self.llil.current_address, addr + 32)
-
- self.assertIsInstance(self.llil.temp_reg_count, int)
- self.assertIsInstance(self.llil.temp_flag_count, int)
-
- self.assertIsInstance(self.llil.mlil, MediumLevelILFunction)
- self.assertIsInstance(self.llil.mapped_medium_level_il, MediumLevelILFunction)
-
- self.assertEqual(self.llil.mmlil, self.llil.mapped_medium_level_il)
-
- self.llil.arch = Architecture['x86_64']
- self.assertEqual(self.llil.arch, Architecture['x86_64'])
- self.llil.arch = Architecture['armv7']
-
- self.llil.source_function = None
- self.assertIsNone(self.llil.source_function)
- self.llil.source_function = self.func
-
- ssa_rs = self.llil.ssa_register_stacks
- self.assertIsInstance(ssa_rs, list)
- for reg_stack in ssa_rs:
- self.assertIsInstance(reg_stack, SSARegisterStack)
-
- ssa_flags = self.llil.ssa_flags
- self.assertIsInstance(ssa_flags, list)
- for flag in ssa_flags:
- self.assertIsInstance(flag, SSAFlag)
-
- mem_versions = self.llil.memory_versions
- self.assertIsInstance(mem_versions, list)
- for value in mem_versions:
- self.assertIsInstance(value, int)
-
- self.llil.source_function = None
- self.assertEqual(self.llil.vars, [])
- self.llil.source_function = self.func
-
- instruction_index = 0
- addr = list(self.llil.instructions)[instruction_index].address
- self.assertEqual(self.llil.get_instruction_start(addr), instruction_index)
- self.assertEqual(self.llil.get_instruction_start(addr, arch=None), instruction_index)
-
- expr_index = self.llil.intrinsic([34], 'SetExclusiveMonitors', [0, 1])
- self.assertIsInstance(expr_index, int)
-
- self.llil.append(self.llil.nop())
-
- self.llil.add_label_for_address(self.func.arch, addr)
- self.assertIsInstance(self.llil.get_label_for_address(self.func.arch, addr), LowLevelILLabel)
-
- index = self.llil.get_high_level_il_instruction_index(InstructionIndex(0))
- self.assertIsOptionalInstance(index, int)
-
- index = self.llil.get_high_level_il_expr_index(0)
- self.assertIsOptionalInstance(index, int)
-
- new_func = LowLevelILFunction(arch=Architecture['aarch64'])
-
- self.assertEqual(new_func.il_form, FunctionGraphType.InvalidILViewType)
- self.assertEqual(new_func.ssa_registers, [])
- self.assertEqual(new_func.vars, [])
-
- def do_il_expression_test(self, target_function, prefix_args, llil_instruction_type, const_args=0, suffix_args=None):
- """
- Helper function for testing LowLevelILFunction Expression generators
- Without this function, the next block of code takes up almost half of this file.
-
- :param target_function: Target function to test
- :param prefix_args: Arguments before we pass the const expressions as arguments
- :param llil_instruction_type: LowLevelILInstruction type this function should append to the LLILFunc
- :param const_args: int amount of const expressions we need to create and pass as arguments.
- :param suffix_args: Argumemts after we pass the const expressions as arguments
- :return: ILInstruction instance that was appended.
- """
- if suffix_args is None:
- suffix_args = []
-
- func = LowLevelILFunction(arch=Architecture['aarch64'])
- function_args = [func] + prefix_args
- const_val = 0
-
- const = func.const(8, const_val)
- func.append(const)
-
- target_expr_index = 1
- for i in range(const_args):
- const = func.const(8, const_val)
- const_val += 8
- func.append(const)
- function_args.append(const)
- target_expr_index += 1
-
- function_args += suffix_args
-
- expression = target_function(*function_args)
-
- func.append(expression)
- func.finalize()
-
- self.assertEqual(func.basic_blocks[0].disassembly_text[target_expr_index].il_instruction.__class__, llil_instruction_type,
- f"LowLevelILFunction.{target_function.__name__} didn't append expected "
- f"{llil_instruction_type.__name__} instruction")
-
- return func.basic_blocks[0].disassembly_text[target_expr_index].il_instruction
-
- def test_individual_expressions(self):
-
- with self.assertRaises(AssertionError, msg="do_il_expression_test not failing properly."):
- self.do_il_expression_test(LowLevelILFunction.nop, prefix_args=[], llil_instruction_type=LowLevelILConst)
-
- """
- The function this method primarily uses has a docstring explaining it, but essentially, pass the function attribute,
- args as a list, the class we should verify it matches,
- however many consts you need to create and inject into the args,
- and then any args that come after the consts.
-
- It will verify it appends the proper ILInstruction subclass, then will return that ILInstruction, in the event
- you need to do any further testing.
- """
-
- self.do_il_expression_test(target_function=LowLevelILFunction.nop, prefix_args=[], llil_instruction_type=LowLevelILNop)
- self.do_il_expression_test(LowLevelILFunction.const, [8, 0x1234], LowLevelILConst)
- self.do_il_expression_test(LowLevelILFunction.set_reg, [8, RegisterName('x0')], LowLevelILSetReg, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.set_reg_stack_top_relative, [8, 0, 0, 0], LowLevelILSetRegStackRel)
- self.do_il_expression_test(LowLevelILFunction.reg_stack_push, [8, 0, 0], LowLevelILRegStackPush)
- self.do_il_expression_test(LowLevelILFunction.load, [8, 0], LowLevelILLoad)
- self.do_il_expression_test(LowLevelILFunction.store, [8, 0, 0x8], LowLevelILStore)
- self.do_il_expression_test(LowLevelILFunction.push, [8, 0x0], LowLevelILPush)
- self.do_il_expression_test(LowLevelILFunction.pop, [8], LowLevelILPop)
- self.do_il_expression_test(LowLevelILFunction.reg, [8, 'x0'], LowLevelILReg)
- self.do_il_expression_test(LowLevelILFunction.reg_split, [16, 'x3', 'x4'], LowLevelILRegSplit)
- self.do_il_expression_test(LowLevelILFunction.reg_stack_top_relative, [4, 0, 0], LowLevelILRegStackRel)
- self.do_il_expression_test(LowLevelILFunction.reg_stack_push, [8, 0, 0x4], LowLevelILRegStackPush)
- self.do_il_expression_test(LowLevelILFunction.reg_stack_pop, [8, 0], LowLevelILRegStackPop)
- self.do_il_expression_test(LowLevelILFunction.const_pointer, [8, 0x100000000], LowLevelILConstPtr)
- self.do_il_expression_test(LowLevelILFunction.reloc_pointer, [8, 0x100000000], LowLevelILExternPtr)
- self.do_il_expression_test(LowLevelILFunction.float_const_raw, [8, 0x4141414141414141], LowLevelILFloatConst)
- self.do_il_expression_test(LowLevelILFunction.float_const_single, [12345.678], LowLevelILFloatConst)
- self.do_il_expression_test(LowLevelILFunction.float_const_double, [12345.678], LowLevelILFloatConst)
- self.do_il_expression_test(LowLevelILFunction.undefined, [], LowLevelILUndef)
- self.do_il_expression_test(LowLevelILFunction.breakpoint, [], LowLevelILBp)
- self.do_il_expression_test(LowLevelILFunction.trap, [0], LowLevelILTrap)
- self.do_il_expression_test(LowLevelILFunction.add, [8], LowLevelILAdd, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.add_carry, [8], LowLevelILAdc, const_args=3)
- self.do_il_expression_test(LowLevelILFunction.sub, [8], LowLevelILSub, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.sub_borrow, [8], LowLevelILSbb, const_args=3)
- self.do_il_expression_test(LowLevelILFunction.and_expr, [8], LowLevelILAnd, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.or_expr, [8], LowLevelILOr, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.xor_expr, [8], LowLevelILXor, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.shift_left, [8], LowLevelILLsl, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.logical_shift_right, [8], LowLevelILLsr, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.arith_shift_right, [8], LowLevelILAsr, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.shift_left, [8], LowLevelILLsl, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.rotate_left, [8], LowLevelILRol, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.rotate_left_carry, [8], LowLevelILRlc, const_args=3)
- self.do_il_expression_test(LowLevelILFunction.rotate_right_carry, [8], LowLevelILRrc, const_args=3)
- self.do_il_expression_test(LowLevelILFunction.rotate_right, [8], LowLevelILRor, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mult, [8], LowLevelILMul, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mult_double_prec_signed, [8], LowLevelILMulsDp, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mult_double_prec_unsigned, [8], LowLevelILMuluDp, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.div_signed, [8], LowLevelILDivs, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.div_double_prec_signed, [8], LowLevelILDivsDp, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.div_unsigned, [8], LowLevelILDivu, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.div_double_prec_unsigned, [8], LowLevelILDivuDp, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mod_signed, [8], LowLevelILMods, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mod_double_prec_signed, [8], LowLevelILModsDp, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mod_unsigned, [8], LowLevelILModu, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.mod_double_prec_unsigned, [8], LowLevelILModuDp, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.neg_expr, [8], LowLevelILNeg, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.not_expr, [8], LowLevelILNot, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.sign_extend, [8], LowLevelILSx, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.zero_extend, [8], LowLevelILZx, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.low_part, [8], LowLevelILLowPart, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.jump, [], LowLevelILJump, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.call, [], LowLevelILCall, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.tailcall, [], LowLevelILTailcall, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.ret, [], LowLevelILRet, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.no_ret, [], LowLevelILNoret)
- self.do_il_expression_test(LowLevelILFunction.compare_equal, [8], LowLevelILCmpE, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_not_equal, [8], LowLevelILCmpNe, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_signed_less_than, [8], LowLevelILCmpSlt, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_unsigned_less_than, [8], LowLevelILCmpUlt, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_signed_less_equal, [8], LowLevelILCmpSle, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_unsigned_less_equal, [8], LowLevelILCmpUle, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_signed_greater_than, [8], LowLevelILCmpSgt, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_unsigned_greater_than, [8], LowLevelILCmpUgt, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_signed_greater_equal, [8], LowLevelILCmpSge, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.compare_unsigned_greater_equal, [8], LowLevelILCmpUge, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.test_bit, [8], LowLevelILTestBit, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.system_call, [], LowLevelILSyscall)
- self.do_il_expression_test(LowLevelILFunction.unimplemented, [], LowLevelILUnimpl)
- self.do_il_expression_test(LowLevelILFunction.unimplemented_memory_ref, [8], LowLevelILUnimplMem, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.float_add, [8], LowLevelILFadd, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_sub, [8], LowLevelILFsub, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_mult, [8], LowLevelILFmul, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_div, [8], LowLevelILFdiv, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_sqrt, [8], LowLevelILFsqrt, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.float_neg, [8], LowLevelILFneg, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.float_to_int, [8], LowLevelILFloatToInt, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.int_to_float, [8], LowLevelILIntToFloat, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.float_convert, [8], LowLevelILFloatConv, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.round_to_int, [8], LowLevelILRoundToInt, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.floor, [8], LowLevelILFloor, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.ceil, [8], LowLevelILCeil, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.float_trunc, [8], LowLevelILFtrunc, const_args=1)
- self.do_il_expression_test(LowLevelILFunction.float_compare_equal, [8], LowLevelILFcmpE, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_not_equal, [8], LowLevelILFcmpNe, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_less_than, [8], LowLevelILFcmpLt, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_less_equal, [8], LowLevelILFcmpLe, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_greater_than, [8], LowLevelILFcmpGt, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_greater_equal, [8], LowLevelILFcmpGe, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_ordered, [8], LowLevelILFcmpO, const_args=2)
- self.do_il_expression_test(LowLevelILFunction.float_compare_unordered, [8], LowLevelILFcmpUo, const_args=2)
-
-
-# class TestObjectiveCPlugin(unittest.TestCase):
-# def setUp(self):
-# with FileApparatus("calculator_macOS12_arm64e") as path:
-# bv = load(
-# os.path.relpath(path),
-# options={"workflows.enable": True, "workflows.functionWorkflow": "core.function.objectiveC"}
-# )
-# bv.update_analysis_and_wait()
-
-# self.bv: BinaryView = bv
-# self.arch: Architecture = self.bv.arch
-# self.plat: Platform = self.bv.platform
-
-# def test_function_nat(self):
-# f = self.bv.get_function_at(0x10000667c)
-# ft = f.function_type
-
-# # Ensure return value and parameter types are being set
-# assert "CGFloat" == str(ft.return_value)
-# assert len(ft.parameters) >= 2
-# assert "SEL" in str(ft.parameters[1])
-
-# # Ensure function names are being set
-# assert "doubleValue" in f.name
-
-# def test_data_vars_created(self):
-# dv1 = self.bv.get_data_var_at(0x1000331a0)
-# dv2 = self.bv.get_data_var_at(0x10001f4b0)
-
-# # Ensure data variables are being created
-# assert "class" in str(dv1.type)
-# assert "method" in str(dv2.type)
-
-# def test_method_call_resolution(self):
-# f = self.bv.get_function_at(0x10000667c)
-# assert f
-
-# # Lazier way of checking that the method call rewriting worked
-# assert "actualValuePeriodDecimal" in str(f.hlil)
-# assert "doubleValue" in str(f.hlil)
diff --git a/suite/binaries b/suite/binaries
deleted file mode 160000
-Subproject 93c0d2647f32bbc42d8f23088f91a44bd305412
diff --git a/suite/generator.py b/suite/generator.py
deleted file mode 100755
index 9bb34ad3..00000000
--- a/suite/generator.py
+++ /dev/null
@@ -1,471 +0,0 @@
-#!/usr/bin/env python3
-import pickle
-import sys
-import os
-import zipfile
-from optparse import OptionParser
-import testcommon
-import time
-
-#Prevent user settings or plugins from impacting unit tests
-os.environ["BN_DISABLE_USER_PLUGINS"] = "True"
-os.environ["BN_DISABLE_USER_SETTINGS"] = "True"
-os.environ["BN_DISABLE_REPOSITORY_PLUGINS"] = "True"
-
-if sys.version_info.major == 2:
- print("Generate unit tests on Python 3. Python 2 is not compatible.")
- sys.exit(1)
-
-unit_test_template = """#!/usr/bin/env python3
-# This is an auto generated unit test file do not edit directly
-import os
-import sys
-import unittest
-import pickle
-import zipfile
-import difflib
-from collections import Counter
-
-#Prevent user settings or plugins from impacting unit tests
-os.environ["BN_DISABLE_USER_PLUGINS"] = "True"
-os.environ["BN_DISABLE_USER_SETTINGS"] = "True"
-os.environ["BN_DISABLE_REPOSITORY_PLUGINS"] = "True"
-
-api_suite_path = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), {4}))
-sys.path.append(api_suite_path)
-# support direct invocation of configuration unit.py
-commondir = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", ".."))
-sys.path.append(commondir)
-
-debugger_suite_path = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", "..",
- "public", "debugger", "test"))
-sys.path.append(debugger_suite_path)
-
-import config
-import testcommon
-import api_test
-import debugger_test
-
-
-class TestBinaryNinja(unittest.TestCase):
- # Returns a tuple of:
- # bool : Two lists are equal
- # string : The string diff
- # Args:
- # list
- # list : (compare list one vs list two)
- # string : anything additional wanted to be printed before the string diff
- # bool : the ordering of the items in the two lists must be the same
- def report(self, oracle, test, firstText='', strictOrdering = False):
- stringDiff = ""
-
- equality = False
- if not strictOrdering:
- equality = (Counter(oracle) == Counter(test))
- else:
- equality = (oracle == test)
-
- if equality:
- return (True, '')
- elif not strictOrdering:
- try:
- for elem in oracle:
- test.remove(elem)
- oracle.remove(elem) # If it's not in the test, it won't get here!
- except ValueError:
- pass
-
- differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
- skipped_lines = 0
- for delta in differ.compare(oracle, test):
- if delta[0] == ' ':
- skipped_lines += 1
- continue
- if skipped_lines > 0:
- stringDiff += "<---" + str(skipped_lines) + ' same lines--->\\n'
- skipped_lines = 0
- delta = delta.replace(\'\\n\', '')
- stringDiff += delta + \'\\n\'
-
- stringDiffList = stringDiff.split(\'\\n\')
-
- if len(stringDiffList) > 10:
- if not config.verbose:
- stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList[:10])
- stringDiff += \'\\n\\n### And ' + str(len(stringDiffList)) + " more lines, use '-v' to show ###"
- elif not config.verbose:
- stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList)
- stringDiff = \'\\n\\n\' + firstText + stringDiff
- return (equality, stringDiff)
-
- @classmethod
- def setUpClass(self):
- self.builder = testcommon.TestBuilder("{3}")
- pickle_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "oracle.pkl")
- try:
- # Python 2 does not have the encodings option
- self.oracle_test_data = pickle.load(open(pickle_path, "rb"), encoding='utf8')
- except TypeError:
- self.oracle_test_data = pickle.load(open(pickle_path, "rb"))
- self.verifybuilder = testcommon.VerifyBuilder("{3}")
-
- def run_binary_test(self, testfile, oracle_suffix="", config_settings=None):
- testname = None
- with zipfile.ZipFile(os.path.join(api_suite_path, testfile), "r") as zf:
- testname = zf.namelist()[0]
- zf.extractall(path=api_suite_path)
-
- pickle_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), testname + oracle_suffix + ".pkl")
- self.assertTrue(pickle_path, "Test pickle doesn't exist")
- try:
- # Python 2 does not have the encodings option
- binary_oracle = pickle.load(open(pickle_path, "rb"), encoding='utf8')
- except TypeError:
- binary_oracle = pickle.load(open(pickle_path, "rb"))
-
- test_builder = testcommon.BinaryViewTestBuilder(testname, config_settings)
- for method in test_builder.methods():
- test = getattr(test_builder, method)()
- oracle = binary_oracle[method]
- if test == oracle:
- continue
-
- result = getattr(test_builder, method).__doc__
- result += ":\\n"
- report = self.report(oracle, test, result)
- self.assertTrue(report[0], report[1]) # Test does not agree with oracle
- os.unlink(os.path.join(api_suite_path, testname))
-{1}{2}
-
-def filter_test_suite(suite, keyword):
- result = unittest.TestSuite()
- for child in suite._tests:
- if type(child) == unittest.suite.TestSuite:
- result.addTest(filter_test_suite(child, keyword))
- elif keyword.lower() in child._testMethodName.lower():
- result.addTest(child)
- return result
-
-def main():
- test_keyword = None
- if len(sys.argv) > 1:
- for i in range(1, len(sys.argv)):
- if sys.argv[i] == '-v' or sys.argv[i] == '-V' or sys.argv[i] == '--verbose':
- config.verbose = True
- elif sys.argv[i] == '--api-only':
- config.api_only = True
- elif sys.argv[i] == '--debugger-only':
- config.debugger_only = True
- else:
- # otherwise the argument is taken as a test case search keyword
- test_keyword = sys.argv[i]
-
- if config.api_only:
- runner = unittest.TextTestRunner(verbosity=2)
- test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test)
- elif config.debugger_only:
- runner = unittest.TextTestRunner(verbosity=2)
- test_suite = unittest.defaultTestLoader.loadTestsFromModule(debugger_test)
- else:
- runner = unittest.TextTestRunner(verbosity=2)
- test_suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinja)
- test_suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(api_test))
-
- # if test keyword supplied, filter
- if test_keyword:
- test_suite = filter_test_suite(test_suite, test_keyword)
-
- runner.run(test_suite)
-
-if __name__ == "__main__":
- main()
-"""
-
-
-binary_test_string = """
- def test_binary__{0}(self):
- self.run_binary_test('{1}', oracle_suffix='{2}', config_settings={3})
-"""
-
-test_string = """
- def {0}(self):
- oracle = self.oracle_test_data['{0}']
- test = self.builder.{0}()
- report = self.report(oracle, test)
- self.assertTrue(report[0], report[1]) # Test does not agree with oracle
-"""
-
-verify_string = """
- def {0}(self):
- self.assertTrue(self.verifybuilder.{0}(), self.{0}.__doc__)
-"""
-
-
-class OracleTestFile:
- def __init__(self, filename):
- self.f = open(filename + ".pkl", "wb")
- self.pkl = pickle.Pickler(self.f, protocol=2)
- self.filename = filename
- self.oracle_test_data = {}
-
- def add_entry(self, builder, test_name):
- self.oracle_test_data[test_name] = getattr(builder, test_name)()
-
- def close(self):
- self.pkl.dump(self.oracle_test_data)
- self.f.close()
-
-
-class UnitTestFile:
- def __init__(self, filename, outdir, test_store):
- self.filename = filename
- self.test_store = test_store
- self.outdir = outdir
- self.f = open(filename, "wb")
- self.template = unit_test_template
- self.tests = ""
- self.binary_tests = ""
-
- def close(self):
- api_path = os.path.relpath(os.path.dirname(os.path.realpath(__file__)), start=self.outdir)
- api_path = os.path.normpath(api_path)
- api_path = map(lambda x: '"{0}"'.format(x), api_path.split(os.sep))
- api_path = '{0}'.format(', '.join(api_path))
- test_store = self.test_store.replace(os.sep, '/') if os.name == 'nt' else self.test_store
- self.f.write(self.template.format(self.outdir, self.tests, self.binary_tests, test_store, api_path).encode('utf8'))
- self.f.close()
-
- def add_verify(self, test_name):
- self.tests += verify_string.format(test_name)
-
- def add_test(self, test_name):
- self.tests += test_string.format(test_name)
-
- def add_binary_test(self, test_store, binary, oracle_suffix="", config_settings=None):
- name = binary[len(test_store):].replace(os.path.sep, "_").replace(".", "_")
- if os.name == 'nt':
- binary = binary.replace(os.sep, '/')
- name += oracle_suffix
- self.binary_tests += binary_test_string.format(name, binary + ".zip", oracle_suffix, config_settings)
-
-
-quiet = False
-def myprint(stuff):
- if not quiet:
- print(stuff)
-
-
-def update_progress(complete, total, description, done=False):
- n = 20
- maxdesc = 70
- if total == 0:
- total, complete = 10, 10
- if len(description) > maxdesc:
- description = description[:maxdesc]
- elif len(description) < maxdesc:
- description += ' ' * (maxdesc - len(description))
-
- if not quiet:
- sys.stdout.write('\r[{0}{1}] {2:10.0f}% - {3}'.format('#' * int(n * (float(complete) / total)), ' ' * (n - int(n * (float(complete) / total))), 100 * float(complete) / total, description))
- if done:
- sys.stdout.write("\n")
-
-
-class TestStoreError(Exception):
- def __init__(self, *args, **kwargs):
- Exception.__init__(self, *args, **kwargs)
-
-
-def generate(test_store, outdir, exclude_binaries, config_settings=None):
- if not os.path.isdir(os.path.join(os.path.dirname(__file__), test_store)):
- raise TestStoreError("Specified test store is not a directory")
-
- if not os.path.exists(outdir):
- os.makedirs(outdir)
-
- unittest = UnitTestFile(os.path.join(outdir, "unit.py"), outdir, test_store)
- oracle = OracleTestFile(os.path.join(outdir, "oracle"))
-
- # check all files to see if there is any newly added ones.
- # If so, create a zip archive for it and delete the original file
- allfiles = sorted(testcommon.get_file_list(test_store))
- for progress, testfile in enumerate(allfiles):
- oraclefile = None
- zip_only = False
- if testfile.endswith(".gitignore"):
- continue
- if testfile.endswith(".pkl"):
- continue
- elif testfile.endswith(".DS_Store"):
- continue
- elif testfile.endswith(".zip"):
- continue
- else:
- if os.path.exists(testfile + ".zip"):
- # We've got a zip file for it, skip
- continue
-
- # create the zip archive for the file
- if not os.path.exists(testfile + ".zip"):
- with zipfile.ZipFile(testfile + ".zip", "w") as zf:
- zf.write(testfile, os.path.relpath(testfile, start=os.path.dirname(__file__)))
-
- os.unlink(testfile)
-
- # Generate the tests that don't involve binaries but do involve oracles
- builder = testcommon.TestBuilder(test_store)
- tests = builder.methods()
- for progress, test_name in enumerate(tests):
- update_progress(progress, len(tests), "Generating test data")
- oracle.add_entry(builder, test_name)
- unittest.add_test(test_name)
- update_progress(len(tests), len(tests), "Generating test data", True)
-
- # Generate the tests that just verify things work as expected
- verify = testcommon.VerifyBuilder(test_store)
- tests = verify.methods()
- for progress, test_name in enumerate(tests):
- update_progress(progress, len(tests), "Generating verify data")
- unittest.add_verify(test_name)
- update_progress(len(tests), len(tests), "Generating verify data", True)
-
- # Now generate test that involve binaries
- allfiles = sorted(testcommon.get_file_list(test_store))
- total_progress = len(allfiles)
- for progress, testfile in enumerate(allfiles):
- oraclefile = None
- zip_only = False
- # # Disable the pe_thumb test because it is causing many test failures
- # if 'pe_thumb' in testfile:
- # continue
- if testfile.endswith(".gitignore"):
- continue
- if testfile.endswith(".pkl"):
- continue
- elif testfile.endswith(".DS_Store"):
- continue
- elif testfile.endswith(".bndb"):
- # For databases, we do not wish to create oracle data for them
- # However, we do wish them to be zipped
- zip_only = True
- oraclefile = testfile
- elif testfile.endswith(".bndb.zip"):
- continue
- elif testfile.endswith(".zip"):
- # We have a zipped binary unzip it so we can rebaseline
- with zipfile.ZipFile(testfile, "r") as zf:
- zf.extractall(path = os.path.dirname(__file__))
- if not os.path.exists(testfile[:-4]):
- print("Error extracting testfile %s from zip: %s" % (testfile[:-4], testfile))
- continue
- oraclefile = testfile[:-4]
- else:
- if os.path.exists(testfile + ".zip"):
- # We've got a binary and zip for that binary just skip it
- continue
- # We have a binary that isn't zipped use it as a new test case
- oraclefile = testfile
-
- # create the zip archive for the file
- if not os.path.exists(oraclefile + ".zip"):
- with zipfile.ZipFile(oraclefile + ".zip", "w") as zf:
- zf.write(oraclefile, os.path.relpath(oraclefile, start=os.path.dirname(__file__)))
-
- if zip_only:
- os.unlink(oraclefile)
- continue
-
- testfile_basename = os.path.basename(oraclefile)
- testfile_rel = os.path.relpath(oraclefile, start=os.path.dirname(__file__))
- oraclefile_basepath = testfile_rel[:-len(testfile_basename)]
- oraclefile_rel = os.path.join(oraclefile_basepath, testfile_basename)
-
- # Create directory for pickle oracle results
- if not os.path.exists(os.path.join(outdir, oraclefile_basepath)):
- os.makedirs(os.path.join(outdir, oraclefile_basepath))
-
- config_settings_for_file = config_settings
- if testfile_basename in ['pe_thumb']:
- config_settings_for_file = {**config_settings_for_file, **{'analysis.gratuitousFunctionUpdate': True}}
-
- # Now generate the oracle data
- update_progress(progress, len(allfiles), oraclefile_rel)
- unittest.add_binary_test(test_store, testfile_rel, config_settings=config_settings_for_file)
- binary_start_time = time.time()
- if exclude_binaries:
- continue
- test_data = testcommon.BinaryViewTestBuilder(testfile_rel, config_settings_for_file)
- binary_oracle = OracleTestFile(os.path.join(outdir, oraclefile_rel))
- for method in test_data.methods():
- binary_oracle.add_entry(test_data, method)
- binary_oracle.close()
- print("{0:.2f}".format(time.time() - binary_start_time))
-
- # Generate oracle data for rebasing tests
- if testfile_basename in ["helloworld", "duff", "partial_register_dataflow", "raw"]:
- oracle_suffix = "_rebasing"
- rebasing_options = {**config_settings_for_file, **{'loader.imageBase' : 0xf00000}}
- unittest.add_binary_test(test_store, testfile_rel, oracle_suffix, rebasing_options)
- test_data = testcommon.BinaryViewTestBuilder(testfile_rel, rebasing_options)
- binary_oracle = OracleTestFile(os.path.join(outdir, oraclefile_rel) + oracle_suffix)
- for method in test_data.methods():
- binary_oracle.add_entry(test_data, method)
- binary_oracle.close()
-
- os.unlink(oraclefile)
-
- update_progress(total_progress, total_progress, "Generating binary unit tests complete", True)
- unittest.close()
- oracle.close()
-
-
-def main():
- usage = "usage: %prog [-q] [-x] [-o <dir>] [-i <dir>]"
- parser = OptionParser(usage=usage)
- default_output = os.path.relpath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, "suite", "generated"))
- parser.add_option("-q", "--quiet",
- dest="quiet", action="store_true",
- default=False, help="Don't print anything")
- parser.add_option("-x", "--exclude",
- dest="exclude_binary", action="store_true",
- default=False, help="Exclude regeneration of binaries")
- parser.add_option("-o", "--outputdir", default=default_output,
- dest="outputdir", action="store", type="string",
- help="output directory where the unit.py and oracle.py files will be stored (relative to cwd)")
- parser.add_option("-i", "--inputdir", default=os.path.join("binaries", "test_corpus"),
- dest="test_store", action="store", type="string",
- help="input directory containing the binaries you which to generate unit tests from (relative to this file)")
- parser.add_option("-a", "--analysismodes",
- dest="analysis_modes", action="store_true",
- default=False, help="Generate additional oracle files to support analysis mode testing")
-
- options, args = parser.parse_args()
-
- test_store_location = os.path.relpath(os.path.join(testcommon.BinaryViewTestBuilder.get_root_directory(), options.test_store))
- myprint(f"[+] INFO: Input Test Corpus: {test_store_location}")
- if len(testcommon.get_file_list(options.test_store)) == 0:
- myprint(f"ERROR: Test Corpus is empty: {testcommon.get_file_list(options.test_store)}")
- sys.exit(1)
-
- configurations = {}
- configurations['default'] = {}
- if options.analysis_modes:
- configurations['mode_controlflow'] = {'analysis.mode' : 'controlFlow'}
- configurations['mode_basic'] = {'analysis.mode' : 'basic'}
- configurations['mode_intermediate'] = {'analysis.mode' : 'intermediate'}
-
- myprint("[+] INFO: Generating Automated Unit Tests and Oracle Results")
- for (name, config_settings) in configurations.items():
- oracle_target = os.path.join(options.outputdir, name)
- myprint(f"[+] INFO: Oracle Target Directory: {oracle_target}")
- try:
- generate(options.test_store, oracle_target, options.exclude_binary, config_settings)
- myprint(f"[+] SUCCESS: Generated Results for the '{name}' Configuration")
- except TestStoreError as te:
- myprint(f"[-] ERROR: Failed to Generate Results for the '{name}' Configuration: {te.message}")
- sys.exit(1)
- sys.exit(0)
-
-
-if __name__ == "__main__":
- main()
diff --git a/suite/pwnadventurez.nes b/suite/pwnadventurez.nes
deleted file mode 100644
index 630684e3..00000000
--- a/suite/pwnadventurez.nes
+++ /dev/null
Binary files differ
diff --git a/suite/testcommon.py b/suite/testcommon.py
deleted file mode 100644
index d0271588..00000000
--- a/suite/testcommon.py
+++ /dev/null
@@ -1,2306 +0,0 @@
-import tempfile
-import os
-import sys
-import zipfile
-import inspect
-from platform import system
-import binaryninja as binja
-from binaryninja.binaryview import BinaryViewType, BinaryView
-from binaryninja.filemetadata import FileMetadata
-from binaryninja.datarender import DataRenderer
-from binaryninja.function import InstructionTextToken, DisassemblyTextLine
-from binaryninja.enums import InstructionTextTokenType, FindFlag,\
- FunctionGraphType, NamedTypeReferenceClass, ReferenceType, SegmentFlag, SectionSemantics
-from binaryninja.types import (Type, BoolWithConfidence, EnumerationBuilder, NamedTypeReferenceBuilder
- EnumerationBuilder, NamedTypeReferenceBuilder)
-import subprocess
-import re
-
-
-# Alright so this one is here for Binja functions that output <in set([blah, blah, blah])>
-def fixSet(string):
- # Apply regular expression
- splitList = (re.split(r"((?<=<in set\(\[).*(?=\]\)>))", string))
- if len(splitList) > 1:
- return splitList[0] + ', '.join(sorted(splitList[1].split(', '))) + splitList[2]
- else:
- return string
-
-
-def fixStrRepr(string):
- # Python 2 and Python 3 represent Unicode character reprs differently
- return string.replace(b"\xe2\x80\xa6".decode("utf8"), "\\xe2\\x80\\xa6")
-
-def get_file_list(test_store_rel):
- test_store = os.path.join(os.path.dirname(__file__), test_store_rel)
- all_files = []
- for root, _, files in os.walk(test_store):
- for file in files:
- all_files.append(os.path.join(root, file))
- return all_files
-
-def remove_low_confidence(type_string):
- low_confidence_types = ["int32_t", "void"]
- for lct in low_confidence_types:
- type_string = type_string.replace(lct + " ", '') # done to resolve confidence ties
- return type_string
-
-class Builder(object):
- def __init__(self, test_store):
- self.test_store = test_store
- # binja.log.log_to_stdout(binja.LogLevel.DebugLog) # Uncomment for more info
-
- def methods(self):
- methodnames = []
- for methodname, _ in inspect.getmembers(self, predicate=inspect.ismethod):
- if methodname.startswith("test_"):
- methodnames.append(methodname)
- return methodnames
-
- def unpackage_file(self, filename):
- path = os.path.join(os.path.dirname(__file__), self.test_store, filename)
- if not os.path.exists(path):
- with zipfile.ZipFile(path + ".zip", "r") as zf:
- zf.extractall(path = os.path.dirname(__file__))
- assert os.path.exists(path)
- return os.path.relpath(path)
-
- def delete_package(self, filename):
- path = os.path.join(os.path.dirname(__file__), self.test_store, filename)
- os.unlink(path)
-
-class BinaryViewTestBuilder(Builder):
- """ The BinaryViewTestBuilder is for test that are verified against a binary.
- The tests are first run on your dev machine to base line then run again
- on the build machine to verify they are correct.
-
- - Function that are tests should start with 'test_'
- - Function doc string used as 'on error' message
- - Should return: list of strings
- """
- def __init__(self, filename, options=None):
- self.filename = os.path.join(os.path.dirname(__file__), filename)
- _bv = binja.load(self.filename, options=options)
- assert _bv is not None, f"{filename} is not an executable format"
- self.bv = _bv
-
- @classmethod
- def get_root_directory(cls):
- return os.path.dirname(__file__)
-
- def test_available_types(self):
- """Available types don't match"""
- bv = BinaryView(FileMetadata()).open(self.filename)
- assert bv is not None
- return ["Available Type: " + x.name for x in bv.available_view_types]
-
- def test_function_starts(self):
- """Function starts list doesn't match"""
- result = []
- for x in self.bv.functions:
- result.append("Function start: " + hex(x.start))
- return result
-
- def test_function_symbol_names(self):
- """Function.symbol.name list doesnt' match"""
- result = []
- for x in self.bv.functions:
- result.append("Symbol: " + x.symbol.name + ' ' + str(x.symbol.type) + ' ' + hex(x.symbol.address) + ' ' + str(x.symbol.namespace))
- return result
-
- def test_function_can_return(self):
- """Function.can_return list doesn't match"""
- result = []
- for x in self.bv.functions:
- result.append("function name: " + x.symbol.name + ' type: ' + str(x.symbol.type) + ' address: ' + hex(x.symbol.address) + ' can_return: ' + str(bool(x.can_return)))
- return result
-
- def test_function_basic_blocks(self):
- """Function basic_block list doesn't match (start, end, has_undetermined_outgoing_edges)"""
- bblist = []
- for func in self.bv.functions:
- for bb in func.basic_blocks:
- bblist.append(f"basic block {bb} start: {bb.start:#x} end: {bb.end:#x} undetermined outgoing edges: {bb.has_undetermined_outgoing_edges} incoming edges: {bb.incoming_edges} outgoing edges: {bb.outgoing_edges}")
- for anno in func.get_block_annotations(bb.start):
- bblist.append(f"basic block {bb} function annotation: {anno}")
- bblist.append(f"basic block {bb} test get self: {func.get_basic_block_at(bb.start)}")
- return bblist
-
- def test_function_low_il_basic_blocks(self):
- """Function low_il_basic_block list doesn't match"""
- ilbblist = []
- for func in self.bv.functions:
- for bb in func.low_level_il.basic_blocks:
- ilbblist.append("LLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing edges: ' + str(len(bb.outgoing_edges)))
- return ilbblist
-
- def test_function_med_il_basic_blocks(self):
- """Function med_il_basic_block list doesn't match"""
- ilbblist = []
- for func in self.bv.functions:
- for bb in func.mlil.basic_blocks:
- ilbblist.append("MLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing_edges: ' + str(len(bb.outgoing_edges)))
- return ilbblist
-
- def test_symbols(self):
- """Symbols list doesn't match"""
- return ["Symbol: " + str(i) for i in sorted(self.bv.symbols)]
-
- def test_symbol_namespaces(self):
- """Symbol namespaces don't match"""
- return self.bv.namespaces
-
- def test_internal_external_namespaces(self):
- """Symbol namespaces don't match"""
- return [BinaryView.internal_namespace(), BinaryView.external_namespace()]
-
- def test_strings(self):
- """Strings list doesn't match"""
- return ["String: " + str(x.value) + ' type: ' + str(x.type) + ' at: ' + hex(x.start) for x in self.bv.strings]
-
- def test_low_il_instructions(self):
- """LLIL instructions produced different output"""
- retinfo = []
- for func in self.bv.functions:
- for bb in func.low_level_il.basic_blocks:
- for ins in bb:
- retinfo.append("Function: {:x} Instruction: {:x} ADDR->LiftedILS: {}".format(func.start, ins.address, str(sorted(list(map(str, func.get_lifted_ils_at(ins.address)))))))
- retinfo.append("Function: {:x} Instruction: {:x} ADDR->LLILS: {}".format(func.start, ins.address, str(sorted(list(map(str, func.get_llils_at(ins.address)))))))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL->MLIL: {}".format(func.start, ins.address, str(ins.mlil)))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL->MLILS: {}".format(func.start, ins.address, str(sorted(list(map(str, ins.mlils))))))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL->HLIL: {}".format(func.start, ins.address, str(ins.hlil)))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL->HLILS: {}".format(func.start, ins.address, str(sorted(list(map(str, ins.hlils))))))
- retinfo.append("Function: {:x} Instruction: {:x} Mapped MLIL: {}".format(func.start, ins.address, str(ins.mapped_medium_level_il)))
- retinfo.append("Function: {:x} Instruction: {:x} Value: {}".format(func.start, ins.address, str(ins.value)))
- retinfo.append("Function: {:x} Instruction: {:x} Possible Values: {}".format(func.start, ins.address, str(ins.possible_values)))
-
- prefixList = []
- for i in ins.prefix_operands:
- if isinstance(i, dict):
- contents = []
- for j in sorted(i.keys()):
- contents.append((j, i[j]))
- prefixList.append(str(contents))
- else:
- prefixList.append(i)
- retinfo.append("Function: {:x} Instruction: {:x} Prefix operands: {}".format(func.start, ins.address, fixStrRepr(str(prefixList))))
-
- postfixList = []
- for i in ins.postfix_operands:
- if isinstance(i, dict):
- contents = []
- for j in sorted(i.keys()):
- contents.append((j, i[j]))
- postfixList.append(str(contents))
- else:
- postfixList.append(i)
- retinfo.append("Function: {:x} Instruction: {:x} Postfix operands: {}".format(func.start, ins.address, fixStrRepr(str(postfixList))))
-
- retinfo.append("Function: {:x} Instruction: {:x} SSA form: {}".format(func.start, ins.address, str(ins.ssa_form)))
- retinfo.append("Function: {:x} Instruction: {:x} Non-SSA form: {}".format(func.start, ins.address, str(ins.non_ssa_form)))
- return retinfo
-
- def test_low_il_ssa(self):
- """LLIL ssa produced different output"""
- retinfo = []
- for func in self.bv.functions:
- func = func.low_level_il
- arch = self.bv.arch
- assert arch is not None, "Architecture is None"
- source_function = func.source_function
- assert source_function is not None, "source_function is None"
- for reg_name in sorted(arch.regs):
- reg = binja.SSARegister(reg_name, 1)
- retinfo.append("Function: {:x} Reg {} SSA definition: {}".format(source_function.start, reg_name, str(getattr(func.get_ssa_reg_definition(reg), 'instr_index', None))))
- retinfo.append("Function: {:x} Reg {} SSA uses: {}".format(source_function.start, reg_name, str(list(map(lambda instr: instr.instr_index, func.get_ssa_reg_uses(reg))))))
- retinfo.append("Function: {:x} Reg {} SSA value: {}".format(source_function.start, reg_name, str(func.get_ssa_reg_value(reg))))
- for flag_name in sorted(arch.flags):
- flag = binja.SSAFlag(flag_name, 1)
- retinfo.append("Function: {:x} Flag {} SSA uses: {}".format(source_function.start, flag_name, str(list(map(lambda instr: instr.instr_index, func.get_ssa_flag_uses(flag))))))
- retinfo.append("Function: {:x} Flag {} SSA value: {}".format(source_function.start, flag_name, str(func.get_ssa_flag_value(flag))))
- for bb in func.basic_blocks:
- for ins in bb:
- tempind = func.get_non_ssa_instruction_index(ins.instr_index)
- retinfo.append("Function: {:x} Instruction: {:x} Non-SSA instruction index: {}".format(source_function.start, ins.address, str(tempind)))
- retinfo.append("Function: {:x} Instruction: {:x} SSA instruction index: {}".format(source_function.start, ins.address, str(func.get_ssa_instruction_index(tempind))))
- retinfo.append("Function: {:x} Instruction: {:x} MLIL instruction index: {}".format(source_function.start, ins.address, str(func.get_medium_level_il_instruction_index(ins.instr_index))))
- retinfo.append("Function: {:x} Instruction: {:x} Mapped MLIL instruction index: {}".format(source_function.start, ins.address, str(func.get_mapped_medium_level_il_instruction_index(ins.instr_index))))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL_SSA->MLIL: {}".format(source_function.start, ins.address, str(ins.mlil)))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL_SSA->MLILS: {}".format(source_function.start, ins.address, str(sorted(list(map(str, ins.mlils))))))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL_SSA->HLIL: {}".format(source_function.start, ins.address, str(ins.hlil)))
- retinfo.append("Function: {:x} Instruction: {:x} LLIL_SSA->HLILS: {}".format(source_function.start, ins.address, str(sorted(list(map(str, ins.hlils))))))
- return retinfo
-
- def test_med_il_instructions(self):
- """MLIL instructions produced different output"""
- retinfo = []
- for func in self.bv.functions:
- for bb in func.mlil.basic_blocks:
- for ins in bb:
- retinfo.append("Function: {:x} Instruction: {:x} Expression type: {}".format(func.start, ins.address, str(ins.expr_type)))
- retinfo.append("Function: {:x} Instruction: {:x} MLIL->LLIL: {}".format(func.start, ins.address, str(ins.llil)))
- retinfo.append("Function: {:x} Instruction: {:x} MLIL->LLILS: {}".format(func.start, ins.address, str(sorted(list(map(str, ins.llils))))))
- retinfo.append("Function: {:x} Instruction: {:x} MLIL->HLIL: {}".format(func.start, ins.address, str(ins.hlil)))
- retinfo.append("Function: {:x} Instruction: {:x} MLIL->HLILS: {}".format(func.start, ins.address, str(sorted(list(map(str, ins.hlils))))))
- retinfo.append("Function: {:x} Instruction: {:x} Value: {}".format(func.start, ins.address, str(ins.value)))
- retinfo.append("Function: {:x} Instruction: {:x} Possible values: {}".format(func.start, ins.address, str(ins.possible_values)))
- retinfo.append("Function: {:x} Instruction: {:x} Branch dependence: {}".format(func.start, ins.address, str(sorted(ins.branch_dependence.items()))))
-
- prefixList = []
- for i in ins.prefix_operands:
- if isinstance(i, float) and 'e' in str(i):
- prefixList.append(str(round(i, 21)))
- elif isinstance(i, float):
- prefixList.append(str(round(i, 11)))
- elif isinstance(i, dict):
- contents = []
- for j in sorted(i.keys()):
- contents.append((j, i[j]))
- prefixList.append(str(contents))
- else:
- prefixList.append(str(i))
- retinfo.append("Function: {:x} Instruction: {:x} Prefix operands: {}".format(func.start, ins.address, fixStrRepr(str(sorted(prefixList)))))
- postfixList = []
- for i in ins.postfix_operands:
- if isinstance(i, float) and 'e' in str(i):
- postfixList.append(str(round(i, 21)))
- elif isinstance(i, float):
- postfixList.append(str(round(i, 11)))
- elif isinstance(i, dict):
- contents = []
- for j in sorted(i.keys()):
- contents.append((j, i[j]))
- postfixList.append(str(contents))
- else:
- postfixList.append(str(i))
-
- retinfo.append("Function: {:x} Instruction: {:x} Postfix operands: {}".format(func.start, ins.address, fixStrRepr(str(sorted(postfixList)))))
- retinfo.append("Function: {:x} Instruction: {:x} SSA form: {}".format(func.start, ins.address, str(ins.ssa_form)))
- retinfo.append("Function: {:x} Instruction: {:x} Non-SSA form: {}".format(func.start, ins.address, str(ins.non_ssa_form)))
- return retinfo
-
- def test_med_il_vars(self):
- """Function med_il_vars doesn't match"""
- varlist = []
- for func in self.bv.functions:
- func = func.mlil
- for bb in func.basic_blocks:
- for instruction in bb:
- instruction = instruction.ssa_form
- for var in (instruction.vars_read + instruction.vars_written):
- if hasattr(var, "var"):
- varlist.append(f"Function: {func.source_function.start:x} Instruction {instruction.address:x} SSA var definition: {getattr(func.get_ssa_var_definition(var), 'instr_index', None)}")
- varlist.append(f"Function: {func.source_function.start:x} Instruction {instruction.address:x} SSA var uses: {list(map(lambda instr: instr.instr_index, func.get_ssa_var_uses(var)))}")
- varlist.append(f"Function: {func.source_function.start:x} Instruction {instruction.address:x} SSA var value: {func.get_ssa_var_value(var)}")
- varlist.append(f"Function: {func.source_function.start:x} Instruction {instruction.address:x} SSA var possible values: {fixSet(str(instruction.get_ssa_var_possible_values(var)))}")
- varlist.append(f"Function: {func.source_function.start:x} Instruction {instruction.address:x} SSA var version: {instruction.get_ssa_var_version(var.var)}")
- return varlist
-
- def test_function_stack(self):
- """Function stack produced different output"""
- funcinfo = []
- for func in self.bv.functions:
- for i, var in enumerate(func.stack_layout):
- funcinfo.append(f"Function: {func.start:x} Stack position {i}: {var}")
-
- funcinfo.append(f"Function: {func.start:x} Stack adjustment: {func.stack_adjustment.value}")
- funcinfo.append(f"Function: {func.start:x} Register stack adjustment: {[v.value for v in func.reg_stack_adjustments.values()]}")
-
- func.stack_adjustment = func.stack_adjustment
- func.reg_stack_adjustments = func.reg_stack_adjustments
- func.create_user_stack_var(0, binja.Type.int(4), "testuservar")
- # The following test has been commented as it leads to non-deterministic test results
- # This is likely due to an extra update coming along afterward and removing sometimes
- # This test would need to be conducted in an analysis pass to be consistent and accurate
- # func.create_auto_stack_var(4, binja.Type.int(4), "testautovar")
-
-
-
- funcinfo.append(f"Function: {func.start:x} Stack content sample: {func.get_stack_contents_at(func.start + 0x10, 0, 0x10)}")
- funcinfo.append(f"Function: {func.start:x} Stack content range sample: {func.get_stack_contents_after(func.start + 0x10, 0, 0x10)}")
- funcinfo.append(f"Function: {func.start:x} Sample stack var: {func.get_stack_var_at_frame_offset(0, 0)}")
- func.delete_user_stack_var(0)
- func.delete_auto_stack_var(0)
- return funcinfo
-
- def test_function_llil(self):
- """Function LLIL produced different output"""
- retinfo = []
- for func in self.bv.functions:
- for llil_bb in func.llil_basic_blocks:
- retinfo.append(f"Function: {func.start:x} LLIL basic block: {llil_bb}")
- for llil_ins in func.llil.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {llil_ins.address:x} LLIL instruction: {llil_ins}")
- for mlil_bb in func.mlil_basic_blocks:
- retinfo.append(f"Function: {func.start:x} MLIL basic block: {mlil_bb}")
- for mlil_ins in func.mlil.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {mlil_ins.address:x} MLIL instruction: {mlil_ins}")
- for hlil_ins in func.hlil.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {hlil_ins.address:x} HLIL instruction: {hlil_ins}")
- for ins in func.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {ins[1]:#x}: {''.join([str(i) for i in ins[0]])}")
- return retinfo
-
- def test_function_hlil(self):
- """Function HLIL produced different output"""
- retinfo = []
- for func in self.bv.functions:
- if func.hlil is None or func.hlil.root is None:
- continue
- for line in func.hlil.root.lines:
- retinfo.append(f"Function: {func.start:x} HLIL line: {line}")
- for hlilins in func.hlil.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->LLIL instruction: {str(hlilins.llil)}")
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->MLIL instruction: {str(hlilins.mlil)}")
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->MLILS instruction: {str(sorted(list(map(str, hlilins.mlils))))}")
- return retinfo
-
- def test_function_type(self):
- """Function types don't match"""
- retinfo = []
- for func in self.bv.functions:
- if func.hlil is None or func.hlil.root is None:
- continue
- retinfo.append(f"Function: {func.start:x} Type: {func.function_type}")
- return retinfo
-
- def test_functions_attributes(self):
- """Function attributes don't match"""
- funcinfo = []
- for func in self.bv.functions:
- func.comment = "testcomment " + func.name
- func.name = func.name
- func.can_return = func.can_return
- func.function_type = func.function_type
- func.return_type = func.return_type
- func.return_regs = func.return_regs
- func.calling_convention = func.calling_convention
- func.parameter_vars = func.parameter_vars
- func.has_variable_arguments = func.has_variable_arguments
- func.analysis_skipped = func.analysis_skipped
- func.clobbered_regs = func.clobbered_regs
- func.set_user_instr_highlight(func.start, binja.highlight.HighlightColor(red=0xff, blue=0xff, green=0))
- func.set_auto_instr_highlight(func.start, binja.highlight.HighlightColor(red=0xff, blue=0xfe, green=0))
-
- for var in func.vars:
- funcinfo.append("Function {} var: ".format(func.name) + str(var))
-
- for (arch, addr, tag) in func.address_tags:
- funcinfo.append("Function {} tag at ({}, {:x}): ".format(func.name, arch.name, addr) + str(tag))
- for tag in func.function_tags:
- funcinfo.append("Function {} tag: ".format(func.name) + str(tag))
-
- for branch in func.indirect_branches:
- funcinfo.append("Function {} indirect branch: ".format(func.name) + str(branch))
- funcinfo.append("Function {} session data: ".format(func.name) + str(func.session_data))
- funcinfo.append("Function {} analysis perf length: ".format(func.name) + str(len(func.analysis_performance_info)))
- for cr in func.clobbered_regs:
- funcinfo.append("Function {} clobbered reg: ".format(func.name) + str(cr))
- funcinfo.append("Function {} explicitly defined type: ".format(func.name) + str(func.explicitly_defined_type))
- funcinfo.append("Function {} needs update: ".format(func.name) + str(func.needs_update))
- funcinfo.append("Function {} global pointer value: ".format(func.name) + str(func.global_pointer_value))
- funcinfo.append("Function {} comment: ".format(func.name) + str(func.comment))
- funcinfo.append("Function {} too large: ".format(func.name) + str(func.too_large))
- funcinfo.append("Function {} analysis skipped: ".format(func.name) + str(func.analysis_skipped))
- funcinfo.append("Function {} first ins LLIL: ".format(func.name) + str(func.get_low_level_il_at(func.start)))
- funcinfo.append("Function {} LLIL exit test: ".format(func.name) + str(func.get_low_level_il_exits_at(func.start+0x100)))
- funcinfo.append("Function {} regs read test: ".format(func.name) + str(func.get_regs_read_by(func.start)))
- funcinfo.append("Function {} regs written test: ".format(func.name) + str(func.get_regs_written_by(func.start)))
- funcinfo.append("Function {} stack var test: ".format(func.name) + str(func.get_stack_vars_referenced_by(func.start)))
- funcinfo.append("Function {} constant reference test: ".format(func.name) + str(func.get_constants_referenced_by(func.start)))
- funcinfo.append("Function {} first ins lifted IL: ".format(func.name) + str(func.get_lifted_il_at(func.start)))
- funcinfo.append("Function {} flags read by lifted IL ins: ".format(func.name) + str(func.get_flags_read_by_lifted_il_instruction(0)))
- funcinfo.append("Function {} flags written by lifted IL ins: ".format(func.name) + str(func.get_flags_written_by_lifted_il_instruction(0)))
- funcinfo.append("Function {} create graph: ".format(func.name) + str(func.create_graph()))
- funcinfo.append("Function {} indirect branches test: ".format(func.name) + str(func.get_indirect_branches_at(func.start+0x10)))
- funcinfo.append("Function {} test instr highlight: ".format(func.name) + str(func.get_instr_highlight(func.start)))
- for token in func.get_type_tokens():
- token = str(token)
- token = remove_low_confidence(token)
- funcinfo.append("Function {} type token: ".format(func.name) + str(token))
- return funcinfo
-
- def test_BinaryView(self):
- """BinaryView produced different results"""
- retinfo = []
-
- for type in sorted([str(i) for i in self.bv.types.items()]):
- retinfo.append(f"BV Type: {type}")
- for segment in sorted([str(i) for i in self.bv.segments]):
- retinfo.append(f"BV segment: {segment}")
- for section in sorted(self.bv.sections):
- retinfo.append(f"BV section: {section}")
- for allrange in self.bv.allocated_ranges:
- retinfo.append(f"BV allocated range: {allrange}")
- retinfo.append(f"Session Data: {self.bv.session_data}")
- for (addr, tag) in self.bv.data_tags:
- retinfo.append(f"BV tag: {addr:x} {repr(tag)}")
- for tag_type in self.bv.tag_types:
- retinfo.append(f"BV tag type: {repr(tag_type)}")
- vars = self.bv.data_vars
- for addr in sorted(vars.keys()):
- retinfo.append(f"BV data var: {vars[addr]}")
- retinfo.append(f"BV Entry function: {repr(self.bv.entry_function)}")
- for i in self.bv:
- retinfo.append(f"BV function: {repr(i)}")
- retinfo.append(f"BV entry point: {self.bv.entry_point:#x}")
- retinfo.append(f"BV start: {self.bv.start:#x}")
- retinfo.append(f"BV length: {len(self.bv):#x}")
-
- return retinfo
-
- def test_dominators(self):
- """Dominators don't match oracle"""
- retinfo = []
- for func in self.bv.functions:
- for bb in func:
- for dom in sorted(bb.dominators, key=lambda x: x.start):
- retinfo.append("Dominator: %x of %x" % (dom.start, bb.start))
- for pdom in sorted(bb.post_dominators, key=lambda x: x.start):
- retinfo.append("PostDominator: %x of %x" % (pdom.start, bb.start))
- return retinfo
-
- def test_liveness(self):
- """Liveness results don't match oracle"""
- retinfo1 = []
- retinfo2 = []
- for hlil in self.bv.hlil_functions():
- vars = hlil.vars
- hlil_ssa = hlil.ssa_form
- ssa_vars = hlil_ssa.ssa_vars
- name = hlil.source_function.name
- for instr_index in range(0, len(hlil)):
- for var in vars:
- retinfo1.append(f"{name}-hlil@{instr_index}: {hlil.is_var_live_at(var, binja.highlevelil.InstructionIndex(instr_index))}")
- for instr_index in range(0, len(hlil_ssa)):
- for var in ssa_vars:
- retinfo2.append(f"{name}-hlil-ssa@{instr_index}: {hlil_ssa.is_ssa_var_live_at(var, binja.highlevelil.InstructionIndex(instr_index))}")
-
- return retinfo1 + retinfo2
-
-
-class TestBuilder(Builder):
- """ The TestBuilder is for tests that need to be checked against a
- stored oracle data that isn't from a binary. These test are
- generated on your local machine then run again on the build
- machine to verify correctness.
-
- - Function that are tests should start with 'test_'
- - Function doc string used as 'on error' message
- - Should return: list of strings
- """
-
- def test_BinaryViewType_list(self):
- """BinaryViewType list doesn't match"""
- return ["BinaryViewType: " + x.name for x in binja.BinaryViewType]
-
- def test_deprecated_BinaryViewType(self):
- """deprecated BinaryViewType list doesn't match"""
- file_name = self.unpackage_file("fat_macho_9arch.bndb")
- if not os.path.exists(file_name):
- return [""]
-
- view_types = []
- with binja.filemetadata.FileMetadata().open_existing_database(file_name, None) as bv:
- for view_type in bv.available_view_types:
- if view_type.is_deprecated:
- view_types.append('BinaryViewType: %s (deprecated)' % view_type.name)
- else:
- view_types.append('BinaryViewType: %s' % view_type.name)
-
- self.delete_package("fat_macho_9arch.bndb")
- return view_types
-
- def test_Architecture_list(self):
- """Architecture list doesn't match"""
- return ["Arch name: " + arch.name for arch in binja.Architecture]
-
- def test_Assemble(self):
- """unexpected assemble result"""
- result = []
-
- # success cases
- result.append(f"x86 assembly: {binja.Architecture['x86'].assemble('xor eax, eax')}")
- result.append(f"x86_64 assembly: {binja.Architecture['x86_64'].assemble('xor rax, rax')}")
- result.append(f"mips32 assembly: {binja.Architecture['mips32'].assemble('move $ra, $zero')}")
- result.append(f"armv7 assembly: {binja.Architecture['armv7'].assemble('str r2, [sp, #-0x4]!')}")
- result.append(f"aarch64 assembly: {binja.Architecture['aarch64'].assemble('mov x0, x0')}")
- result.append(f"thumb2 assembly: {binja.Architecture['thumb2'].assemble('ldr r4, [r4]')}")
- result.append(f"thumb2eb assembly: {binja.Architecture['thumb2eb'].assemble('ldr r4, [r4]')}")
-
- # fail cases
- try:
- strResult = binja.Architecture["x86"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86'")
- try:
- strResult = binja.Architecture["x86_64"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86_64'")
- try:
- strResult = binja.Architecture["mips32"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mips32'")
- try:
- strResult = binja.Architecture["mipsel32"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mipsel32'")
- try:
- strResult = binja.Architecture["armv7"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'armv7'")
- try:
- strResult = binja.Architecture["aarch64"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'aarch64'")
- try:
- strResult = binja.Architecture["thumb2"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2'")
- try:
- strResult = binja.Architecture["thumb2eb"].assemble("thisisnotaninstruction")
- except ValueError:
- result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2eb'")
- return result
-
- def test_Architecture(self):
- """Architectures produced different results"""
- retinfo = []
-
- flag_reg0 = binja.FlagName("reg0")
- reg_reg0 = binja.RegisterName("reg0")
- reg_fwidthreg0 = binja.RegisterName("fwidth_reg0")
- stack_reg0 = binja.RegisterStackName("reg0")
- semgrp_flggrp0 = binja.SemanticGroupName("flggrp0")
- semcls_cls0 = binja.SemanticClassName("cls0")
-
- class ArchTest(binja.Architecture):
- name = "ArchTest"
- address_size = -1
- default_int_size = -1
- instr_alignment = -1
- opcode_display_length = 1
- max_instr_length = -1
- regs = {
- reg_reg0: binja.RegisterInfo(reg_reg0, 2)
- }
- stack_pointer = "reg0"
- flags = [flag_reg0, binja.FlagName("reg0_flg")]
- flag_write_types = [binja.FlagWriteTypeName("*")]
- flag_roles = {
- flag_reg0: binja.FlagRole.SpecialFlagRole,
- "reg0_flg": "SpecialFlagRole"
- }
- flags_required_for_flag_condition = {
- binja.LowLevelILFlagCondition.LLFC_UGE: [flag_reg0]
- }
- flags_written_by_flag_write_type = {
- "*": ["reg0"]
- }
- full_width_regs = {
- reg_fwidthreg0: binja.RegisterInfo(reg_fwidthreg0, 3)
- }
- reg_stacks = {
- stack_reg0: binja.RegisterStackInfo([stack_reg0], [stack_reg0], stack_reg0, 0)
- }
- semantic_flag_groups = {
- semgrp_flggrp0: 0
- }
- flags_required_by_semantic_flag_group = {
- semgrp_flggrp0: [0]
- }
- flags_required_for_semantic_flag_group = {
- semgrp_flggrp0: [flag_reg0]
- }
- semantic_flag_classes = {
- semcls_cls0: 0
- }
- # flag_conditions_for_semantic_flag_group = {
- # semgrp_flggrp0: semcls_cls0
- # }
-
- def get_instruction_text(self, data, addr):
- return [binja.InstructionTextToken(binja.InstructionTextTokenType.TextToken, "not hooked")], 1
-
- class EmptyArch(binja.Architecture):
- pass
-
- ArchTest.register()
-
- try:
- EmptyArch.register()
- assert False # Registering an empty arch should fail (this code should not be reached)
- except:
- pass
-
- at = binja.Architecture['ArchTest']
-
- assert len(at.type_libraries) == 0
-
- assert at.can_assemble == False
- assert binja.Architecture['x86'].can_assemble == True
-
- for arch in binja.Architecture:
- retinfo.append(f"Arch calling convention: {arch.calling_conventions}")
- retinfo.append(f"Arch regs: {arch.regs}")
- retinfo.append(f"Arch full width regs: {arch.full_width_regs}")
- retinfo.append(f"Arch standalone platform: {arch.standalone_platform}")
- retinfo.append(f"Arch repr: {repr(arch)}")
- retinfo.append(f"Arch endianness: {arch.endianness}")
- retinfo.append(f"Arch address size: {arch.address_size}")
- retinfo.append(f"Arch default int size: {arch.default_int_size}")
- retinfo.append(f"Arch instr alignment: {arch.instr_alignment}")
- retinfo.append(f"Arch max instr length: {arch.max_instr_length}")
- retinfo.append(f"Arch opcode display length: {arch.opcode_display_length}")
- retinfo.append(f"Arch stack pointer: {arch.stack_pointer}")
- retinfo.append(f"Arch link reg: {arch.link_reg}")
- retinfo.append(f"Arch & address: {arch.get_associated_arch_by_address(0)}")
-
- assert binja.Architecture['x86'] == binja.Architecture['x86']
- assert binja.Architecture['x86'] != binja.Architecture['x86_64']
- return retinfo
-
- def test_ArchitectureHook(self):
- class ArchTestHook(binja.ArchitectureHook):
- def get_instruction_text(self, data, addr):
- return [binja.InstructionTextToken(binja.InstructionTextTokenType.TextToken, "hooked")], 1
-
- class ArchTestHook2(binja.ArchitectureHook):
- pass
-
- at = binja.Architecture["ArchTest"]
- instr_text = at.get_instruction_text(b'\x00', 1)
-
- ArchTestHook(at).register()
- instr_text_hooked = at.get_instruction_text(b'\x00', 1)
-
- # Register empty hook
- ArchTestHook2(at).register()
-
- assert instr_text != instr_text_hooked
- assert instr_text == instr_text
-
- ath2 = ArchTestHook2(at)
- assert ath2.base_arch == at
- ath2.base_arch = binja.Architecture["x86"]
- assert ath2.base_arch == binja.Architecture["x86"]
- ath2.base_arch = at
- assert ath2.base_arch == at
- return [f"{at}"]
-
-
- def test_Function(self):
- """Function produced different result"""
- inttype = binja.Type.int(4)
- testfunction = binja.Type.function(inttype, [inttype, inttype, inttype])
- return ["Test_function params: " + str(testfunction.parameters), "Test_function pointer: " + str(testfunction.pointer(binja.Architecture["x86"], testfunction))]
-
- def test_Simplifier(self):
- """Template Simplification"""
- result = [binja.demangle.simplify_name_to_string(s) for s in [
- # Minimal exhaustive examples of simplifier (these are replicated in testcommon)
- "std::basic_string<T, std::char_traits<T>, std::allocator<T> >",
- "std::vector<T, std::allocator<T> >",
- "std::vector<T, std::allocator<T>, std::lessthan<T> >",
- "std::deque<T, std::allocator<T> >",
- "std::forward_list<T, std::allocator<T> >",
- "std::list<T, std::allocator<T> >",
- "std::stack<T, std::deque<T> >",
- "std::queue<T, std::deque<T> >",
- "std::set<T, std::less<T>, std::allocator<T> >",
- "std::multiset<T, std::less<T>, std::allocator<T> >",
- "std::map<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2> > >",
- "std::multimap<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2> > >",
- "std::unordered_set<T, std::hash<T>, std::equal_to<T>, std::allocator<T> >",
- "std::unordered_multiset<T, std::hash<T>, std::equal_to<T>, std::allocator<T> >",
- "std::unordered_map<T1, T2, std::hash<T1>, std::equal_to<T1>, std::allocator<std::pair<const T1, T2> > >",
- "std::unordered_multimap<T1, T2, std::hash<T1>, std::equal_to<T1>, std::allocator<std::pair<const T1, T2> > >",
-
- "std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >",
- "std::basic_istringstream<char, std::char_traits<char>, std::allocator<char> >",
- "std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >",
- "std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >",
- "std::basic_stringbuf<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >",
- "std::basic_istringstream<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >",
- "std::basic_ostringstream<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >",
- "std::basic_stringstream<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >",
- "std::basic_stringbuf<T, std::char_traits<T>, std::allocator<T> >",
- "std::basic_istringstream<T, std::char_traits<T>, std::allocator<T> >",
- "std::basic_ostringstream<T, std::char_traits<T>, std::allocator<T> >",
- "std::basic_stringstream<T, std::char_traits<T>, std::allocator<T> >",
-
- "std::basic_ios<char, std::char_traits<char> >",
- "std::basic_streambuf<char, std::char_traits<char> >",
- "std::basic_istream<char, std::char_traits<char> >",
- "std::basic_ostream<char, std::char_traits<char> >",
- "std::basic_iostream<char, std::char_traits<char> >",
- "std::basic_filebuf<char, std::char_traits<char> >",
- "std::basic_ifstream<char, std::char_traits<char> >",
- "std::basic_ofstream<char, std::char_traits<char> >",
- "std::basic_fstream<char, std::char_traits<char> >",
- "std::basic_ios<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_streambuf<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_istream<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_ostream<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_iostream<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_filebuf<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_ifstream<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_ofstream<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_fstream<wchar_t, std::char_traits<wchar_t> >",
- "std::basic_ios<T, std::char_traits<T> >",
- "std::basic_streambuf<T, std::char_traits<T> >",
- "std::basic_istream<T, std::char_traits<T> >",
- "std::basic_ostream<T, std::char_traits<T> >",
- "std::basic_iostream<T, std::char_traits<T> >",
- "std::basic_filebuf<T, std::char_traits<T> >",
- "std::basic_ifstream<T, std::char_traits<T> >",
- "std::basic_ofstream<T, std::char_traits<T> >",
- "std::basic_fstream<T, std::char_traits<T> >",
-
- # The following simplifiers should probably be done as typedefs some where as they can appear both
- # as the simplified and unsimplified name in the type libraries and in mangled names
- # "std::fpos<__mbstate_t>",
- # "std::_Ios_Iostate",
- # "std::_Ios_Seekdir",
- # "std::_Ios_Openmode",
- # "std::_Ios_Fmtflags",
-
- # The following 5 entries are the simplified versions of the above so we don't have to re-generate
- # unit test results.
- "std::streampos",
- "std::ios_base::iostate",
- "std::ios_base::seekdir",
- "std::ios_base::openmode",
- "std::ios_base::fmtflags",
-
- "std::foo<T, std::char_traits<T> >",
- "std::bar<T, std::char_traits<T> >::bar",
- "std::foo<T, std::char_traits<T> >::~foo",
- "std::foo<T, std::char_traits<T> >::bar",
-
- "std::foo<bleh::T, std::char_traits<bleh::T> >",
- "std::bar<bleh::T, std::char_traits<bleh::T> >::bar",
- "std::foo<bleh::T, std::char_traits<bleh::T> >::~foo",
- "std::foo<bleh::T, std::char_traits<bleh::T> >::bar",
-
- "std::foo<foo::bleh::T, std::char_traits<foo::bleh::T> >",
- "std::bar<foo::bleh::T, std::char_traits<foo::bleh::T> >::bar",
- "std::foo<foo::bleh::T, std::char_traits<foo::bleh::T> >::~foo",
- "std::foo<foo::bleh::T, std::char_traits<foo::bleh::T> >::bar",
-
- # More complex examples:
- "AddRequiredUIPluginDependency(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)",
- "std::vector<std::vector<BinaryNinja::InstructionTextToken, std::allocator<BinaryNinja::InstructionTextToken> >, std::allocator<std::vector<BinaryNinja::InstructionTextToken, std::allocator<BinaryNinja::InstructionTextToken> > > >::_M_check_len(uint64_t, char const*) const",
- "std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::array<uint32_t, 5ul> >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::array<uint32_t, 5ul> > > >::_M_default_append(uint64_t)",
- "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string",
- "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string",
- ]]
-
- # Test all the APIs
- qName = binja.types.QualifiedName(["std", "__cxx11", "basic_string<T, std::char_traits<T>, std::allocator<T> >"])
- result.append(binja.demangle.simplify_name_to_string(qName))
- result.append(str(binja.demangle.simplify_name_to_qualified_name(qName)))
- result.append(str(binja.demangle.simplify_name_to_qualified_name(str(qName))))
- result.append(str(binja.demangle.simplify_name_to_qualified_name(str(qName), False).name))
- result.append("::".join(binja.demangle_gnu3(binja.Architecture['x86_64'], "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm", False)[1]))
- result.append("::".join(binja.demangle_gnu3(binja.Architecture['x86_64'], "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm", True)[1]))
-
- return result
-
- def test_Struct(self):
- """Struct produced different result"""
- retinfo = []
- inttype = binja.Type.int(4)
- struct = binja.TypeBuilder.structure()
- struct.insert(0, inttype)
- struct.append(inttype)
- struct.replace(0, inttype)
- struct.remove(1)
- for i in struct.members:
- retinfo.append("Struct member: " + str(i))
- retinfo.append("Struct width: " + str(struct.width))
- struct.width = 16
- retinfo.append("Struct width after adjustment: " + str(struct.width))
- retinfo.append("Struct alignment: " + str(struct.alignment))
- struct.alignment = 8
- retinfo.append("Struct alignment after adjustment: " + str(struct.alignment))
- retinfo.append("Struct packed: " + str(struct.packed))
- struct.packed = True
- retinfo.append("Struct packed after adjustment: " + str(struct.packed))
- retinfo.append("Struct type: " + str(struct.type))
- assert struct == struct, "Structs are not equal"
- assert not (struct != struct), "Structs are not not not equal"
- retinfo.append("False") # TODO Remove when regenerating this
- return retinfo
-
- def test_Enumeration(self):
- """Enumeration produced different result"""
- retinfo = []
- enum = binja.TypeBuilder.enumeration()
- enum.append("a", 1)
- enum.append("b", 2)
- enum.replace(0, "a", 2)
- enum.remove(0)
- retinfo.append(str(enum))
- retinfo.append(str((enum == enum) and not (enum != enum)))
- return retinfo
-
- def test_Types(self):
- """Types produced different result"""
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
-
- preprocessed = binja.preprocess_source("""
- #ifdef nonexistant
- int foo = 1;
- long long foo1 = 1;
- #else
- int bar = 2;
- long long bar1 = 2;
- #endif
- """)
- source = '\n'.join([i for i in preprocessed[0].split('\n') if not '#line' in i and len(i) > 0])
- typelist = bv.platform.parse_types_from_source(source)
- inttype = binja.Type.int(4)
-
- namedtype = binja.NamedTypeReferenceBuilder.create()
- tokens = inttype.get_tokens() + inttype.get_tokens_before_name() + inttype.get_tokens_after_name()
- retinfo = []
- for i in range(len(typelist.variables)):
- for j in typelist.variables.popitem():
- retinfo.append("Type: " + str(j))
- retinfo.append("Named Type: " + str(namedtype))
-
- retinfo.append("Type equality: " + str((inttype == inttype) and not (inttype != inttype)))
- return retinfo
- finally:
- self.delete_package("helloworld")
-
- def test_TypeBuilders_and_Types(self):
- """Test TypeBuilders"""
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- with binja.StructureBuilder.builder(bv, 'Foo') as s:
- s.packed = True
- s.append(Type.int(2))
- s.append(Type.int(4))
- s.append(Type.void())
- s.append(Type.bool())
- s.append(Type.char())
- s.append(Type.char("char_alt_name"))
- s.append(Type.float(2, "half"))
- s.append(Type.float(4) )
- s.append(Type.float(8))
- s.append(Type.float(16))
- s.append(Type.wide_char(4, "wchar32_t"))
- s.append(Type.structure_type(binja.StructureBuilder.create([Type.int(1)])))
- s.append(Type.named_type(NamedTypeReferenceBuilder.create(NamedTypeReferenceClass.UnknownNamedTypeClass, "id", "name")))
- s.append(Type.named_type_from_type_and_id("id2", ["qualified", "name"]))
- s.append(Type.generate_named_type_reference("guid", [b"byte", b"name"]))
- s.append(Type.enumeration_type(bv.arch, EnumerationBuilder.create([("Member1", 1)])))
- try:
- Type.pointer(None, None) # test the failure case
- except ValueError:
- pass
- s.append(Type.pointer_of_width(8, Type.int(4), BoolWithConfidence(True, 255), BoolWithConfidence(False, 255), ReferenceType.RValueReferenceType))
- s.append(Type.array(Type.int(4), 4))
- s.append(Type.structure([(Type.int(4), "field1")]))
- s.append(Type.enumeration(bv.arch, [binja.types.EnumerationMember("Mem-1", 1), binja.types.EnumerationMember("Mem-2")]))
- s.append(Type.enumeration(bv.arch, [binja.types.EnumerationMember("Mem2-1", 1), binja.types.EnumerationMember("Mem2-2")], 2))
- s.append(Type.enumeration(bv.arch, [binja.types.EnumerationMember("Mem3-1", 1), binja.types.EnumerationMember("Mem3-2")], 2, True))
- s.append(Type.enumeration(bv.arch, None))
- tid = Type.generate_auto_demangled_type_id("auto_demangled_tid")
- tid_source = Type.get_auto_demangled_type_id_source()
- s.append(Type.named_type_reference(NamedTypeReferenceClass.UnknownNamedTypeClass, "Someothername", tid, 4, 4, True, True))
- try:
- Type.int(4).name
- assert False, "trying to access name of integer succeeded when it shouldn't have"
- except NotImplementedError:
- pass
-
- members = s.members
- const = s.const
- volatile = s.volatile
- s = bv.types['Foo']
- assert members == s.members
- assert const == s.const
- assert volatile == s.volatile
- return [str(s.members)]
- finally:
- self.delete_package("helloworld")
-
- def test_Plugin_bin_info(self):
- """print_syscalls plugin produced different result"""
- file_name = self.unpackage_file("helloworld")
- try:
- bin_info_path = os.path.join(os.path.dirname(__file__), '..', 'python', 'examples', 'bin_info.py')
- if sys.platform == "win32":
- python_bin = ["py", "-3"]
- else:
- python_bin = ["python3"]
- result = subprocess.Popen(python_bin + [bin_info_path, file_name], stdout=subprocess.PIPE).communicate()[0]
- # normalize line endings and path sep
- return [line for line in result.replace(b"\\", b"/").replace(b"\r\n", b"\n").decode("charmap").split("\n")]
- finally:
- self.delete_package("helloworld")
-
- def test_linear_disassembly(self):
- """linear_disassembly produced different result"""
- file_name = self.unpackage_file("helloworld")
- try:
- bv = binja.BinaryViewType['ELF'].open(file_name)
- disass = bv.linear_disassembly
- retinfo = []
- for i in disass:
- i = str(i)
- i = remove_low_confidence(i)
- retinfo.append(i)
- return retinfo
- finally:
- self.delete_package("helloworld")
-
- def test_data_renderer(self):
- """data renderer produced different result"""
- file_name = self.unpackage_file("helloworld")
- class ElfHeaderDataRenderer(DataRenderer):
- def __init__(self):
- DataRenderer.__init__(self)
- def perform_is_valid_for_data(self, ctxt, view, addr, type, context):
- return DataRenderer.is_type_of_struct_name(type, "Elf64_Header", context)
- def perform_get_lines_for_data(self, ctxt, view, addr, type, prefix, width, context):
- prefix.append(InstructionTextToken(InstructionTextTokenType.TextToken, "I'm in ur Elf64_Header"))
- return [DisassemblyTextLine(prefix, addr)]
- def __del__(self):
- pass
- try:
- bv = binja.BinaryViewType['ELF'].open(file_name)
- ElfHeaderDataRenderer().register_type_specific()
- disass = bv.linear_disassembly
- retinfo = []
- for i in disass:
- i = str(i)
- i = remove_low_confidence(i)
- retinfo.append(i)
- return retinfo
- finally:
- self.delete_package("helloworld")
-
- # def test_partial_register_dataflow(self):
- # """partial_register_dataflow produced different results"""
- # file_name = self.unpackage_file("partial_register_dataflow")
- # result = []
- # reg_list = ['ch', 'cl', 'ah', 'edi', 'al', 'cx', 'ebp', 'ax', 'edx', 'ebx', 'esp', 'esi', 'dl', 'dh', 'di', 'bl', 'bh', 'eax', 'dx', 'bx', 'ecx', 'sp', 'si']
- # bv = binja.load(file_name)
- # for func in bv.functions:
- # llil = func.low_level_il
- # for i in range(0, llil.__len__()-1):
- # for x in reg_list:
- # result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_reg_value(x)).replace('L', ''))
- # result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_possible_reg_values(x)).replace('L', ''))
- # result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_reg_value_after(x)).replace('L', ''))
- # result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_possible_reg_values_after(x)).replace('L', ''))
- # bv.file.close()
- # del bv
- # return result
-
-
- def test_low_il_stack(self):
- """LLIL stack produced different output"""
- file_name = self.unpackage_file("jumptable_reordered")
- try:
- with binja.load(file_name) as bv:
- # reg_list = ['ch', 'cl', 'ah', 'edi', 'al', 'cx', 'ebp', 'ax', 'edx', 'ebx', 'esp', 'esi', 'dl', 'dh', 'di', 'bl', 'bh', 'eax', 'dx', 'bx', 'ecx', 'sp', 'si']
- flag_list = ['c', 'p', 'a', 'z', 's', 'o']
- retinfo = []
- for func in bv.functions:
- for bb in func.low_level_il.basic_blocks:
- for ins in bb:
- retinfo.append("LLIL first stack element: " + str(ins.get_stack_contents(0,1)))
- retinfo.append("LLIL second stack element: " + str(ins.get_stack_contents_after(0,1)))
- retinfo.append("LLIL possible first stack element: " + str(ins.get_possible_stack_contents(0,1)))
- retinfo.append("LLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0,1)))
- for flag in flag_list:
- retinfo.append("LLIL flag {} value at {}: {}".format(flag, hex(ins.address), str(ins.get_flag_value(flag))))
- retinfo.append("LLIL flag {} value after {}: {}".format(flag, hex(ins.address), str(ins.get_flag_value_after(flag))))
- retinfo.append("LLIL flag {} possible value at {}: {}".format(flag, hex(ins.address), str(ins.get_possible_flag_values(flag))))
- retinfo.append("LLIL flag {} possible value after {}: {}".format(flag, hex(ins.address), str(ins.get_possible_flag_values_after(flag))))
- return retinfo
- finally:
- self.delete_package("jumptable_reordered")
-
- def test_med_il_stack(self):
- """MLIL stack produced different output"""
- file_name = self.unpackage_file("jumptable_reordered")
- try:
- with binja.load(file_name) as bv:
- reg_list = ['ch', 'cl', 'ah', 'edi', 'al', 'cx', 'ebp', 'ax', 'edx', 'ebx', 'esp', 'esi', 'dl', 'dh', 'di', 'bl', 'bh', 'eax', 'dx', 'bx', 'ecx', 'sp', 'si']
- flag_list = ['c', 'p', 'a', 'z', 's', 'o']
- retinfo = []
- for func in bv.functions:
- for bb in func.mlil.basic_blocks:
- for ins in bb:
- retinfo.append(f"MLIL stack begin var: {ins.get_var_for_stack_location(0)}")
- retinfo.append(f"MLIL first stack element: {ins.get_stack_contents(0, 1)}")
- retinfo.append(f"MLIL second stack element: {ins.get_stack_contents_after(0, 1)}")
- retinfo.append(f"MLIL possible first stack element: {ins.get_possible_stack_contents(0, 1)}")
- retinfo.append(f"MLIL possible second stack element: {ins.get_possible_stack_contents_after(0, 1)}")
-
- for reg in reg_list:
- retinfo.append(f"MLIL reg {reg} var at {ins.address:#x}: {ins.get_var_for_reg(reg)}")
- retinfo.append(f"MLIL reg {reg} value at {ins.address:#x}: {ins.get_reg_value(reg)}")
- retinfo.append(f"MLIL reg {reg} value after {ins.address:#x}: {ins.get_reg_value_after(reg)}")
- retinfo.append(f"MLIL reg {reg} possible value at {ins.address:#x}: {ins.get_possible_reg_values(reg)}")
- retinfo.append(f"MLIL reg {reg} possible value after {ins.address:#x}: {ins.get_possible_reg_values_after(reg)}")
-
- for flag in flag_list:
- retinfo.append("MLIL flag {} value at {}: {}".format(flag, hex(ins.address), str(ins.get_flag_value(flag))))
- retinfo.append("MLIL flag {} value after {}: {}".format(flag, hex(ins.address), str(ins.get_flag_value_after(flag))))
- retinfo.append("MLIL flag {} possible value at {}: {}".format(flag, hex(ins.address), fixSet(str(ins.get_possible_flag_values(flag)))))
- retinfo.append("MLIL flag {} possible value after {}: {}".format(flag, hex(ins.address), fixSet(str(ins.get_possible_flag_values(flag)))))
- return retinfo
- finally:
- self.delete_package("jumptable_reordered")
-
- def test_events(self):
- """Event failure"""
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
-
- bv.update_analysis_and_wait()
- results = []
-
- def simple_complete(self):
- results.append("analysis complete")
- _ = binja.AnalysisCompletionEvent(bv, simple_complete)
-
- class NotifyTest(binja.BinaryDataNotification):
- def data_written(self, view, offset, length):
- results.append("data written: offset {0} length {1}".format(hex(offset), hex(length)))
-
- def data_inserted(self, view, offset, length):
- results.append("data inserted: offset {0} length {1}".format(hex(offset), hex(length)))
-
- def data_removed(self, view, offset, length):
- results.append("data removed: offset {0} length {1}".format(hex(offset), hex(length)))
-
- def function_added(self, view, func):
- results.append("function added: {0}".format(func.name))
-
- def function_removed(self, view, func):
- results.append("function removed: {0}".format(func.name))
-
- def data_var_added(self, view, var):
- results.append("data var added: {0}".format(hex(var.address)))
-
- def data_var_removed(self, view, var):
- results.append("data var removed: {0}".format(hex(var.address)))
-
- def string_found(self, view, string_type, offset, length):
- results.append("string found: offset {0} length {1}".format(hex(offset), hex(length)))
-
- def string_removed(self, view, string_type, offset, length):
- results.append("string removed: offset {0} length {1}".format(hex(offset), hex(length)))
-
- def type_defined(self, view, name, type):
- results.append("type defined: {0}".format(name))
-
- def type_undefined(self, view, name, type):
- results.append("type undefined: {0}".format(name))
-
- def type_ref_changed(self, view, name, type):
- results.append("type reference changed: {0}".format(name))
-
- def type_field_ref_changed(self, view, name, offset):
- results.append("type field reference changed: {0}, offset {1}".format(name, hex(offset)))
-
- def segment_added(self, view, segment):
- results.append("segment added: {0}".format(segment))
-
- def segment_updated(self, view, segment):
- results.append("segment updated: {0}".format(segment))
-
- def segment_removed(self, view, segment):
- results.append("segment removed: {0}".format(segment))
-
- def section_added(self, view, section):
- results.append("section added: {0} {1}".format(section, section.semantics))
-
- def section_updated(self, view, section):
- results.append("section updated: {0} {1}".format(section, section.semantics))
-
- def section_removed(self, view, section):
- results.append("section removed: {0} {1}".format(section, section.semantics))
-
- test = NotifyTest()
- bv.register_notification(test)
- sacrificial_addr = 0x84fc
-
- type, name = bv.parse_type_string("int foo")
- type_id = Type.generate_auto_type_id("source", name)
-
- bv.define_type(type_id, name, type)
- bv.undefine_type(type_id)
-
- bv.update_analysis_and_wait()
-
- bv.insert(sacrificial_addr, b"AAAA")
- bv.update_analysis_and_wait()
-
- bv.define_data_var(sacrificial_addr, binja.types.Type.int(4))
- bv.update_analysis_and_wait()
-
- bv.define_data_var(sacrificial_addr + 4, "int")
- bv.update_analysis_and_wait()
-
- bv.write(sacrificial_addr, b"BBBB")
- bv.update_analysis_and_wait()
-
- bv.add_function(sacrificial_addr)
- bv.update_analysis_and_wait()
-
- bv.remove_function(bv.get_function_at(sacrificial_addr))
- bv.update_analysis_and_wait()
-
- bv.undefine_data_var(sacrificial_addr)
- bv.update_analysis_and_wait()
-
- bv.undefine_data_var(sacrificial_addr + 4)
- bv.update_analysis_and_wait()
-
- bv.remove(sacrificial_addr, 4)
- bv.update_analysis_and_wait()
-
- type, _ = bv.parse_type_string("struct { uint64_t bar; }")
- bv.define_user_type('foo', type)
- bv.define_user_type('bar', "struct { uint64_t bas; }")
- func = bv.get_function_at(0x8440)
- func.return_type = binja.Type.named_type_from_type('foo', type)
- bv.update_analysis_and_wait()
-
- bv.add_user_segment(0, 5, 0, 5, SegmentFlag.SegmentReadable)
- bv.update_analysis_and_wait()
-
- bv.add_user_segment(0, 5, 0, 5, SegmentFlag.SegmentWritable)
- bv.update_analysis_and_wait()
-
- bv.remove_user_segment(0, 5)
- bv.update_analysis_and_wait()
-
- bv.add_user_section("test_section", 0, 5, SectionSemantics.ReadOnlyDataSectionSemantics)
- bv.update_analysis_and_wait()
-
- bv.add_user_section("test_section", 0, 5, SectionSemantics.ReadWriteDataSectionSemantics)
- bv.update_analysis_and_wait()
-
- bv.remove_user_section("test_section")
- bv.update_analysis_and_wait()
-
- bv.unregister_notification(test)
-
- return sorted(results)
- finally:
- self.delete_package("helloworld")
-
- def test_type_xref(self):
- """Type xref failure"""
-
- def dump_type_xref_info(type_name, code_refs, data_refs, type_refs, offset = None):
- retinfo = []
- if offset is None:
- for ref in code_refs:
- retinfo.append('type {} is referenced by code {}'.format(type_name, ref))
- for ref in data_refs:
- retinfo.append('type {} is referenced by data {}'.format(type_name, ref))
- for ref in type_refs:
- retinfo.append('type {} is referenced by type {}'.format(type_name, ref))
- else:
- for ref in code_refs:
- retinfo.append('type field {}, offset {} is referenced by code {}'.format(type_name, hex(offset), ref))
- for ref in data_refs:
- retinfo.append('type field {}, offset {} is referenced by data {}'.format(type_name, hex(offset), ref))
- for ref in type_refs:
- retinfo.append('type field {}, offset {} is referenced by type {}'.format(type_name, hex(offset), ref))
-
- return retinfo
-
- retinfo = []
- file_name = self.unpackage_file("type_xref.bndb")
- if not os.path.exists(file_name):
- return retinfo
-
- with binja.load(file_name) as bv:
- if bv is None:
- return retinfo
-
- types = bv.types
- test_types = ['A', 'B', 'C', 'D', 'E', 'F']
- for test_type in test_types:
- code_refs = bv.get_code_refs_for_type(test_type)
- data_refs = bv.get_data_refs_for_type(test_type)
- type_refs = bv.get_type_refs_for_type(test_type)
- retinfo.extend(dump_type_xref_info(test_type, code_refs, data_refs, type_refs))
-
- t = types[test_type]
- if not t:
- continue
-
- for member in t.members:
- offset = member.offset
- code_refs = bv.get_code_refs_for_type_field(test_type, offset)
- data_refs = bv.get_data_refs_for_type_field(test_type, offset)
- type_refs = bv.get_type_refs_for_type_field(test_type, offset)
- retinfo.extend(dump_type_xref_info(test_type, code_refs, data_refs, type_refs, offset))
-
- self.delete_package("type_xref.bndb")
- return sorted(retinfo)
-
- def test_variable_xref(self):
- """Variable xref failure"""
-
- def dump_var_xref_info(var, var_refs):
- retinfo = []
- for ref in var_refs:
- retinfo.append('var {} is referenced at {}'.format(repr(var), repr(ref)))
- return retinfo
-
- retinfo = []
- file_name = self.unpackage_file("type_xref.bndb")
- if not os.path.exists(file_name):
- return retinfo
-
- with binja.load(file_name) as bv:
- if bv is None:
- return retinfo
-
- func = bv.get_function_at(0x1169)
- for var in func.vars:
- mlil_refs = func.get_mlil_var_refs(var)
- retinfo.extend(dump_var_xref_info(var, mlil_refs))
- hlil_refs = func.get_hlil_var_refs(var)
- retinfo.extend(dump_var_xref_info(var, hlil_refs))
-
- mlil_range_var_refs = func.get_mlil_var_refs_from(0x1175, 0x8c)
- for ref in mlil_range_var_refs:
- retinfo.append(f"var {ref.var} is referenced at {ref.src}")
-
- hlil_range_var_refs = func.get_hlil_var_refs_from(0x1175, 0x8c)
- for ref in hlil_range_var_refs:
- retinfo.append(f"var {ref.var} is referenced at {ref.src}")
-
- self.delete_package("type_xref.bndb")
- return sorted(retinfo)
-
- # INSANE HACK AHEAD
- # The name `test_all_search` is VERY special here. It reorders this test to
- # before the binary tests. This is EXTREMELY important to the speed of the
- # unit tests on Linux. No one knows why. There be dragons here.
- def test_all_search(self):
- """Search"""
- retinfo = []
- file_name = self.unpackage_file("type_xref.bndb")
- if not os.path.exists(file_name):
- return retinfo
-
- with binja.load(file_name) as bv:
- if bv is None:
- return retinfo
-
- for addr, match in bv.find_all_data(bv.start, bv.end, b'\xc3'):
- retinfo.append('byte 0xc3 is found at address 0x%lx with DataBuffer %s' %
- (addr, match.escape()))
-
- for addr, match, line in bv.find_all_text(bv.start, bv.end, 'test'):
- retinfo.append('text "test" is found at address 0x%lx with string %s \
- line %s' % (addr, match, line))
-
- for addr, line in bv.find_all_constant(bv.start, bv.end, 0x58):
- retinfo.append('constant 0x58 is found at address 0x%lx with line %s' %\
- (addr, line))
-
- def data_callback(addr, match):
- retinfo.append('match found at address: 0x%lx with DataBuffer %s' % (addr, match.escape()))
-
- bv.find_all_data(bv.start, bv.end, b'\xc3', FindFlag.FindCaseSensitive, None,
- data_callback)
-
- def string_callback(addr, match, line):
- retinfo.append('match found at address: 0x%lx with string %s, line %s' %\
- (addr, match, line))
-
- bv.find_all_text(bv.start, bv.end, 'test', None, FindFlag.FindCaseSensitive,
- FunctionGraphType.NormalFunctionGraph, None, string_callback)
-
- def constant_callback(addr, line):
- retinfo.append('match found at address: 0x%lx with constant 0x58, line %s'\
- % (addr, line))
-
- bv.find_all_constant(bv.start, bv.end, 0x58, None,\
- FunctionGraphType.NormalFunctionGraph, None, constant_callback)
-
- self.delete_package("type_xref.bndb")
- return sorted(retinfo)
-
- def test_auto_create_struct(self):
- """Automatically create a structure"""
- retinfo = []
- file_name = self.unpackage_file("auto_create_members.bndb")
- if not os.path.exists(file_name):
- return retinfo
-
- with binja.load(file_name) as bv:
- if bv is None:
- return retinfo
-
- test_types = ['struct_1', 'struct_2', 'struct_3']
- for test_type in test_types:
- offsets = bv.get_all_fields_referenced(test_type)
- for offset in offsets:
- retinfo.append(f'type {test_type}, offset {offset:#x} is referenced')
-
- refs = bv.get_all_sizes_referenced(test_type)
- for offset in refs:
- sizes = refs[offset]
- for size in sizes:
- retinfo.append(f'type {test_type}, offset {offset:#x} is referenced of size {size:#x}')
-
- refs = bv.get_all_types_referenced(test_type)
- for offset in refs:
- types = refs[offset]
- for refType in types:
- retinfo.append(f'type {test_type}, offset {offset:#x} is referenced of type {refType}')
-
- struct = bv.create_structure_from_offset_access(test_type)
- for member in struct.members:
- retinfo.append(f'type {test_type}, member: {member}')
-
- self.delete_package("auto_create_members.bndb")
- return sorted(retinfo)
-
- def test_hlil_arrays(self):
- """HLIL array resolution failure"""
-
- retinfo = []
- file_name = self.unpackage_file("array_test.bndb")
- if not os.path.exists(file_name):
- return retinfo
-
- with binja.load(file_name) as bv:
- if bv is None:
- return retinfo
-
- for func in bv.functions:
- for line in func.hlil.root.lines:
- retinfo.append(f"Function: {func.start:x} HLIL line: {line}")
- for hlilins in func.hlil.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->LLIL instruction: {hlilins.llil}")
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->MLIL instruction: {hlilins.mlil}")
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->MLILS instruction: {sorted(list(map(str, hlilins.mlils)))}")
-
- self.delete_package("array_test.bndb")
-
- retinfo = []
- file_name = self.unpackage_file("struct_array8.bndb")
- if not os.path.exists(file_name):
- return retinfo
-
- with binja.load(file_name) as bv:
- if bv is None:
- return retinfo
-
- for func in bv.functions:
- for line in func.hlil.root.lines:
- retinfo.append(f"Function: {func.start:x} HLIL line: {line}")
- for hlilins in func.hlil.instructions:
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->LLIL instruction: {hlilins.llil}")
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->MLIL instruction: {hlilins.mlil}")
- retinfo.append(f"Function: {func.start:x} Instruction: {hlilins.address:x} HLIL->MLILS instruction: {sorted(list(map(str, hlilins.mlils)))}")
-
- self.delete_package("struct_array8.bndb")
- return sorted(retinfo)
-
- def test_x87_uniqueness(self):
- """
- Verify fix for fmul: that different assembly strings do not disassemble the same
- Vector35/arch-x86#29
- """
- pairs = [
- ("x86", "fadd st0, st1", "fadd st1, st0"),
- ("x86", "fsub st0, st1", "fsub st1, st0"),
- ("x86", "fsubr st0, st1", "fsubr st1, st0"),
- ("x86", "fmul st0, st1", "fmul st1, st0"),
- ("x86", "fdiv st0, st1", "fdiv st1, st0"),
- ("x86", "fdivr st0, st1", "fdivr st1, st0"),
- ]
- for (arch, asm1, asm2) in pairs:
- a = binja.Architecture[arch]
- code1 = a.assemble(asm1)
- code2 = a.assemble(asm2)
- text1 = ''.join(str(t) for t in a.get_instruction_text(code1, 0)[0])
- text2 = ''.join(str(t) for t in a.get_instruction_text(code2, 0)[0])
- assert code1 != code2
- assert text1 != text2, f"{asm1} and {asm2} are different but both disassemble to {text1}"
-
- def test_merge_vars(self):
- """Variable merging produced different output"""
- file_name = self.unpackage_file("array_test.bndb")
- try:
- with binja.load(file_name) as bv:
- func = bv.get_function_at(0x100003920)
- target = None
- sources = []
- for var in func.vars:
- if var.storage == -0x758:
- target = var
- func.delete_user_var(var)
- if var.storage in [-0x760, -0x768, -0x778]:
- sources.append(var)
- func.delete_user_var(var)
-
- func.merge_vars(target, sources)
- bv.update_analysis_and_wait()
-
- retinfo = ["HLIL after merge: " + x for x in str(func.hlil).split("\n")]
-
- sources = sources[1:]
- func.unmerge_vars(target, sources)
- bv.update_analysis_and_wait()
-
- retinfo += ["HLIL after unmerge: " + x for x in str(func.hlil).split("\n")]
- return retinfo
- finally:
- self.delete_package("array_test.bndb")
-
- def test_live_instrs_for_var(self):
- """Live instructions for variable produced different output"""
- file_name = self.unpackage_file("array_test.bndb")
- try:
- with binja.load(file_name) as bv:
- func = bv.get_function_at(0x100003920)
- retinfo = []
- for var in func.vars:
- instrs = func.mlil.get_live_instructions_for_var(var)
- for instr in instrs:
- retinfo += [f"MLIL live instr for {var}: {repr(instr)}"]
- return retinfo
- finally:
- self.delete_package("array_test.bndb")
-
-
-class VerifyBuilder(Builder):
- """ The VerifyBuilder is for tests that verify
- Binary Ninja against expected output.
-
- - Function that are tests should start with 'test_'
- - Function doc string used as 'on error' message
- - Should return: boolean
- """
-
- def __init__(self, test_store):
- super(VerifyBuilder, self).__init__(test_store)
-
- def get_functions(self, bv):
- return [x.start for x in bv.functions]
-
- def get_comments(self, bv):
- return next(bv.functions).comments
-
- def test_possiblevalueset_parse(self):
- """ Failed to parse PossibleValueSet from string"""
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- # ConstantValue
- lhs = bv.parse_possiblevalueset("0", binja.RegisterValueType.ConstantValue)
- rhs = binja.PossibleValueSet.constant(0)
- assert lhs == rhs
- lhs = bv.parse_possiblevalueset("$here + 2", binja.RegisterValueType.ConstantValue, 0x2000)
- rhs = binja.PossibleValueSet.constant(0x2000 + 2)
- assert lhs == rhs
- # ConstantPointerValue
- lhs = bv.parse_possiblevalueset("0x8000", binja.RegisterValueType.ConstantPointerValue)
- rhs = binja.PossibleValueSet.constant_ptr(0x8000)
- assert lhs == rhs
- # StackFrameOffset
- lhs = bv.parse_possiblevalueset("16", binja.RegisterValueType.StackFrameOffset)
- rhs = binja.PossibleValueSet.stack_frame_offset(0x16)
- assert lhs == rhs
- # SignedRangeValue
- lhs = bv.parse_possiblevalueset("-10:0:2", binja.RegisterValueType.SignedRangeValue)
- rhs = binja.PossibleValueSet.signed_range_value([binja.ValueRange(-0x10, 0, 2)])
- assert lhs == rhs
- lhs = bv.parse_possiblevalueset("-10:0:2,2:5:1", binja.RegisterValueType.SignedRangeValue)
- rhs = binja.PossibleValueSet.signed_range_value([binja.ValueRange(-0x10, 0, 2), binja.ValueRange(2, 5, 1)])
- assert lhs == rhs
- # UnsignedRangeValue
- lhs = bv.parse_possiblevalueset("1:10:1", binja.RegisterValueType.UnsignedRangeValue)
- rhs = binja.PossibleValueSet.unsigned_range_value([binja.ValueRange(1, 0x10, 1)])
- assert lhs == rhs
- lhs = bv.parse_possiblevalueset("1:10:1, 2:20:2", binja.RegisterValueType.UnsignedRangeValue)
- rhs = binja.PossibleValueSet.unsigned_range_value([binja.ValueRange(1, 0x10, 1), binja.ValueRange(2, 0x20, 2)])
- assert lhs == rhs
- # InSetOfValues
- lhs = bv.parse_possiblevalueset("1,2,3,3,4", binja.RegisterValueType.InSetOfValues)
- rhs = binja.PossibleValueSet.in_set_of_values([1,2,3,4])
- assert lhs == rhs
- # NotInSetOfValues
- lhs = bv.parse_possiblevalueset("1,2,3,4,4", binja.RegisterValueType.NotInSetOfValues)
- rhs = binja.PossibleValueSet.not_in_set_of_values([1,2,3,4])
- assert lhs == rhs
- # UndeterminedValue
- lhs = bv.parse_possiblevalueset("", binja.RegisterValueType.UndeterminedValue)
- rhs = binja.PossibleValueSet.undetermined()
- assert lhs == rhs
- return True
- finally:
- self.delete_package("helloworld")
-
- def test_expression_parse(self):
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- assert bv.parse_expression("1 + 1") == 2
- assert bv.parse_expression("-1 + 1") == 0
- assert bv.parse_expression("1 - 1") == 0
- assert bv.parse_expression("1 + -1") == 0
- assert bv.parse_expression("[0x8000]") == 0x464c457f
- assert bv.parse_expression("[0x8000]b") == 0
- assert bv.parse_expression("[0x8000].b") == 0x7f
- assert bv.parse_expression("[0x8000].w") == 0x457f
- assert bv.parse_expression("[0x8000].d") == 0x464c457f
- assert bv.parse_expression("[0x8000].q") == 0x10101464c457f
- assert bv.parse_expression("$here + 1", 12345) == 12345 + 1
- assert bv.parse_expression("_start") == 0x830c
- assert bv.parse_expression("_start + 4") == 0x8310
- return True
- finally:
- self.delete_package("helloworld")
-
- def test_get_il_vars(self):
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- main_func = bv.get_functions_by_name("main")[0]
- value = sorted(list(map(lambda v: str(v), main_func.vars)))
- oracle = ['__saved_r11', 'arg_0', 'argc', 'argv', 'envp', 'r0', 'r3', 'var_10', 'var_4', 'var_c']
- assert value == oracle, f"test result from 'main_func.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.lifted_il.vars)))
- oracle = []
- assert value == oracle, f"test result from 'main_func.lifted_il.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.lifted_il.ssa_vars)))
- oracle = []
- assert value == oracle, f"test result from 'main_func.lifted_il.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.vars)))
- oracle = ['lr', 'r0', 'r1', 'r11', 'r12', 'r2', 'r3', 'sp', 'temp0']
- assert value == oracle, f"test result from 'main_func.llil.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.ssa_vars)))
- oracle = ['<ssa lr version 0>', '<ssa lr version 1>', '<ssa lr version 2>', '<ssa lr version 3>', '<ssa r0 version 0>', '<ssa r0 version 1>', '<ssa r0 version 2>', '<ssa r0 version 3>', '<ssa r0 version 4>', '<ssa r0 version 5>', '<ssa r0 version 6>', '<ssa r1 version 0>', '<ssa r1 version 1>', '<ssa r1 version 2>', '<ssa r1 version 3>', '<ssa r11 version 0>', '<ssa r11 version 1>', '<ssa r11 version 2>', '<ssa r12 version 1>', '<ssa r12 version 2>', '<ssa r12 version 3>', '<ssa r2 version 1>', '<ssa r2 version 2>', '<ssa r2 version 3>', '<ssa r3 version 1>', '<ssa r3 version 2>', '<ssa r3 version 3>', '<ssa r3 version 4>', '<ssa r3 version 5>', '<ssa sp version 0>', '<ssa sp version 1>', '<ssa sp version 2>', '<ssa sp version 3>', '<ssa sp version 4>', '<ssa sp version 5>', '<ssa sp version 6>', '<ssa temp0 version 1>']
- assert value == oracle, f"test result from 'main_func.llil.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.ssa_form.vars)))
- oracle = ['lr', 'r0', 'r1', 'r11', 'r12', 'r2', 'r3', 'sp', 'temp0']
- assert value == oracle, f"test result from 'main_func.llil.ssa_form.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.ssa_form.ssa_registers)))
- oracle = ['<ssa lr version 0>', '<ssa lr version 1>', '<ssa lr version 2>', '<ssa lr version 3>', '<ssa r0 version 0>', '<ssa r0 version 1>', '<ssa r0 version 2>', '<ssa r0 version 3>', '<ssa r0 version 4>', '<ssa r0 version 5>', '<ssa r0 version 6>', '<ssa r1 version 0>', '<ssa r1 version 1>', '<ssa r1 version 2>', '<ssa r1 version 3>', '<ssa r11 version 0>', '<ssa r11 version 1>', '<ssa r11 version 2>', '<ssa r12 version 1>', '<ssa r12 version 2>', '<ssa r12 version 3>', '<ssa r2 version 1>', '<ssa r2 version 2>', '<ssa r2 version 3>', '<ssa r3 version 1>', '<ssa r3 version 2>', '<ssa r3 version 3>', '<ssa r3 version 4>', '<ssa r3 version 5>', '<ssa sp version 0>', '<ssa sp version 1>', '<ssa sp version 2>', '<ssa sp version 3>', '<ssa sp version 4>', '<ssa sp version 5>', '<ssa sp version 6>', '<ssa temp0 version 1>']
- assert value == oracle, f"test result from 'main_func.llil.ssa_form.ssa_registers' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.ssa_form.ssa_register_stacks)))
- oracle = []
- assert value == oracle, f"test result from 'main_func.llil.ssa_form.ssa_register_stacks' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.ssa_form.ssa_flags)))
- oracle = []
- assert value == oracle, f"test result from 'main_func.llil.ssa_form.ssa_flags' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.mapped_medium_level_il.vars)))
- oracle = ['__saved_r11', 'argc', 'argv', 'envp', 'lr', 'r11', 'r12', 'r3', 'sp', 'temp0', 'var_10', 'var_4', 'var_c']
- assert value == oracle, f"test result from 'main_func.llil.mapped_medium_level_il.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.mapped_medium_level_il.ssa_vars)))
- oracle = ['<ssa __saved_r11 version 1>', '<ssa argc version 0>', '<ssa argc version 1>', '<ssa argc version 2>', '<ssa argc version 3>', '<ssa argc version 4>', '<ssa argc version 5>', '<ssa argc version 6>', '<ssa argv version 0>', '<ssa argv version 1>', '<ssa argv version 2>', '<ssa argv version 3>', '<ssa envp version 1>', '<ssa envp version 2>', '<ssa envp version 3>', '<ssa lr version 0>', '<ssa lr version 1>', '<ssa lr version 2>', '<ssa lr version 3>', '<ssa r11 version 0>', '<ssa r11 version 1>', '<ssa r11 version 2>', '<ssa r12 version 1>', '<ssa r12 version 2>', '<ssa r12 version 3>', '<ssa r3 version 1>', '<ssa r3 version 2>', '<ssa r3 version 3>', '<ssa r3 version 4>', '<ssa r3 version 5>', '<ssa sp version 1>', '<ssa sp version 2>', '<ssa sp version 3>', '<ssa sp version 4>', '<ssa sp version 5>', '<ssa sp version 6>', '<ssa temp0 version 1>', '<ssa var_10 version 1>', '<ssa var_4 version 1>', '<ssa var_c version 1>']
- assert value == oracle, f"test result from 'main_func.llil.mapped_medium_level_il.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.mapped_medium_level_il.ssa_form.vars)))
- oracle = ['__saved_r11', 'argc', 'argv', 'envp', 'lr', 'r11', 'r12', 'r3', 'sp', 'temp0', 'var_10', 'var_4', 'var_c']
- assert value == oracle, f"test result from 'main_func.llil.mapped_medium_level_il.ssa_form.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.llil.mapped_medium_level_il.ssa_form.ssa_vars)))
- oracle = ['<ssa __saved_r11 version 1>', '<ssa argc version 0>', '<ssa argc version 1>', '<ssa argc version 2>', '<ssa argc version 3>', '<ssa argc version 4>', '<ssa argc version 5>', '<ssa argc version 6>', '<ssa argv version 0>', '<ssa argv version 1>', '<ssa argv version 2>', '<ssa argv version 3>', '<ssa envp version 1>', '<ssa envp version 2>', '<ssa envp version 3>', '<ssa lr version 0>', '<ssa lr version 1>', '<ssa lr version 2>', '<ssa lr version 3>', '<ssa r11 version 0>', '<ssa r11 version 1>', '<ssa r11 version 2>', '<ssa r12 version 1>', '<ssa r12 version 2>', '<ssa r12 version 3>', '<ssa r3 version 1>', '<ssa r3 version 2>', '<ssa r3 version 3>', '<ssa r3 version 4>', '<ssa r3 version 5>', '<ssa sp version 1>', '<ssa sp version 2>', '<ssa sp version 3>', '<ssa sp version 4>', '<ssa sp version 5>', '<ssa sp version 6>', '<ssa temp0 version 1>', '<ssa var_10 version 1>', '<ssa var_4 version 1>', '<ssa var_c version 1>']
- assert value == oracle, f"test result from 'main_func.llil.mapped_medium_level_il.ssa_form.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.mlil.vars)))
- oracle = ['argc', 'argv', 'r0', 'r3', 'var_10', 'var_c']
- assert value == oracle, f"test result from 'main_func.mlil.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.mlil.ssa_vars)))
- oracle = ['<ssa argc version 0>', '<ssa argv version 0>', '<ssa r0 version 1>', '<ssa r3 version 1>', '<ssa var_10 version 1>', '<ssa var_c version 1>']
- assert value == oracle, f"test result from 'main_func.mlil.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.mlil.ssa_form.vars)))
- oracle = ['argc', 'argv', 'r0', 'r3', 'var_10', 'var_c']
- assert value == oracle, f"test result from 'main_func.mlil.ssa_form.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.mlil.ssa_form.ssa_vars)))
- oracle = ['<ssa argc version 0>', '<ssa argv version 0>', '<ssa r0 version 1>', '<ssa r3 version 1>', '<ssa var_10 version 1>', '<ssa var_c version 1>']
- assert value == oracle, f"test result from 'main_func.mlil.ssa_form.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.hlil.vars)))
- oracle = ['argc', 'argv', 'var_10']
- assert value == oracle, f"test result from 'main_func.hlil.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.hlil.ssa_vars)))
- oracle = ['<ssa argc version 0>', '<ssa argv version 0>', '<ssa var_10 version 1>']
- assert value == oracle, f"test result from 'main_func.hlil.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.hlil.ssa_form.vars)))
- oracle = ['argc', 'argv', 'var_10']
- assert value == oracle, f"test result from 'main_func.hlil.ssa_form.vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), main_func.hlil.ssa_form.ssa_vars)))
- oracle = ['<ssa argc version 0>', '<ssa argv version 0>', '<ssa var_10 version 1>']
- assert value == oracle, f"test result from 'main_func.hlil.ssa_form.ssa_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
-
- start_func = bv.get_functions_by_name("_start")[0]
- value = sorted(list(map(lambda v: str(v), start_func.mlil.aliased_vars)))
- oracle = ['arg_4']
- assert value == oracle, f"test result from 'start_func.mlil.aliased_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), start_func.mlil.ssa_form.aliased_vars)))
- oracle = ['arg_4']
- assert value == oracle, f"test result from 'start_func.mlil.ssa_form.aliased_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), start_func.hlil.aliased_vars)))
- oracle = ['arg_4']
- assert value == oracle, f"test result from 'start_func.hlil.aliased_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
- value = sorted(list(map(lambda v: str(v), start_func.hlil.ssa_form.aliased_vars)))
- oracle = ['arg_4']
- assert value == oracle, f"test result from 'start_func.hlil.ssa_form.aliased_vars' = \n\t{value}\nwhich is != to oracle: \n\t{oracle}"
-
- return True
- finally:
- self.delete_package("helloworld")
-
- def test_verify_BNDB_round_trip(self):
- """Binary Ninja Database output doesn't match its input"""
- # This will test Binja's ability to save and restore databases
- # By:
- # - Creating a binary view
- # - Make modification that impact the database
- # - Record those modification
- # - Save the database
- # - Restore the datbase
- # - Validate that the modifications are present
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- bv.update_analysis_and_wait()
- # Make some modifications to the binary view
-
- # Add a comment
- f = next(bv.functions)
- f.set_comment(f.start, "Function start")
- # Add a new function
- bv.add_function(f.start + 4)
- temp_name = next(tempfile._get_candidate_names()) + ".bndb"
-
- comments = self.get_comments(bv)
- functions = self.get_functions(bv)
- bv.create_database(temp_name)
- bv.file.close()
- del bv
-
- bv = binja.FileMetadata(temp_name).open_existing_database(temp_name).get_view_of_type('ELF')
- bv.update_analysis_and_wait()
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- # force windows to close the handle to the bndb that we want to delete
- bv.file.close()
- del bv
- os.unlink(temp_name)
- return [str(functions == bndb_functions and comments == bndb_comments)]
- finally:
- self.delete_package("helloworld")
-
- def test_verify_persistent_undo(self):
- file_name = self.unpackage_file("helloworld")
- try:
- temp_name = next(tempfile._get_candidate_names()) + ".bndb"
-
- with binja.load(file_name) as bv:
-
- bv.update_analysis_and_wait()
-
- bv.begin_undo_actions()
- f = next(bv.functions)
- f.set_comment(f.start, "Function start")
- bv.commit_undo_actions()
-
- bv.update_analysis_and_wait()
- comments = self.get_comments(bv)
- functions = self.get_functions(bv)
-
- bv.begin_undo_actions()
- f.set_comment(f.start, "Function start!")
- bv.commit_undo_actions()
-
- bv.begin_undo_actions()
- bv.create_user_function(bv.start)
- bv.commit_undo_actions()
-
- bv.update_analysis_and_wait()
- bv.create_database(temp_name)
-
- with binja.FileMetadata(temp_name).open_existing_database(temp_name).get_view_of_type('ELF') as bv:
-
- bv.update_analysis_and_wait()
-
- bv.undo()
- bv.undo()
-
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
-
- os.unlink(temp_name)
- return functions == bndb_functions and comments == bndb_comments
-
- finally:
- self.delete_package("helloworld")
-
- def test_memory_leaks(self):
- """Detected memory leaks during analysis"""
- # This test will attempt to detect object leaks during headless analysis
- file_name = self.unpackage_file("helloworld")
- try:
- # Open the binary once and let any persistent structures be created (typically types)
- bv = binja.BinaryViewType['ELF'].open(file_name)
- bv.update_analysis_and_wait()
- # Hold on to a graph reference while tearing down the binary view. This will keep a reference
- # in the core. If we directly free the view, the teardown will happen in a worker thread and
- # we will not be able to get a reliable object count. By keeping a reference in a different
- # object in the core, the teardown will occur immediately upon freeing the other object.
- graph = next(bv.functions).create_graph()
- bv.file.close()
- del bv
- import gc
- gc.collect()
- del graph
- gc.collect()
-
- initial_object_counts = binja.get_memory_usage_info()
-
- # Analyze the binary again
- bv = binja.BinaryViewType['ELF'].open(file_name)
- bv.update_analysis_and_wait()
- graph = next(bv.functions).create_graph()
- bv.file.close()
- del bv
- gc.collect()
- del graph
- gc.collect()
-
- # Capture final object count
- final_object_counts = binja.get_memory_usage_info()
-
- # Check for leaks
- ok = True
- for i in initial_object_counts.keys():
- if final_object_counts[i] > initial_object_counts[i]:
- ok = False
- return ok
- finally:
- self.delete_package("helloworld")
-
- def test_univeral_loader(self):
- """Universal Mach-O Loader Tests"""
- file_name = self.unpackage_file("fat_macho_9arch")
- save_setting_value = binja.Settings().get_string_list("files.universal.architecturePreference")
- binja.Settings().reset("files.universal.architecturePreference")
- try:
- # test with default arch preference
- with binja.load(file_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "x86")
- assert(bv.start == 0x1000)
- load_setting_keys = bv.get_load_settings("Mach-O")
- assert(load_setting_keys is not None)
- assert(len(bv.get_load_settings("Mach-O").keys()) == 1)
- assert(bv.get_load_settings("Mach-O").get_integer("loader.macho.universalImageOffset") == 0x1000)
-
- # save temp bndb for round trip testing
- f = next(bv.functions)
- f.set_comment(f.start, "Function start")
- comments = self.get_comments(bv)
- functions = self.get_functions(bv)
- temp_name = next(tempfile._get_candidate_names()) + ".bndb"
- bv.create_database(temp_name)
-
- # test binja.load open path
- binja.Settings().reset("files.universal.architecturePreference")
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "x86")
- assert(bv.start == 0x1000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
-
- # test binja.load open path
- binja.Settings().reset("files.universal.architecturePreference")
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "x86")
- assert(bv.start == 0x1000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
-
- # test binja.load open path (modified architecture preference)
- binja.Settings().set_string_list("files.universal.architecturePreference", ["arm64"])
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "x86")
- assert(bv.start == 0x1000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
-
- # test binja.load open path (modified architecture preference)
- binja.Settings().set_string_list("files.universal.architecturePreference", ["x86_64", "arm64"])
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "x86")
- assert(bv.start == 0x1000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
- os.unlink(temp_name)
-
- # test with overridden arch preference
- binja.Settings().set_string_list("files.universal.architecturePreference", ["arm64"])
- with binja.load(file_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "aarch64")
- assert(bv.start == 0x100000000)
- load_setting_keys = bv.get_load_settings("Mach-O")
- assert(load_setting_keys is not None)
- assert(len(bv.get_load_settings("Mach-O").keys()) == 1)
- assert(bv.get_load_settings("Mach-O").get_integer("loader.macho.universalImageOffset") == 0x4c000)
-
- # save temp bndb for round trip testing
- f = next(bv.functions)
- f.set_comment(f.start, "Function start")
- comments = self.get_comments(bv)
- functions = self.get_functions(bv)
- temp_name = next(tempfile._get_candidate_names()) + ".bndb"
- bv.create_database(temp_name)
-
- # test binja.load open path
- binja.Settings().reset("files.universal.architecturePreference")
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "aarch64")
- assert(bv.start == 0x100000000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
-
- # test binja.load open path
- binja.Settings().reset("files.universal.architecturePreference")
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "aarch64")
- assert(bv.start == 0x100000000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
-
- # test binja.load open path (modified architecture preference)
- binja.Settings().set_string_list("files.universal.architecturePreference", ["x86"])
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "aarch64")
- assert(bv.start == 0x100000000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
-
- # test binja.load open path (modified architecture preference)
- binja.Settings().set_string_list("files.universal.architecturePreference", ["x86_64", "arm64"])
- with binja.load(temp_name) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "aarch64")
- assert(bv.start == 0x100000000)
- bndb_functions = self.get_functions(bv)
- bndb_comments = self.get_comments(bv)
- assert([str(functions == bndb_functions and comments == bndb_comments)])
- bv.file.close()
- os.unlink(temp_name)
-
-
- binja.Settings().set_string_list("files.universal.architecturePreference", ["x86_64", "arm64"])
- with binja.load(file_name, options={'loader.imageBase': 0xfffffff0000}) as bv:
- assert(bv.view_type == "Mach-O")
- assert(bv.arch.name == "x86_64")
- assert(bv.start == 0xfffffff0000)
- load_setting_keys = bv.get_load_settings("Mach-O")
- assert(load_setting_keys is not None)
- assert(len(bv.get_load_settings("Mach-O").keys()) == 8)
- assert(bv.get_load_settings("Mach-O").get_integer("loader.macho.universalImageOffset") == 0x8000)
-
- binja.Settings().set_string_list("files.universal.architecturePreference", save_setting_value)
- return True
-
- finally:
- binja.Settings().set_string_list("files.universal.architecturePreference", save_setting_value)
- self.delete_package("fat_macho_9arch")
-
- def test_user_informed_dataflow(self):
- """User-informed dataflow tests"""
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- func = bv.get_function_at(0x00008440)
-
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
- assert(ins.operation == binja.MediumLevelILOperation.MLIL_IF)
- assert(len(ins.vars_read) == 1)
- var = ins.vars_read[0]
- defs = func.mlil.get_var_definitions(var)
- assert(len(defs) == 1)
- def_site = defs[0].address
-
- # Set variable value to 0
- bv.begin_undo_actions()
- func.set_user_var_value(var, def_site, binja.PossibleValueSet.constant(0))
- bv.commit_undo_actions()
- bv.update_analysis_and_wait()
-
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
- assert(ins.operation == binja.MediumLevelILOperation.MLIL_IF)
- # test if condition value is updated to true
- assert(ins.condition.value == True)
- # test if register value is updated to 0
- assert(ins.get_reg_value_after('r3') == 0)
- # test if branch is eliminated in hlil
- for hlil_ins in func.hlil.instructions:
- assert(hlil_ins.operation != binja.HighLevelILOperation.HLIL_IF)
-
- # test undo action
- bv.undo()
- bv.update_analysis_and_wait()
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
- assert(ins.operation == binja.MediumLevelILOperation.MLIL_IF)
- # test if condition value is updated to undetermined
- assert(ins.condition.value.type == binja.RegisterValueType.UndeterminedValue)
- # test if register value is updated to undetermined
- assert(ins.get_reg_value_after('r3').type == binja.RegisterValueType.EntryValue)
- # test if branch is restored in hlil
- found = False
- for hlil_ins in func.hlil.instructions:
- if hlil_ins.operation == binja.HighLevelILOperation.HLIL_IF:
- found = True
- assert(found)
-
- # test redo action
- bv.redo()
- bv.update_analysis_and_wait()
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
- assert(ins.operation == binja.MediumLevelILOperation.MLIL_IF)
- # test if condition value is updated to true
- assert(ins.condition.value == True)
- # test if register value is updated to 0
- assert(ins.get_reg_value_after('r3') == 0)
- # test if branch is eliminated in hlil
- for hlil_ins in func.hlil.instructions:
- assert(hlil_ins.operation != binja.HighLevelILOperation.HLIL_IF)
-
- # test bndb round trip
- temp_name = next(tempfile._get_candidate_names()) + ".bndb"
- bv.create_database(temp_name)
-
- with binja.load(temp_name) as bv:
- func = bv.get_function_at(0x00008440)
-
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
- assert(ins.operation == binja.MediumLevelILOperation.MLIL_IF)
- # test if condition value is updated to true
- assert(ins.condition.value == True)
- # test if register value is updated to 0
- assert(ins.get_reg_value_after('r3') == 0)
- # test if branch is eliminated in hlil
- for hlil_ins in func.hlil.instructions:
- assert(hlil_ins.operation != binja.HighLevelILOperation.HLIL_IF)
-
- # test undo after round trip
- bv.undo()
- bv.update_analysis_and_wait()
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
- assert(ins.operation == binja.MediumLevelILOperation.MLIL_IF)
- # test if condition value is updated to undetermined
- assert(ins.condition.value.type == binja.RegisterValueType.UndeterminedValue)
- # test if register value is updated to undetermined
- assert(ins.get_reg_value_after('r3').type == binja.RegisterValueType.EntryValue)
- # test if branch is restored in hlil
- found = False
- for hlil_ins in func.hlil.instructions:
- if hlil_ins.operation == binja.HighLevelILOperation.HLIL_IF:
- found = True
- assert(found)
-
- os.unlink(temp_name)
- return True
-
- finally:
- self.delete_package("helloworld")
-
- def test_possiblevalueset_ser_and_deser(self):
- """PossibleValueSet serialization and deserialization"""
- def test_helper(value):
- file_name = self.unpackage_file("helloworld")
- try:
- with binja.load(file_name) as bv:
- func = bv.get_function_at(0x00008440)
-
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
-
- var = ins.vars_read[0]
- defs = func.mlil.get_var_definitions(var)
- def_site = defs[0].address
-
- func.set_user_var_value(var, def_site, value)
- bv.update_analysis_and_wait()
-
- def_ins_idx = func.mlil.get_instruction_start(def_site)
- def_ins = func.mlil[def_ins_idx]
-
- assert(def_ins.get_possible_reg_values_after('r3') == value)
-
- temp_name = next(tempfile._get_candidate_names()) + ".bndb"
- bv.create_database(temp_name)
-
- with binja.load(temp_name) as bv:
- func = bv.get_function_at(0x00008440)
-
- ins_idx = func.mlil.get_instruction_start(0x845c)
- ins = func.mlil[ins_idx]
-
- def_ins_idx = func.mlil.get_instruction_start(def_site)
- def_ins = func.mlil[def_ins_idx]
-
- assert(def_ins.get_possible_reg_values_after('r3') == value)
-
- os.unlink(temp_name)
- return True
-
- finally:
- self.delete_package("helloworld")
-
- assert(test_helper(binja.PossibleValueSet.constant(0)))
- assert(test_helper(binja.PossibleValueSet.constant_ptr(0x8000)))
- assert(test_helper(binja.PossibleValueSet.unsigned_range_value([binja.ValueRange(1, 10, 2)])))
- # assert(test_helper(binja.PossibleValueSet.signed_range_value([binja.ValueRange(-10, 0, 2)])))
- assert(test_helper(binja.PossibleValueSet.in_set_of_values([1,2,3,4])))
- assert(test_helper(binja.PossibleValueSet.not_in_set_of_values([1,2,3,4])))
- return True
-
- def test_binaryview_callbacks(self):
- """BinaryView finalized callback and analysis completion callback"""
- file_name = self.unpackage_file("helloworld")
-
- # Currently, there is no way to unregister a BinaryView event callback.
- # This boolean tells the callback function whether it should run or just return
- callback_should_run = True
-
- def bv_finalized_callback(bv):
- if callback_should_run:
- bv.store_metadata('finalized', 'yes')
-
- def bv_finalized_callback_2(bv):
- if callback_should_run:
- bv.store_metadata('finalized_2', 'yes')
-
- def bv_analysis_completion_callback(bv):
- if callback_should_run:
- bv.store_metadata('analysis_completion', 'yes')
-
- BinaryViewType.add_binaryview_finalized_event(bv_finalized_callback)
- BinaryViewType.add_binaryview_finalized_event(bv_finalized_callback_2)
- BinaryViewType.add_binaryview_initial_analysis_completion_event(bv_analysis_completion_callback)
-
- try:
- with binja.load(file_name) as bv:
- finalized = bv.query_metadata('finalized') == 'yes'
- finalized_2 = bv.query_metadata('finalized_2') == 'yes'
- analysis_completion = bv.query_metadata('analysis_completion') == 'yes'
- return finalized and finalized_2 and analysis_completion
-
- finally:
- self.delete_package("helloworld")
- callback_should_run = False
-
- def test_load_old_database(self):
- """Load a database produced by older versions of Binary Ninja"""
- for version in ["binja_v1.2.1921_bin_ls.bndb", "binja_v2.2.2487_bin_ls.bndb", "binja_v2.5.3112_bin_ls.bndb"]:
- file_name = self.unpackage_file(version)
- if not os.path.exists(file_name):
- return False
-
- binja.Settings().set_bool("analysis.database.suppressReanalysis", True)
- ret = None
- with binja.load(file_name) as bv:
- if bv is None:
- ret = False
- if bv.file.snapshot_data_applied_without_error:
- ret = True
-
- binja.Settings().reset("analysis.database.suppressReanalysis")
- self.delete_package(version)
-
- if not ret:
- return ret
- return True
-
- def test_struct_type_leakage(self):
- """
- Define a structure, then assign a variable to it. There should only be NTRs (and not dereffed types) in func.vars
- See: #2428
- """
- file_name = self.unpackage_file("basic_struct")
-
- ret = True
- try:
- with binja.load(file_name) as bv:
- # struct A { uint64_t a; uint64_t b; };
- with binja.StructureBuilder.builder(bv, "A") as s:
- s.width = 0x10
- s.append(binja.Type.int(8, False), "a")
- s.append(binja.Type.int(8, False), "b")
-
- # Find main and the var it sets to malloc(0x10)
- func = [f for f in bv.functions if f.name == '_main'][0]
- for v in func.vars:
- d = func.mlil.get_var_definitions(v)
- if len(d) == 0:
- continue
-
- if d[0].operation == binja.MediumLevelILOperation.MLIL_CALL:
- var = v
-
- # Change var type to struct A*
- vt = binja.Type.pointer(bv.arch, binja.Type.named_type_from_registered_type(bv, 'A'))
- func.create_user_var(var, vt, 'test')
- bv.update_analysis_and_wait()
-
- for v in func.vars:
- if isinstance(v.type, binja.types.PointerType):
- if isinstance(v.type.target, binja.types.StructureType):
- ret = False
- print(f"Found ptr to raw structure: {v.type} {v}")
- finally:
- self.delete_package("basic_struct")
-
- return ret
-
- def test_old_tags(self):
- """
- New builds use string-based ids for tags, whereas older builds used integers. Make sure the old builds still work
- """
-
- file_name = self.unpackage_file("old_tags.bndb")
- assert file_name is not None
- ret = True
- try:
- binja.Settings().set_bool("analysis.database.suppressReanalysis", True)
- with binja.load(file_name) as bv:
- if bv is None:
- ret = False
- raise Exception("File binja.load error")
- if not bv.file.snapshot_data_applied_without_error:
- ret = False
- raise Exception("Snapshot apply error")
-
- # Make sure the tags exist and are where we expect them
- _start = bv.get_function_at(bv.start + 0x1060)
- assert _start is not None
- sub_1012 = bv.get_function_at(bv.start + 0x1012)
-
- assert len(bv.get_data_tags_at(bv.start + 0x6030)) == 1
- assert bv.get_data_tags_at(bv.start + 0x6030)[0].type.name == 'Bookmarks'
- assert bv.get_data_tags_at(bv.start + 0x6030)[0].data == '2'
- assert bv.get_data_tags_at(bv.start + 0x6030)[0].id == '7'
-
- assert len(bv.get_data_tags_at(bv.start + 0x6040)) == 2
- assert bv.get_data_tags_at(bv.start + 0x6040)[0].type.name == 'Crashes'
- assert bv.get_data_tags_at(bv.start + 0x6040)[0].data == 'New Tag'
- assert bv.get_data_tags_at(bv.start + 0x6040)[0].id == '8'
- assert bv.get_data_tags_at(bv.start + 0x6040)[1].type.name == 'Library'
- assert bv.get_data_tags_at(bv.start + 0x6040)[1].data == 'New Tag'
- assert bv.get_data_tags_at(bv.start + 0x6040)[1].id == '9'
-
- function_tags = list(_start.function_tags)
- assert len(function_tags) == 1
- assert function_tags[0].type.name == 'Library'
- assert function_tags[0].data == 'New Tag'
- assert function_tags[0].id == '1'
-
- function_tags = list(sub_1012.function_tags)
- assert len(function_tags) == 2
- assert function_tags[0].type.name == 'Library'
- assert function_tags[0].data == 'New Tag'
- assert function_tags[0].id == '3'
- assert function_tags[1].type.name == 'Bugs'
- assert function_tags[1].data == 'New Tag'
- assert function_tags[1].id == '10'
-
- address_tags = list(_start.get_address_tags_at(bv.start + 0x1097))
- assert len(address_tags) == 1
- assert address_tags[0].type.name == 'Important'
- assert address_tags[0].data == 'New Tag'
- assert address_tags[0].id == '4'
-
- address_tags = list(_start.get_address_tags_at(bv.start + 0x1116))
- assert len(address_tags) == 2
- assert address_tags[0].type.name == 'Crashes'
- assert address_tags[0].data == 'New Tag'
- assert address_tags[0].id == '5'
- assert address_tags[1].type.name == 'Needs Analysis'
- assert address_tags[1].data == 'New Tag'
- assert address_tags[1].id == '6'
-
- binja.Settings().reset("analysis.database.suppressReanalysis")
- finally:
- self.delete_package("old_tags.bndb")
-
- return ret
-
- def test_get_paths(self):
- """Get install directory and bundled plugin directory"""
- core_platform = system()
-
- install_dir = binja.get_install_directory()
- if not os.path.isdir(install_dir):
- return False
-
- files = os.listdir(install_dir)
- if core_platform == "Darwin":
- if not 'libbinaryninjacore.dylib' in files:
- return False
- elif core_platform == "Linux":
- if not 'libbinaryninjacore.so.1' in files:
- return False
- elif core_platform == "Windows":
- if not 'binaryninjacore.dll' in files:
- return False
- else:
- return False
-
- plugin_dir = binja.bundled_plugin_path()
- if not os.path.isdir(plugin_dir):
- return False
-
- files = os.listdir(plugin_dir)
- if core_platform == "Darwin":
- if not 'libarch_x86.dylib' in files:
- return False
- elif core_platform == "Linux":
- if not 'libarch_x86.so' in files:
- return False
- elif core_platform == "Windows":
- if not 'arch_x86.dll' in files:
- return False
- else:
- return False
-
- return True
diff --git a/suite/unit_api.py b/suite/unit_api.py
deleted file mode 100755
index 3c93e823..00000000
--- a/suite/unit_api.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-# This test file is maintained for API unit test distribution.
-import os
-import sys
-import unittest
-import pickle
-import zipfile
-import difflib
-from collections import Counter
-
-api_suite_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "api", "suite")
-sys.path.append(api_suite_path)
-import testcommon
-import api_test
-
-global verbose
-verbose = False
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- for i in range(1, len(sys.argv)):
- if sys.argv[i] == '-v' or sys.argv[i] == '-V' or sys.argv[i] == '--verbose':
- verbose = True
-
- test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test)
- runner = unittest.TextTestRunner(verbosity=2)
- runner.run(test_suite)