diff --git a/view/macho/machoview.cpp b/view/macho/machoview.cpp index a9a070c0a..78798f451 100644 --- a/view/macho/machoview.cpp +++ b/view/macho/machoview.cpp @@ -4,6 +4,7 @@ #include "fatmachoview.h" #include "lowlevelilinstruction.h" #include "rapidjsonwrapper.h" +#include "universaltransform.h" #include "universalview.h" #include @@ -1816,7 +1817,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ return true; bool is64Bit; - string archName = UniversalViewType::ArchitectureToString(m_archId, 0, is64Bit); + string archName = UniversalTransform::ArchitectureToString(m_archId, 0, is64Bit); if (!archName.empty()) { #ifdef DEMO_EDITION @@ -3868,6 +3869,7 @@ extern "C" InitMachoViewType(); InitFatMachoViewType(); InitUniversalViewType(); + InitUniversalTransform(); return true; } } diff --git a/view/macho/universaltransform.cpp b/view/macho/universaltransform.cpp new file mode 100644 index 000000000..5b8dddef4 --- /dev/null +++ b/view/macho/universaltransform.cpp @@ -0,0 +1,365 @@ +#include "universaltransform.h" +#include "machoview.h" +#include + +using namespace BinaryNinja; +using namespace std; + + +const map, string>& UniversalTransform::GetArchitectures() +{ + static map, string> g_cpuArchNames = + { + {{MACHO_CPU_TYPE_VAX, 0}, "vax"}, + {{MACHO_CPU_TYPE_MC680x0, 0}, "mc680x0"}, + {{MACHO_CPU_TYPE_X86, 0}, "x86"}, + {{MACHO_CPU_TYPE_X86, MACHO_CPU_SUBTYPE_X86_ALL}, "x86"}, + {{MACHO_CPU_TYPE_X86, MACHO_CPU_SUBTYPE_X86_ARCH1}, "x86 (Arch1)"}, + {{MACHO_CPU_TYPE_X86_64, 0}, "x86_64"}, + {{MACHO_CPU_TYPE_X86_64, MACHO_CPU_SUBTYPE_X86_64_ALL}, "x86_64"}, + {{MACHO_CPU_TYPE_X86_64, MACHO_CPU_SUBTYPE_X86_64_H}, "x86_64 (Haswell)"}, + {{MACHO_CPU_TYPE_MIPS, 0}, "mips"}, + {{MACHO_CPU_TYPE_MC98000, 0}, "mc98000"}, + {{MACHO_CPU_TYPE_HPPA, 0}, "hppa"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_ALL}, "arm"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V4T}, "armv4t"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V6}, "armv6"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V5TEJ}, "armv5tej"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_XSCALE}, "arm (XScale)"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7}, "armv7"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7F}, "armv7f"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7S}, "armv7s"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7K}, "armv7k"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V8}, "armv8"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V6M}, "armv6m"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7M}, "armv7m"}, + {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7EM}, "armv7em"}, + {{MACHO_CPU_TYPE_ARM64, MACHO_CPU_SUBTYPE_ARM64_ALL}, "arm64"}, + {{MACHO_CPU_TYPE_ARM64, MACHO_CPU_SUBTYPE_ARM64_V8}, "arm64v8"}, + {{MACHO_CPU_TYPE_ARM64, MACHO_CPU_SUBTYPE_ARM64E}, "arm64e"}, + {{MACHO_CPU_TYPE_ARM64_32, MACHO_CPU_SUBTYPE_ARM64_32_ALL}, "arm64_32"}, + {{MACHO_CPU_TYPE_ARM64_32, MACHO_CPU_SUBTYPE_ARM64_32_V8}, "arm64_32v8"}, + {{MACHO_CPU_TYPE_MC88000, 0}, "mc88000"}, + {{MACHO_CPU_TYPE_SPARC, 0}, "sparc"}, + {{MACHO_CPU_TYPE_I860, 0}, "i860"}, + {{MACHO_CPU_TYPE_ALPHA, 0}, "alpha"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_ALL}, "ppc"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_601}, "ppc601"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_602}, "ppc602"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_603}, "ppc603"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_603e}, "ppc603e"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_603ev}, "ppc603ev"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_604}, "ppc604"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_604e}, "ppc604e"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_620}, "ppc620"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_750}, "ppc750"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_7400}, "ppc7400"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_7450}, "ppc7450"}, + {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_970}, "ppc970"}, + {{MACHO_CPU_TYPE_POWERPC64, 0}, "ppc64"} + }; + + return g_cpuArchNames; +} + + +string UniversalTransform::ArchitectureToString(cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool& is64Bit) +{ + const map, string>& cpuArchNames = UniversalTransform::GetArchitectures(); + + switch(cpuType) + { + case MACHO_CPU_TYPE_X86_64: + case MACHO_CPU_TYPE_ARM64: + case MACHO_CPU_TYPE_ARM64_32: + case MACHO_CPU_TYPE_POWERPC64: + is64Bit = true; + break; + default: + is64Bit = false; + break; + } + + auto itr = cpuArchNames.find({cpuType, cpuSubType}); + if (itr != cpuArchNames.end()) + return itr->second; + + itr = cpuArchNames.find({cpuType, 0}); + if (itr != cpuArchNames.end()) + return itr->second; + + return "Unknown"; +} + + +bool UniversalTransform::ParseHeaders(Ref data, FatHeader& fatHeader, vector& fatArchEntries, bool& isFat64, string& errorMsg) +{ + if (data->GetLength() < 8) + { + errorMsg = "Universal (Fat Mach-O): file too small"; + return false; + } + + uint8_t header[8]; + if (data->Read(header, 0, 8) < 8) + { + errorMsg = "Universal (Fat Mach-O): failed to read header"; + return false; + } + + uint32_t magic = ToBE32(*(uint32_t*)header); + if ((magic != FAT_MAGIC) && (magic != FAT_MAGIC_64)) + { + errorMsg = "Universal (Fat Mach-O): invalid signature"; + return false; + } + + BinaryReader reader(data); + reader.SetEndianness(BigEndian); + fatHeader.magic = reader.Read32(); + fatHeader.nfat_arch = reader.Read32(); + + isFat64 = (fatHeader.magic == FAT_MAGIC_64); + size_t requiredFatHeaderSize = fatHeader.nfat_arch * (isFat64 ? 32 : 20) + 8; + if (requiredFatHeaderSize > data->GetLength()) + { + errorMsg = "Universal (Fat Mach-O): header truncated"; + return false; + } + + for (size_t i = 0; i < fatHeader.nfat_arch; i++) + { + FatArch64 fatArch; + if (isFat64) + { + fatArch.cputype = reader.Read32(); + fatArch.cpusubtype = reader.Read32(); + fatArch.offset = reader.Read64(); + fatArch.size = reader.Read64(); + fatArch.align = reader.Read32(); + fatArch.reserved = reader.Read32(); + } + else + { + fatArch.cputype = reader.Read32(); + fatArch.cpusubtype = reader.Read32(); + fatArch.offset = reader.Read32(); + fatArch.size = reader.Read32(); + fatArch.align = reader.Read32(); + fatArch.reserved = 0; + } + + // Mask away cpu subtype capability bits + fatArch.cpusubtype &= ~MACHO_CPU_SUBTYPE_MASK; + fatArchEntries.push_back(fatArch); + } + + return true; +} + + +UniversalTransform::UniversalTransform() : + Transform(DecodeTransform, TransformCapabilities(TransformSupportsDetection | TransformSupportsContext), "Universal", "Universal (Fat Mach-O)", "Container") +{ +} + + +bool UniversalTransform::Decode(const DataBuffer& input, DataBuffer& output, const map& params) +{ + // Create a temporary BinaryView for parsing + auto fileMetadata = new FileMetadata(); + auto rawView = new BinaryData(fileMetadata, input); + + FatHeader fatHeader; + vector fatArchEntries; + bool isFat64; + string errorMsg; + + if (!ParseHeaders(rawView, fatHeader, fatArchEntries, isFat64, errorMsg)) + { + LogError("Universal: %s", errorMsg.c_str()); + return false; + } + + if (fatArchEntries.empty()) + { + LogError("Universal: no architectures found"); + return false; + } + + // Look for architecture parameter + string targetArch; + if (auto archParam = params.find("architecture"); archParam != params.end()) + targetArch = string(reinterpret_cast(archParam->second.GetData()), archParam->second.GetLength()); + + // If no target specified, extract first architecture + const FatArch64* targetEntry = nullptr; + if (targetArch.empty()) + { + targetEntry = &fatArchEntries[0]; + } + else + { + // Find matching architecture + for (const auto& entry : fatArchEntries) + { + bool is64Bit; + string archName = ArchitectureToString(entry.cputype, entry.cpusubtype, is64Bit); + if (archName == targetArch) + { + targetEntry = &entry; + break; + } + } + + if (!targetEntry) + { + LogError("Universal: architecture '%s' not found", targetArch.c_str()); + return false; + } + } + + // Validate bounds + if (targetEntry->offset > input.GetLength() || targetEntry->size > input.GetLength() - targetEntry->offset) + { + LogError("Universal: architecture data extends beyond file bounds"); + return false; + } + + // Extract the Mach-O slice + output = DataBuffer(static_cast(input.GetData()) + targetEntry->offset, static_cast(targetEntry->size)); + return true; +} + + +bool UniversalTransform::DecodeWithContext(Ref context, const map& params) +{ + if (!context || !context->GetInput()) + return false; + + Ref input = context->GetInput(); + FatHeader fatHeader; + vector fatArchEntries; + bool isFat64; + string errorMsg; + + if (!ParseHeaders(input, fatHeader, fatArchEntries, isFat64, errorMsg)) + { + LogError("Universal: %s", errorMsg.c_str()); + return false; + } + + if (fatArchEntries.empty()) + { + LogError("Universal: no architectures found"); + return false; + } + + // Phase 1: Discovery - enumerate available architectures + if (!context->HasAvailableFiles()) + { + vector architectures; + for (const auto& entry : fatArchEntries) + { + bool is64Bit; + string archName = ArchitectureToString(entry.cputype, entry.cpusubtype, is64Bit); + architectures.push_back(archName); + } + + if (!context->IsInteractive()) + { + vector archPref = context->GetSettings()->Get>("files.universal.architecturePreference"); + if (auto result = find_first_of(archPref.begin(), archPref.end(), architectures.begin(), architectures.end()); result != archPref.end()) + { + // Filter to preferred architecture to support container auto-open policy + size_t archIndex = find(architectures.begin(), architectures.end(), *result) - architectures.begin(); + context->SetAvailableFiles({architectures[archIndex]}); + return false; + } + } + + context->SetAvailableFiles(architectures); + return false; + } + + // Phase 2: Extraction - extract requested architectures + vector requestedFiles = context->GetRequestedFiles(); + if (requestedFiles.empty()) + return false; + + // Build a map of architecture names to entries + map archMap; + for (const auto& entry : fatArchEntries) + { + bool is64Bit; + string archName = ArchitectureToString(entry.cputype, entry.cpusubtype, is64Bit); + archMap[archName] = &entry; + } + + bool complete = true; + for (const string& requestedArch : requestedFiles) + { + auto itr = archMap.find(requestedArch); + if (itr == archMap.end()) + { + string msg = "Universal: requested architecture '" + requestedArch + "' not found"; + context->SetChild(DataBuffer(), requestedArch, TransformFailure, msg); + complete = false; + continue; + } + + const FatArch64* entry = itr->second; + + // Validate bounds + if (entry->offset > input->GetLength() || entry->size > input->GetLength() - entry->offset) + { + string msg = "Universal: architecture data extends beyond file bounds"; + context->SetChild(DataBuffer(), requestedArch, TransformFailure, msg); + complete = false; + continue; + } + + // Extract the Mach-O slice + DataBuffer sliceData; + sliceData.SetSize(static_cast(entry->size)); + if (input->Read(sliceData.GetData(), entry->offset, static_cast(entry->size)) < entry->size) + { + string msg = "Universal: failed to read architecture data"; + context->SetChild(DataBuffer(), requestedArch, TransformFailure, msg); + complete = false; + continue; + } + + // Create child context with the extracted slice + context->SetChild(sliceData, requestedArch, TransformSuccess, "", true); + } + + return complete; +} + + +bool UniversalTransform::Encode(const DataBuffer& input, DataBuffer& output, const map& params) +{ + return false; +} + + +bool UniversalTransform::CanDecode(Ref input) const +{ + if (input->GetLength() < 4) + return false; + + uint8_t magic[4]; + if (input->Read(magic, 0, 4) < 4) + return false; + + uint32_t magicValue = ToBE32(*(uint32_t*)magic); + return (magicValue == FAT_MAGIC) || (magicValue == FAT_MAGIC_64); +} + + +void BinaryNinja::InitUniversalTransform() +{ + static UniversalTransform universalXform; + Transform::Register(&universalXform); +} diff --git a/view/macho/universaltransform.h b/view/macho/universaltransform.h new file mode 100644 index 000000000..2d54d65ef --- /dev/null +++ b/view/macho/universaltransform.h @@ -0,0 +1,24 @@ +#pragma once + +#include "binaryninjaapi.h" +#include "machoview.h" + +namespace BinaryNinja +{ + void InitUniversalTransform(); + + class UniversalTransform : public Transform + { + public: + static const std::map, std::string>& GetArchitectures(); + static std::string ArchitectureToString(cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool& is64Bit); + static bool ParseHeaders(Ref data, FatHeader& fatHeader, std::vector& fatArchEntries, bool& isFat64, std::string& errorMsg); + + UniversalTransform(); + + virtual bool Decode(const DataBuffer& input, DataBuffer& output, const std::map& params) override; + virtual bool DecodeWithContext(Ref context, const std::map& params) override; + virtual bool Encode(const DataBuffer& input, DataBuffer& output, const std::map& params) override; + virtual bool CanDecode(Ref input) const override; + }; +} diff --git a/view/macho/universalview.cpp b/view/macho/universalview.cpp index d11630a32..4a35f0cd2 100644 --- a/view/macho/universalview.cpp +++ b/view/macho/universalview.cpp @@ -6,6 +6,7 @@ #include #endif #include "universalview.h" +#include "universaltransform.h" #include "machoview.h" #include "rapidjsonwrapper.h" @@ -16,92 +17,6 @@ using namespace std; static UniversalViewType* g_universalViewType = nullptr; -const map, string>& UniversalViewType::GetArchitectures() -{ - static map, string> g_cpuArchNames = - { - {{MACHO_CPU_TYPE_VAX, 0}, "vax"}, - {{MACHO_CPU_TYPE_MC680x0, 0}, "mc680x0"}, - {{MACHO_CPU_TYPE_X86, 0}, "x86"}, - {{MACHO_CPU_TYPE_X86, MACHO_CPU_SUBTYPE_X86_ALL}, "x86"}, - {{MACHO_CPU_TYPE_X86, MACHO_CPU_SUBTYPE_X86_ARCH1}, "x86 (Arch1)"}, - {{MACHO_CPU_TYPE_X86_64, 0}, "x86_64"}, - {{MACHO_CPU_TYPE_X86_64, MACHO_CPU_SUBTYPE_X86_64_ALL}, "x86_64"}, - {{MACHO_CPU_TYPE_X86_64, MACHO_CPU_SUBTYPE_X86_64_H}, "x86_64 (Haswell)"}, - {{MACHO_CPU_TYPE_MIPS, 0}, "mips"}, - {{MACHO_CPU_TYPE_MC98000, 0}, "mc98000"}, - {{MACHO_CPU_TYPE_HPPA, 0}, "hppa"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_ALL}, "arm"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V4T}, "armv4t"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V6}, "armv6"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V5TEJ}, "armv5tej"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_XSCALE}, "arm (XScale)"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7}, "armv7"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7F}, "armv7f"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7S}, "armv7s"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7K}, "armv7k"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V8}, "armv8"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V6M}, "armv6m"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7M}, "armv7m"}, - {{MACHO_CPU_TYPE_ARM, MACHO_CPU_SUBTYPE_ARM_V7EM}, "armv7em"}, - {{MACHO_CPU_TYPE_ARM64, MACHO_CPU_SUBTYPE_ARM64_ALL}, "arm64"}, - {{MACHO_CPU_TYPE_ARM64, MACHO_CPU_SUBTYPE_ARM64_V8}, "arm64v8"}, - {{MACHO_CPU_TYPE_ARM64, MACHO_CPU_SUBTYPE_ARM64E}, "arm64e"}, - {{MACHO_CPU_TYPE_ARM64_32, MACHO_CPU_SUBTYPE_ARM64_32_ALL}, "arm64_32"}, - {{MACHO_CPU_TYPE_ARM64_32, MACHO_CPU_SUBTYPE_ARM64_32_V8}, "arm64_32v8"}, - {{MACHO_CPU_TYPE_MC88000, 0}, "mc88000"}, - {{MACHO_CPU_TYPE_SPARC, 0}, "sparc"}, - {{MACHO_CPU_TYPE_I860, 0}, "i860"}, - {{MACHO_CPU_TYPE_ALPHA, 0}, "alpha"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_ALL}, "ppc"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_601}, "ppc601"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_602}, "ppc602"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_603}, "ppc603"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_603e}, "ppc603e"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_603ev}, "ppc603ev"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_604}, "ppc604"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_604e}, "ppc604e"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_620}, "ppc620"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_750}, "ppc750"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_7400}, "ppc7400"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_7450}, "ppc7450"}, - {{MACHO_CPU_TYPE_POWERPC, MACHO_CPU_SUBTYPE_POWERPC_970}, "ppc970"}, - {{MACHO_CPU_TYPE_POWERPC64, 0}, "ppc64"} - }; - - return g_cpuArchNames; -} - - -string UniversalViewType::ArchitectureToString(cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool& is64Bit) -{ - const map, string>& cpuArchNames = GetArchitectures(); - - switch(cpuType) - { - case MACHO_CPU_TYPE_X86_64: - case MACHO_CPU_TYPE_ARM64: - case MACHO_CPU_TYPE_ARM64_32: - case MACHO_CPU_TYPE_POWERPC64: - is64Bit = true; - break; - default: - is64Bit = false; - break; - } - - auto itr = cpuArchNames.find({cpuType, cpuSubType}); - if (itr != cpuArchNames.end()) - return itr->second; - - itr = cpuArchNames.find({cpuType, 0}); - if (itr != cpuArchNames.end()) - return itr->second; - - return "Unknown"; -} - - void BinaryNinja::InitUniversalViewType() { static UniversalViewType type; @@ -119,7 +34,7 @@ void BinaryNinja::InitUniversalViewType() "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] })"); - const map, string>& cpuArchNames = UniversalViewType::GetArchitectures(); + const map, string>& cpuArchNames = UniversalTransform::GetArchitectures(); set names; for (const auto& [key, name] : cpuArchNames) names.insert(name); @@ -157,52 +72,7 @@ bool UniversalViewType::IsTypeValidForData(BinaryView* data) bool UniversalViewType::ParseHeaders(BinaryView* data, FatHeader& fatHeader, vector& fatArchEntries, bool& isFat64, string& errorMsg) { - if (!IsTypeValidForData(data)) - { - errorMsg = "Universal (Fat Mach-O): invalid signature"; - return false; - } - - BinaryReader reader(data); - reader.SetEndianness(BigEndian); - fatHeader.magic = reader.Read32(); - fatHeader.nfat_arch = reader.Read32(); - - isFat64 = (fatHeader.magic == FAT_MAGIC_64); - size_t requiredFatHeaderSize = fatHeader.nfat_arch * (isFat64 ? 32 : 20) + 8; - if (requiredFatHeaderSize > data->GetLength()) - { - errorMsg = "Universal (Fat Mach-O): header truncated"; - return false; - } - - for (size_t i = 0; i < fatHeader.nfat_arch; i++) - { - FatArch64 fatArch; - if (isFat64) - { - fatArch.cputype = reader.Read32(); - fatArch.cpusubtype = reader.Read32(); - fatArch.offset = reader.Read64(); - fatArch.size = reader.Read64(); - fatArch.align = reader.Read32(); - fatArch.reserved = reader.Read32(); - } - else - { - fatArch.cputype = reader.Read32(); - fatArch.cpusubtype = reader.Read32(); - fatArch.offset = reader.Read32(); - fatArch.size = reader.Read32(); - fatArch.align = reader.Read32(); - } - - // Mask away cpu subtype capability bits - fatArch.cpusubtype &= ~MACHO_CPU_SUBTYPE_MASK; - fatArchEntries.push_back(fatArch); - } - - return true; + return UniversalTransform::ParseHeaders(data, fatHeader, fatArchEntries, isFat64, errorMsg); } @@ -248,7 +118,7 @@ Ref UniversalViewType::GetLoadSettingsForData(BinaryView* data) { rapidjson::Value result(rapidjson::kObjectType); bool is64Bit; - string archDesc = ArchitectureToString(entry.cputype, entry.cpusubtype, is64Bit); + string archDesc = UniversalTransform::ArchitectureToString(entry.cputype, entry.cpusubtype, is64Bit); string bitDesc = is64Bit ? "64-bit" : "32-bit"; result.AddMember("id", count++, entries.GetAllocator()); result.AddMember("architecture", archDesc, entries.GetAllocator()); diff --git a/view/macho/universalview.h b/view/macho/universalview.h index aaf483cc3..bccea6a12 100644 --- a/view/macho/universalview.h +++ b/view/macho/universalview.h @@ -16,9 +16,6 @@ namespace BinaryNinja class UniversalViewType: public BinaryViewType { public: - static const std::map, std::string>& GetArchitectures(); - static std::string ArchitectureToString(cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool& is64Bit); - UniversalViewType(): BinaryViewType("Universal", "Universal") { } virtual Ref Create(BinaryView* data) override; virtual bool IsTypeValidForData(BinaryView* data) override;