diff options
| -rw-r--r-- | platform/mac/platform_mac.cpp | 172 | ||||
| -rw-r--r-- | view/macho/machoview.cpp | 82 | ||||
| -rw-r--r-- | view/macho/machoview.h | 2 |
3 files changed, 218 insertions, 38 deletions
diff --git a/platform/mac/platform_mac.cpp b/platform/mac/platform_mac.cpp index f1a33333..6a539f66 100644 --- a/platform/mac/platform_mac.cpp +++ b/platform/mac/platform_mac.cpp @@ -4,6 +4,10 @@ using namespace BinaryNinja; using namespace std; +Ref<Platform> g_macX86, g_macX64, g_macArmv7, g_macThumb2, g_macArm64; +Ref<Platform> g_iosArmv7, g_iosThumb2, g_iosArm64; + + class MacX86Platform: public Platform { public: @@ -31,6 +35,17 @@ public: { return false; } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + auto machoPlatform = metadata->Get("machoplatform"); + if (!machoPlatform || !machoPlatform->IsUnsignedInteger()) + return nullptr; + if (machoPlatform->GetUnsignedInteger() != 2) + return g_macX86; + + return nullptr; + } }; @@ -55,6 +70,17 @@ public: { return false; } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + auto machoPlatform = metadata->Get("machoplatform"); + if (!machoPlatform || !machoPlatform->IsUnsignedInteger()) + return nullptr; + if (machoPlatform->GetUnsignedInteger() != 2) + return g_macX64; + + return nullptr; + } }; @@ -79,6 +105,17 @@ public: { return false; } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + auto machoPlatform = metadata->Get("machoplatform"); + if (!machoPlatform || !machoPlatform->IsUnsignedInteger()) + return nullptr; + if (machoPlatform->GetUnsignedInteger() != 2) + return g_macArmv7; + + return nullptr; + } }; @@ -103,6 +140,86 @@ public: { return false; } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + auto machoPlatform = metadata->Get("machoplatform"); + if (!machoPlatform || !machoPlatform->IsUnsignedInteger()) + return nullptr; + if (machoPlatform->GetUnsignedInteger() != 2) + return g_macArm64; + + return nullptr; + } +}; + + +class IOSArmv7Platform: public Platform +{ +public: + IOSArmv7Platform(Architecture* arch, const std::string& name): Platform(arch, name) + { + Ref<CallingConvention> cc; + + cc = arch->GetCallingConventionByName("cdecl"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + } + + virtual bool GetFallbackEnabled() override + { + return false; + } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + auto machoPlatform = metadata->Get("machoplatform"); + if (!machoPlatform || !machoPlatform->IsUnsignedInteger()) + return nullptr; + if (machoPlatform->GetUnsignedInteger() == 2) + return g_iosArmv7; + + return nullptr; + } +}; + +class IOSArm64Platform: public Platform +{ +public: + IOSArm64Platform(Architecture* arch): Platform(arch, "ios-aarch64") + { + Ref<CallingConvention> cc; + + cc = arch->GetCallingConventionByName("apple-arm64"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + } + + virtual bool GetFallbackEnabled() override + { + return false; + } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + auto machoPlatform = metadata->Get("machoplatform"); + if (!machoPlatform || !machoPlatform->IsUnsignedInteger()) + return nullptr; + if (machoPlatform->GetUnsignedInteger() == 2) + return g_iosArm64; + + return nullptr; + } }; @@ -126,50 +243,55 @@ extern "C" BINARYNINJAPLUGIN bool CorePluginInit() #endif { + auto viewType = BinaryViewType::GetByName("Mach-O"); Ref<Architecture> x86 = Architecture::GetByName("x86"); if (x86) { - Ref<Platform> platform; - - platform = new MacX86Platform(x86); - Platform::Register("mac", platform); - BinaryViewType::RegisterPlatform("Mach-O", 0, x86, platform); + g_macX86 = new MacX86Platform(x86); + Platform::Register("mac", g_macX86); + viewType->RegisterPlatformRecognizer(7, LittleEndian, MacX86Platform::Recognize); } Ref<Architecture> x64 = Architecture::GetByName("x86_64"); if (x64) { - Ref<Platform> platform; - - platform = new MacX64Platform(x64); - Platform::Register("mac", platform); - BinaryViewType::RegisterPlatform("Mach-O", 0, x64, platform); + g_macX64 = new MacX64Platform(x64); + Platform::Register("mac", g_macX64); + viewType->RegisterPlatformRecognizer(0x01000007, LittleEndian, MacX64Platform::Recognize); } Ref<Architecture> armv7 = Architecture::GetByName("armv7"); Ref<Architecture> thumb2 = Architecture::GetByName("thumb2"); if (armv7 && thumb2) { - Ref<Platform> armPlatform, thumbPlatform; - - armPlatform = new MacArmv7Platform(armv7, "mac-armv7"); - thumbPlatform = new MacArmv7Platform(thumb2, "mac-thumb2"); - armPlatform->AddRelatedPlatform(thumb2, thumbPlatform); - thumbPlatform->AddRelatedPlatform(armv7, armPlatform); - Platform::Register("mac", armPlatform); - Platform::Register("mac", thumbPlatform); - BinaryViewType::RegisterPlatform("Mach-O", 0, armv7, armPlatform); + g_macArmv7 = new MacArmv7Platform(armv7, "mac-armv7"); + g_macThumb2 = new MacArmv7Platform(thumb2, "mac-thumb2"); + g_iosArmv7 = new IOSArmv7Platform(armv7, "ios-armv7"); + g_iosThumb2 = new IOSArmv7Platform(thumb2, "ios-thumb2"); + g_macArmv7->AddRelatedPlatform(thumb2, g_macThumb2); + g_macThumb2->AddRelatedPlatform(armv7, g_macArmv7); + g_iosArmv7->AddRelatedPlatform(thumb2, g_iosThumb2); + g_iosThumb2->AddRelatedPlatform(armv7, g_iosArmv7); + Platform::Register("mac", g_macArmv7); + Platform::Register("ios", g_iosArmv7); + Platform::Register("mac", g_macThumb2); + Platform::Register("ios", g_iosThumb2); + viewType->RegisterPlatformRecognizer(0xc, LittleEndian, MacArmv7Platform::Recognize); + viewType->RegisterPlatformRecognizer(0xc, LittleEndian, IOSArmv7Platform::Recognize); } Ref<Architecture> arm64 = Architecture::GetByName("aarch64"); if (arm64) { - Ref<Platform> platform; - - platform = new MacArm64Platform(arm64); - Platform::Register("mac", platform); - BinaryViewType::RegisterPlatform("Mach-O", 9, arm64, platform); - BinaryViewType::RegisterPlatform("Mach-O", 0, arm64, platform); + g_macArm64 = new MacArm64Platform(arm64); + g_iosArm64 = new IOSArm64Platform(arm64); + Platform::Register("mac", g_macArm64); + Platform::Register("ios", g_iosArm64); + viewType->RegisterPlatformRecognizer(0, LittleEndian, MacArm64Platform::Recognize); + viewType->RegisterPlatformRecognizer(0x0100000c, LittleEndian, MacArm64Platform::Recognize); + viewType->RegisterPlatformRecognizer(0x0200000c, LittleEndian, MacArm64Platform::Recognize); + viewType->RegisterPlatformRecognizer(0, LittleEndian, IOSArm64Platform::Recognize); + viewType->RegisterPlatformRecognizer(0x0100000c, LittleEndian, IOSArm64Platform::Recognize); } return true; diff --git a/view/macho/machoview.cpp b/view/macho/machoview.cpp index 257f57a6..ef5b1c3b 100644 --- a/view/macho/machoview.cpp +++ b/view/macho/machoview.cpp @@ -138,9 +138,7 @@ static string BuildToolVersionToString(uint32_t version) uint32_t update = version & 0xff; stringstream ss; - ss << major << "." << minor; - if (update) - ss << "." << update; + ss << major << "." << minor << "." << update; return ss.str(); } @@ -802,11 +800,14 @@ MachOHeader MachoView::HeaderForAddress(BinaryView* data, uint64_t address, bool case LC_LOAD_DYLIB: { uint32_t offset = reader.Read32(); + reader.Read32(); // timestamp + uint32_t currentVersion = reader.Read32(); if (offset < nextOffset) { reader.Seek(curOffset + offset); string libname = reader.ReadCString(); - header.dylibs.push_back(libname); + auto version = BuildToolVersionToString(currentVersion); + header.dylibs.push_back({libname, version}); } } break; @@ -1926,17 +1927,19 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ { vector<Ref<Metadata>> libraries; vector<Ref<Metadata>> libraryFound; - for (auto& libName : header.dylibs) + for (auto& [libName, libVersion] : header.dylibs) { if (!GetExternalLibrary(libName)) { AddExternalLibrary(libName, {}, true); } libraries.push_back(new Metadata(string(libName))); - Ref<TypeLibrary> typeLib = GetTypeLibrary(libName); + // Compose exact name with {install_name}.{platform}.{version} + std::string libNameExact = fmt::format("{}.{}.{}", libName, GetDefaultPlatform()->GetName(), libVersion); + Ref<TypeLibrary> typeLib = GetTypeLibrary(libNameExact); if (!typeLib) { - vector<Ref<TypeLibrary>> typeLibs = platform->GetTypeLibrariesByName(libName); + vector<Ref<TypeLibrary>> typeLibs = GetDefaultPlatform()->GetTypeLibrariesByName(libNameExact); if (typeLibs.size()) { typeLib = typeLibs[0]; @@ -1946,6 +1949,22 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ libName.c_str(), typeLib->GetName().c_str(), typeLib->GetGuid().c_str()); } } + if (!typeLib) + { + typeLib = GetTypeLibrary(libName); + if (!typeLib) + { + vector<Ref<TypeLibrary>> typeLibs = GetDefaultPlatform()->GetTypeLibrariesByName(libName); + if (typeLibs.size()) + { + typeLib = typeLibs[0]; + AddTypeLibrary(typeLib); + + m_logger->LogDebug("mach-o: adding type library for '%s': %s (%s)", + libName.c_str(), typeLib->GetName().c_str(), typeLib->GetGuid().c_str()); + } + } + } if (typeLib) libraryFound.push_back(new Metadata(typeLib->GetName())); @@ -2344,8 +2363,6 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ Ref<Symbol> MachoView::DefineMachoSymbol( BNSymbolType type, const string& name, uint64_t addr, BNSymbolBinding binding, bool deferred) { - Ref<Type> symbolTypeRef; - // If name is empty, symbol is not valid if (name.size() == 0) return nullptr; @@ -2375,17 +2392,19 @@ Ref<Symbol> MachoView::DefineMachoSymbol( return nullptr; } + Ref<Type> symbolTypeRef; + if ((type == ExternalSymbol) || (type == ImportAddressSymbol) || (type == ImportedDataSymbol)) { QualifiedName n(name); - // TODO - Ref<TypeLibrary> appliedLib = nullptr; + Ref<TypeLibrary> appliedLib; symbolTypeRef = ImportTypeLibraryObject(appliedLib, n); if (symbolTypeRef) { m_logger->LogDebug("mach-o: type Library '%s' found hit for '%s'", appliedLib->GetName().c_str(), name.c_str()); RecordImportedObjectLibrary(GetDefaultPlatform(), addr, appliedLib, n); } + } auto process = [=]() { @@ -3785,11 +3804,50 @@ uint64_t MachoViewType::ParseHeaders(BinaryView* data, uint64_t imageOffset, mac errorMsg = "invalid file class"; return 0; } + uint64_t loadCommandStart = reader.GetOffset(); + + uint32_t cmd; + uint32_t cmdsize; + MachoPlatform machoPlat = MachoPlatform::MACHO_PLATFORM_MACOS; // Default to macOS. + // Quickly determine the OS from commands. + for (uint32_t i = 0; i < ident.ncmds; i++) + { + cmd = reader.Read32(); + cmdsize = reader.Read32(); + if (cmd == LC_BUILD_VERSION) + { + machoPlat = MachoPlatform(reader.Read32()); + break; + } + else if (cmd == LC_VERSION_MIN_MACOSX) + { + machoPlat = MachoPlatform(1); + break; + } + else if (cmd == LC_VERSION_MIN_IPHONEOS) + { + machoPlat = MachoPlatform(2); + break; + } + else if (cmd == _LC_VERSION_MIN_TVOS) + { + machoPlat = MachoPlatform(3); + break; + } + else if (cmd == LC_VERSION_MIN_WATCHOS) + { + machoPlat = MachoPlatform(4); + break; + } + + reader.SeekRelative(cmdsize - 8); + } map<string, Ref<Metadata>> metadataMap = { {"cputype", new Metadata((uint64_t) ident.cputype)}, {"cpusubtype", new Metadata((uint64_t) ident.cpusubtype)}, {"flags", new Metadata((uint64_t) ident.flags)}, + {"machoplatform", new Metadata((uint64_t) machoPlat)}, }; Ref<Metadata> metadata = new Metadata(metadataMap); @@ -3810,7 +3868,7 @@ uint64_t MachoViewType::ParseHeaders(BinaryView* data, uint64_t imageOffset, mac *arch = g_machoViewType->GetArchitecture(ident.cputype, endianness); } - return reader.GetOffset(); + return loadCommandStart; } diff --git a/view/macho/machoview.h b/view/macho/machoview.h index 4bf37ef0..6a5e80ae 100644 --- a/view/macho/machoview.h +++ b/view/macho/machoview.h @@ -1285,7 +1285,7 @@ namespace BinaryNinja std::vector<section_64> symbolStubSections; std::vector<section_64> symbolPointerSections; - std::vector<std::string> dylibs; + std::vector<std::pair<std::string, std::string>> dylibs; build_version_command buildVersion; std::vector<build_tool_version> buildToolVersions; |
