diff options
| author | Mason Reed <mason@vector35.com> | 2024-06-14 12:20:46 -0400 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2024-06-14 12:20:46 -0400 |
| commit | 3c58f74fe8e8bb9029cfe560a836303a2ce3bbdb (patch) | |
| tree | 8566be9997805944141e3c745c26fdbe4bc07b3e | |
| parent | f4eb81635006d8bbfe1a4a7550d62ae3163117a3 (diff) | |
Delete unmaintained test suite
| -rw-r--r-- | suite/api_test.py | 3565 | ||||
| m--------- | suite/binaries | 0 | ||||
| -rwxr-xr-x | suite/generator.py | 471 | ||||
| -rw-r--r-- | suite/pwnadventurez.nes | bin | 262160 -> 0 bytes | |||
| -rw-r--r-- | suite/testcommon.py | 2306 | ||||
| -rwxr-xr-x | suite/unit_api.py | 27 |
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 Binary files differdeleted file mode 100644 index 630684e3..00000000 --- a/suite/pwnadventurez.nes +++ /dev/null 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) |
