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.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 = BinaryViewType.get_view_of_file(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::detach_helper_grow(int32_t, int32_t)", "int32_t QStatePrivate::emitPropertiesAssigned()", "int32_t QtMetaTypePrivate::QMetaTypeFunctionHelper::Construct(void*, void const*)", "int32_t QSharedDataPointer::data()", "void QAbstractNativeEventFilter::~QAbstractNativeEventFilter()", "int32_t QList::end()", "int32_t BinaryNinjaCore::ArchitectureWrapper::GetOpcodeDisplayLength() const", "int32_t BinaryNinjaCore::ScriptingInstance::SetCurrentSelection(uint64_t, uint64_t)", "int32_t (anonymous namespace)::TypeDestructor::DestructorImpl::Destruct(int32_t, void*)", "int32_t QGb18030Codec::_name()", "int32_t QList::detach()", "int32_t QBasicAtomicPointer >::testAndSetRelease(QFreeList*, QFreeList*)", "int32_t QJsonPrivate::Parser::reserveSpace(int32_t)", "int32_t QStateMachinePrivate::endMacrostep(bool)", "void QScopedPointer >::~QScopedPointer()", "bool QVariantIsNull<(anonymous namespace)::CoreTypesFilter>::delegate(QMatrix4x4 const*)", "void QAbstractProxyModelPrivate::QAbstractProxyModelPrivate()", "int32_t std::__1::__function::__func, 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, data: binaryview.BinaryView, name: types.QualifiedName, line_width, 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, '', 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" result = tp.get_type_lines(Type.void(), BinaryView.new(b''), QualifiedName(['test'])) 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("") 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(" -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('') 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 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) self.func.function_type = ftm 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("") 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("" 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) == '', 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) == "" ai = self.bv.analysis_info assert repr(ai) == "" 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('" 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 BinaryViewType.get_view_of_file(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 = BinaryViewType.get_view_of_file_with_options( # 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)