// // Created by kat on 5/23/23. // /* * * */ #include "KCView.h" #include "view/macho/machoview.h" #include "KernelCache.h" [[maybe_unused]] KCViewType* g_kcViewType; #define COMPRESSION_DEBUG 1 using namespace BinaryNinja; KCView::KCView(const std::string& typeName, BinaryView* data, bool parseOnly) : BinaryView(typeName, data->GetFile(), data), m_parseOnly(parseOnly) { CreateLogger("KernelCache"); } KCView::~KCView() { } enum KCPlatform { KCPlatformMacOS = 1, KCPlatformiOS = 2, KCPlatformTVOS = 3, KCPlatformWatchOS = 4, KCPlatformBridgeOS = 5, // T1/T2 APL1023/T8012, this is your touchbar/touchid in intel macs. Similar to watchOS. // KCPlatformMacCatalyst = 6, KCPlatformiOSSimulator = 7, KCPlatformTVOSSimulator = 8, KCPlatformWatchOSSimulator = 9, KCPlatformVisionOS = 11, // Apple Vision Pro KCPlatformVisionOSSimulator = 12 // Apple Vision Pro Simulator }; bool KCView::Init() { BinaryReader reader(GetParentView()); reader.Seek(0x4); uint32_t cpuType = reader.Read32(); reader.Seek(0x10); uint64_t ncmds = reader.Read32(); uint64_t sizeofcmds = reader.Read32(); // get __TEXT seg offset uint64_t textSegOffset = 0; uint64_t anyFilesetHeaderFileOffset = 0; uint64_t offset = 0x20; for (uint64_t i = 0; i < ncmds; i++) { reader.Seek(offset); uint64_t cmd = reader.Read32(); uint64_t cmdsize = reader.Read32(); if (textSegOffset == 0 && cmd == LC_SEGMENT_64) { uint64_t segname = reader.Read64(); reader.Read64(); uint64_t vmaddr = reader.Read64(); if (segname == 0x545845545f5f) // __TEXT { textSegOffset = vmaddr; } } if (anyFilesetHeaderFileOffset == 0 && cmd == LC_FILESET_ENTRY) { reader.SeekRelative(8); anyFilesetHeaderFileOffset = reader.Read64(); } offset += cmdsize; if (textSegOffset && anyFilesetHeaderFileOffset) break; } Ref platform; Ref architecture; if (anyFilesetHeaderFileOffset) { reader.Seek(anyFilesetHeaderFileOffset); reader.SeekRelative(0x10); uint64_t ncmdsFH = reader.Read32(); reader.Seek(anyFilesetHeaderFileOffset + 0x20); offset = anyFilesetHeaderFileOffset + 0x20; bool foundBuildVersion = false; for (uint64_t i = 0; i < ncmdsFH; i++) { reader.Seek(offset); uint64_t cmd = reader.Read32(); uint64_t cmdsize = reader.Read32(); if (cmd == LC_BUILD_VERSION) { uint32_t platformID = reader.Read32(); std::map> metadataMap = { {"machoplatform", new Metadata((uint64_t) platformID)}, }; Ref metadata = new Metadata(metadataMap); Ref plat = g_kcViewType->RecognizePlatform(cpuType, GetDefaultEndianness(), this, metadata); SetDefaultArchitecture(plat->GetArchitecture()); SetDefaultPlatform(plat); foundBuildVersion = true; } offset += cmdsize; } if (!foundBuildVersion) { LogError("Failed to find LC_BUILD_VERSION in subheader"); SetDefaultArchitecture(Architecture::GetByName("aarch64")); SetDefaultPlatform(Platform::GetByName("macos-kernel-aarch64")); } } else { LogError("MH_FILESET had no subheaders"); return false; } if (textSegOffset == 0) { LogError("Failed to find __TEXT segment"); return false; } // Add Mach-O file header type info EnumerationBuilder cpuTypeBuilder; cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ANY", MACHO_CPU_TYPE_ANY); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_VAX", MACHO_CPU_TYPE_VAX); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC680x0", MACHO_CPU_TYPE_MC680x0); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_X86", MACHO_CPU_TYPE_X86); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_X86_64", MACHO_CPU_TYPE_X86_64); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MIPS", MACHO_CPU_TYPE_MIPS); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC98000", MACHO_CPU_TYPE_MC98000); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_HPPA", MACHO_CPU_TYPE_HPPA); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM", MACHO_CPU_TYPE_ARM); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM64", MACHO_CPU_TYPE_ARM64); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM64_32", MACHO_CPU_TYPE_ARM64_32); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC88000", MACHO_CPU_TYPE_MC88000); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_SPARC", MACHO_CPU_TYPE_SPARC); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_I860", MACHO_CPU_TYPE_I860); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ALPHA", MACHO_CPU_TYPE_ALPHA); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_POWERPC", MACHO_CPU_TYPE_POWERPC); cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_POWERPC64", MACHO_CPU_TYPE_POWERPC64); Ref cpuTypeEnum = cpuTypeBuilder.Finalize(); Ref cpuTypeEnumType = Type::EnumerationType(nullptr, cpuTypeEnum, 4, false); std::string cpuTypeEnumName = "cpu_type_t"; std::string cpuTypeEnumId = Type::GenerateAutoTypeId("macho", cpuTypeEnumName); DefineType(cpuTypeEnumId, cpuTypeEnumName, cpuTypeEnumType); EnumerationBuilder fileTypeBuilder; fileTypeBuilder.AddMemberWithValue("MH_OBJECT", MH_OBJECT); fileTypeBuilder.AddMemberWithValue("MH_EXECUTE", MH_EXECUTE); fileTypeBuilder.AddMemberWithValue("MH_FVMLIB", MH_FVMLIB); fileTypeBuilder.AddMemberWithValue("MH_CORE", MH_CORE); fileTypeBuilder.AddMemberWithValue("MH_PRELOAD", MH_PRELOAD); fileTypeBuilder.AddMemberWithValue("MH_DYLIB", MH_DYLIB); fileTypeBuilder.AddMemberWithValue("MH_DYLINKER", MH_DYLINKER); fileTypeBuilder.AddMemberWithValue("MH_BUNDLE", MH_BUNDLE); fileTypeBuilder.AddMemberWithValue("MH_DYLIB_STUB", MH_DYLIB_STUB); fileTypeBuilder.AddMemberWithValue("MH_DSYM", MH_DSYM); fileTypeBuilder.AddMemberWithValue("MH_KEXT_BUNDLE", MH_KEXT_BUNDLE); fileTypeBuilder.AddMemberWithValue("MH_FILESET", MH_FILESET); Ref fileTypeEnum = fileTypeBuilder.Finalize(); Ref fileTypeEnumType = Type::EnumerationType(nullptr, fileTypeEnum, 4, false); std::string fileTypeEnumName = "file_type_t"; std::string fileTypeEnumId = Type::GenerateAutoTypeId("macho", fileTypeEnumName); DefineType(fileTypeEnumId, fileTypeEnumName, fileTypeEnumType); EnumerationBuilder flagsTypeBuilder; flagsTypeBuilder.AddMemberWithValue("MH_NOUNDEFS", MH_NOUNDEFS); flagsTypeBuilder.AddMemberWithValue("MH_INCRLINK", MH_INCRLINK); flagsTypeBuilder.AddMemberWithValue("MH_DYLDLINK", MH_DYLDLINK); flagsTypeBuilder.AddMemberWithValue("MH_BINDATLOAD", MH_BINDATLOAD); flagsTypeBuilder.AddMemberWithValue("MH_PREBOUND", MH_PREBOUND); flagsTypeBuilder.AddMemberWithValue("MH_SPLIT_SEGS", MH_SPLIT_SEGS); flagsTypeBuilder.AddMemberWithValue("MH_LAZY_INIT", MH_LAZY_INIT); flagsTypeBuilder.AddMemberWithValue("MH_TWOLEVEL", MH_TWOLEVEL); flagsTypeBuilder.AddMemberWithValue("MH_FORCE_FLAT", MH_FORCE_FLAT); flagsTypeBuilder.AddMemberWithValue("MH_NOMULTIDEFS", MH_NOMULTIDEFS); flagsTypeBuilder.AddMemberWithValue("MH_NOFIXPREBINDING", MH_NOFIXPREBINDING); flagsTypeBuilder.AddMemberWithValue("MH_PREBINDABLE", MH_PREBINDABLE); flagsTypeBuilder.AddMemberWithValue("MH_ALLMODSBOUND", MH_ALLMODSBOUND); flagsTypeBuilder.AddMemberWithValue("MH_SUBSECTIONS_VIA_SYMBOLS", MH_SUBSECTIONS_VIA_SYMBOLS); flagsTypeBuilder.AddMemberWithValue("MH_CANONICAL", MH_CANONICAL); flagsTypeBuilder.AddMemberWithValue("MH_WEAK_DEFINES", MH_WEAK_DEFINES); flagsTypeBuilder.AddMemberWithValue("MH_BINDS_TO_WEAK", MH_BINDS_TO_WEAK); flagsTypeBuilder.AddMemberWithValue("MH_ALLOW_STACK_EXECUTION", MH_ALLOW_STACK_EXECUTION); flagsTypeBuilder.AddMemberWithValue("MH_ROOT_SAFE", MH_ROOT_SAFE); flagsTypeBuilder.AddMemberWithValue("MH_SETUID_SAFE", MH_SETUID_SAFE); flagsTypeBuilder.AddMemberWithValue("MH_NO_REEXPORTED_DYLIBS", MH_NO_REEXPORTED_DYLIBS); flagsTypeBuilder.AddMemberWithValue("MH_PIE", MH_PIE); flagsTypeBuilder.AddMemberWithValue("MH_DEAD_STRIPPABLE_DYLIB", MH_DEAD_STRIPPABLE_DYLIB); flagsTypeBuilder.AddMemberWithValue("MH_HAS_TLV_DESCRIPTORS", MH_HAS_TLV_DESCRIPTORS); flagsTypeBuilder.AddMemberWithValue("MH_NO_HEAP_EXECUTION", MH_NO_HEAP_EXECUTION); flagsTypeBuilder.AddMemberWithValue("MH_APP_EXTENSION_SAFE", _MH_APP_EXTENSION_SAFE); flagsTypeBuilder.AddMemberWithValue("MH_NLIST_OUTOFSYNC_WITH_DYLDINFO", _MH_NLIST_OUTOFSYNC_WITH_DYLDINFO); flagsTypeBuilder.AddMemberWithValue("MH_SIM_SUPPORT", _MH_SIM_SUPPORT); flagsTypeBuilder.AddMemberWithValue("MH_DYLIB_IN_CACHE", _MH_DYLIB_IN_CACHE); Ref flagsTypeEnum = flagsTypeBuilder.Finalize(); Ref flagsTypeEnumType = Type::EnumerationType(nullptr, flagsTypeEnum, 4, false); std::string flagsTypeEnumName = "flags_type_t"; std::string flagsTypeEnumId = Type::GenerateAutoTypeId("macho", flagsTypeEnumName); DefineType(flagsTypeEnumId, flagsTypeEnumName, flagsTypeEnumType); StructureBuilder machoHeaderBuilder; machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "magic"); machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("cpu_type_t")), "cputype"); machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "cpusubtype"); machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("file_type_t")), "filetype"); machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "ncmds"); machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeofcmds"); machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("flags_type_t")), "flags"); if (GetAddressSize() == 8) machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "reserved"); Ref machoHeaderStruct = machoHeaderBuilder.Finalize(); QualifiedName headerName = (GetAddressSize() == 8) ? std::string("mach_header_64") : std::string("mach_header"); std::string headerTypeId = Type::GenerateAutoTypeId("macho", headerName); Ref machoHeaderType = Type::StructureType(machoHeaderStruct); DefineType(headerTypeId, headerName, machoHeaderType); EnumerationBuilder cmdTypeBuilder; cmdTypeBuilder.AddMemberWithValue("LC_REQ_DYLD", LC_REQ_DYLD); cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT", LC_SEGMENT); cmdTypeBuilder.AddMemberWithValue("LC_SYMTAB", LC_SYMTAB); cmdTypeBuilder.AddMemberWithValue("LC_SYMSEG", LC_SYMSEG); cmdTypeBuilder.AddMemberWithValue("LC_THREAD", LC_THREAD); cmdTypeBuilder.AddMemberWithValue("LC_UNIXTHREAD", LC_UNIXTHREAD); cmdTypeBuilder.AddMemberWithValue("LC_LOADFVMLIB", LC_LOADFVMLIB); cmdTypeBuilder.AddMemberWithValue("LC_IDFVMLIB", LC_IDFVMLIB); cmdTypeBuilder.AddMemberWithValue("LC_IDENT", LC_IDENT); cmdTypeBuilder.AddMemberWithValue("LC_FVMFILE", LC_FVMFILE); cmdTypeBuilder.AddMemberWithValue("LC_PREPAGE", LC_PREPAGE); cmdTypeBuilder.AddMemberWithValue("LC_DYSYMTAB", LC_DYSYMTAB); cmdTypeBuilder.AddMemberWithValue("LC_LOAD_DYLIB", LC_LOAD_DYLIB); cmdTypeBuilder.AddMemberWithValue("LC_ID_DYLIB", LC_ID_DYLIB); cmdTypeBuilder.AddMemberWithValue("LC_LOAD_DYLINKER", LC_LOAD_DYLINKER); cmdTypeBuilder.AddMemberWithValue("LC_ID_DYLINKER", LC_ID_DYLINKER); cmdTypeBuilder.AddMemberWithValue("LC_PREBOUND_DYLIB", LC_PREBOUND_DYLIB); cmdTypeBuilder.AddMemberWithValue("LC_ROUTINES", LC_ROUTINES); cmdTypeBuilder.AddMemberWithValue("LC_SUB_FRAMEWORK", LC_SUB_FRAMEWORK); cmdTypeBuilder.AddMemberWithValue("LC_SUB_UMBRELLA", LC_SUB_UMBRELLA); cmdTypeBuilder.AddMemberWithValue("LC_SUB_CLIENT", LC_SUB_CLIENT); cmdTypeBuilder.AddMemberWithValue("LC_SUB_LIBRARY", LC_SUB_LIBRARY); cmdTypeBuilder.AddMemberWithValue("LC_TWOLEVEL_HINTS", LC_TWOLEVEL_HINTS); cmdTypeBuilder.AddMemberWithValue("LC_PREBIND_CKSUM", LC_PREBIND_CKSUM); cmdTypeBuilder.AddMemberWithValue("LC_LOAD_WEAK_DYLIB", LC_LOAD_WEAK_DYLIB); // (0x18 | LC_REQ_DYLD) cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT_64", LC_SEGMENT_64); cmdTypeBuilder.AddMemberWithValue("LC_ROUTINES_64", LC_ROUTINES_64); cmdTypeBuilder.AddMemberWithValue("LC_UUID", LC_UUID); cmdTypeBuilder.AddMemberWithValue("LC_RPATH", LC_RPATH); // (0x1c | LC_REQ_DYLD) cmdTypeBuilder.AddMemberWithValue("LC_CODE_SIGNATURE", LC_CODE_SIGNATURE); cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT_SPLIT_INFO", LC_SEGMENT_SPLIT_INFO); cmdTypeBuilder.AddMemberWithValue("LC_REEXPORT_DYLIB", LC_REEXPORT_DYLIB); // (0x1f | LC_REQ_DYLD) cmdTypeBuilder.AddMemberWithValue("LC_LAZY_LOAD_DYLIB", LC_LAZY_LOAD_DYLIB); cmdTypeBuilder.AddMemberWithValue("LC_ENCRYPTION_INFO", LC_ENCRYPTION_INFO); cmdTypeBuilder.AddMemberWithValue("LC_DYLD_INFO", LC_DYLD_INFO); cmdTypeBuilder.AddMemberWithValue("LC_DYLD_INFO_ONLY", LC_DYLD_INFO_ONLY); // (0x22 | LC_REQ_DYLD) cmdTypeBuilder.AddMemberWithValue("LC_LOAD_UPWARD_DYLIB", LC_LOAD_UPWARD_DYLIB); // (0x23 | LC_REQ_DYLD) cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_MACOSX", LC_VERSION_MIN_MACOSX); cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_IPHONEOS", LC_VERSION_MIN_IPHONEOS); cmdTypeBuilder.AddMemberWithValue("LC_FUNCTION_STARTS", LC_FUNCTION_STARTS); cmdTypeBuilder.AddMemberWithValue("LC_DYLD_ENVIRONMENT", LC_DYLD_ENVIRONMENT); cmdTypeBuilder.AddMemberWithValue("LC_MAIN", LC_MAIN); // (0x28 | LC_REQ_DYLD) cmdTypeBuilder.AddMemberWithValue("LC_DATA_IN_CODE", LC_DATA_IN_CODE); cmdTypeBuilder.AddMemberWithValue("LC_SOURCE_VERSION", LC_SOURCE_VERSION); cmdTypeBuilder.AddMemberWithValue("LC_DYLIB_CODE_SIGN_DRS", LC_DYLIB_CODE_SIGN_DRS); cmdTypeBuilder.AddMemberWithValue("LC_ENCRYPTION_INFO_64", _LC_ENCRYPTION_INFO_64); cmdTypeBuilder.AddMemberWithValue("LC_LINKER_OPTION", _LC_LINKER_OPTION); cmdTypeBuilder.AddMemberWithValue("LC_LINKER_OPTIMIZATION_HINT", _LC_LINKER_OPTIMIZATION_HINT); cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_TVOS", _LC_VERSION_MIN_TVOS); cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_WATCHOS", LC_VERSION_MIN_WATCHOS); cmdTypeBuilder.AddMemberWithValue("LC_NOTE", LC_NOTE); cmdTypeBuilder.AddMemberWithValue("LC_BUILD_VERSION", LC_BUILD_VERSION); cmdTypeBuilder.AddMemberWithValue("LC_DYLD_EXPORTS_TRIE", LC_DYLD_EXPORTS_TRIE); cmdTypeBuilder.AddMemberWithValue("LC_DYLD_CHAINED_FIXUPS", LC_DYLD_CHAINED_FIXUPS); cmdTypeBuilder.AddMemberWithValue("LC_FILESET_ENTRY", LC_FILESET_ENTRY); Ref cmdTypeEnum = cmdTypeBuilder.Finalize(); Ref cmdTypeEnumType = Type::EnumerationType(nullptr, cmdTypeEnum, 4, false); std::string cmdTypeEnumName = "load_command_type_t"; std::string cmdTypeEnumId = Type::GenerateAutoTypeId("macho", cmdTypeEnumName); DefineType(cmdTypeEnumId, cmdTypeEnumName, cmdTypeEnumType); StructureBuilder loadCommandBuilder; loadCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); loadCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); Ref loadCommandStruct = loadCommandBuilder.Finalize(); QualifiedName loadCommandName = std::string("load_command"); std::string loadCommandTypeId = Type::GenerateAutoTypeId("macho", loadCommandName); Ref loadCommandType = Type::StructureType(loadCommandStruct); DefineType(loadCommandTypeId, loadCommandName, loadCommandType); EnumerationBuilder protTypeBuilder; protTypeBuilder.AddMemberWithValue("VM_PROT_NONE", MACHO_VM_PROT_NONE); protTypeBuilder.AddMemberWithValue("VM_PROT_READ", MACHO_VM_PROT_READ); protTypeBuilder.AddMemberWithValue("VM_PROT_WRITE", MACHO_VM_PROT_WRITE); protTypeBuilder.AddMemberWithValue("VM_PROT_EXECUTE", MACHO_VM_PROT_EXECUTE); // protTypeBuilder.AddMemberWithValue("VM_PROT_DEFAULT", MACHO_VM_PROT_DEFAULT); // protTypeBuilder.AddMemberWithValue("VM_PROT_ALL", MACHO_VM_PROT_ALL); protTypeBuilder.AddMemberWithValue("VM_PROT_NO_CHANGE", MACHO_VM_PROT_NO_CHANGE); protTypeBuilder.AddMemberWithValue("VM_PROT_COPY_OR_WANTS_COPY", MACHO_VM_PROT_COPY); // protTypeBuilder.AddMemberWithValue("VM_PROT_WANTS_COPY", MACHO_VM_PROT_WANTS_COPY); Ref protTypeEnum = protTypeBuilder.Finalize(); Ref protTypeEnumType = Type::EnumerationType(nullptr, protTypeEnum, 4, false); std::string protTypeEnumName = "vm_prot_t"; std::string protTypeEnumId = Type::GenerateAutoTypeId("macho", protTypeEnumName); DefineType(protTypeEnumId, protTypeEnumName, protTypeEnumType); EnumerationBuilder segFlagsTypeBuilder; segFlagsTypeBuilder.AddMemberWithValue("SG_HIGHVM", SG_HIGHVM); segFlagsTypeBuilder.AddMemberWithValue("SG_FVMLIB", SG_FVMLIB); segFlagsTypeBuilder.AddMemberWithValue("SG_NORELOC", SG_NORELOC); segFlagsTypeBuilder.AddMemberWithValue("SG_PROTECTED_VERSION_1", SG_PROTECTED_VERSION_1); Ref segFlagsTypeEnum = segFlagsTypeBuilder.Finalize(); Ref segFlagsTypeEnumType = Type::EnumerationType(nullptr, segFlagsTypeEnum, 4, false); std::string segFlagsTypeEnumName = "sg_flags_t"; std::string segFlagsTypeEnumId = Type::GenerateAutoTypeId("macho", segFlagsTypeEnumName); DefineType(segFlagsTypeEnumId, segFlagsTypeEnumName, segFlagsTypeEnumType); StructureBuilder loadSegmentCommandBuilder; loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); loadSegmentCommandBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname"); loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "vmaddr"); loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "vmsize"); loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "fileoff"); loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "filesize"); loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "maxprot"); loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "initprot"); loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "nsects"); loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("sg_flags_t")), "flags"); Ref loadSegmentCommandStruct = loadSegmentCommandBuilder.Finalize(); QualifiedName loadSegmentCommandName = std::string("segment_command"); std::string loadSegmentCommandTypeId = Type::GenerateAutoTypeId("macho", loadSegmentCommandName); Ref loadSegmentCommandType = Type::StructureType(loadSegmentCommandStruct); DefineType(loadSegmentCommandTypeId, loadSegmentCommandName, loadSegmentCommandType); StructureBuilder loadSegmentCommand64Builder; loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); loadSegmentCommand64Builder.AddMember(Type::IntegerType(4, false), "cmdsize"); loadSegmentCommand64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname"); loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "vmaddr"); loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "vmsize"); loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "fileoff"); loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "filesize"); loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "maxprot"); loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "initprot"); loadSegmentCommand64Builder.AddMember(Type::IntegerType(4, false), "nsects"); loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("sg_flags_t")), "flags"); Ref loadSegmentCommand64Struct = loadSegmentCommand64Builder.Finalize(); QualifiedName loadSegment64CommandName = std::string("segment_command_64"); std::string loadSegment64CommandTypeId = Type::GenerateAutoTypeId("macho", loadSegment64CommandName); Ref loadSegment64CommandType = Type::StructureType(loadSegmentCommand64Struct); DefineType(loadSegment64CommandTypeId, loadSegment64CommandName, loadSegment64CommandType); StructureBuilder sectionBuilder; sectionBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "sectname"); sectionBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname"); sectionBuilder.AddMember(Type::IntegerType(4, false), "addr"); sectionBuilder.AddMember(Type::IntegerType(4, false), "size"); sectionBuilder.AddMember(Type::IntegerType(4, false), "offset"); sectionBuilder.AddMember(Type::IntegerType(4, false), "align"); sectionBuilder.AddMember(Type::IntegerType(4, false), "reloff"); sectionBuilder.AddMember(Type::IntegerType(4, false), "nreloc"); sectionBuilder.AddMember(Type::IntegerType(4, false), "flags"); sectionBuilder.AddMember(Type::IntegerType(4, false), "reserved1"); sectionBuilder.AddMember(Type::IntegerType(4, false), "reserved2"); Ref sectionStruct = sectionBuilder.Finalize(); QualifiedName sectionName = std::string("section"); std::string sectionTypeId = Type::GenerateAutoTypeId("macho", sectionName); Ref sectionType = Type::StructureType(sectionStruct); DefineType(sectionTypeId, sectionName, sectionType); StructureBuilder section64Builder; section64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "sectname"); section64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname"); section64Builder.AddMember(Type::IntegerType(8, false), "addr"); section64Builder.AddMember(Type::IntegerType(8, false), "size"); section64Builder.AddMember(Type::IntegerType(4, false), "offset"); section64Builder.AddMember(Type::IntegerType(4, false), "align"); section64Builder.AddMember(Type::IntegerType(4, false), "reloff"); section64Builder.AddMember(Type::IntegerType(4, false), "nreloc"); section64Builder.AddMember(Type::IntegerType(4, false), "flags"); section64Builder.AddMember(Type::IntegerType(4, false), "reserved1"); section64Builder.AddMember(Type::IntegerType(4, false), "reserved2"); section64Builder.AddMember(Type::IntegerType(4, false), "reserved3"); Ref section64Struct = section64Builder.Finalize(); QualifiedName section64Name = std::string("section_64"); std::string section64TypeId = Type::GenerateAutoTypeId("macho", section64Name); Ref section64Type = Type::StructureType(section64Struct); DefineType(section64TypeId, section64Name, section64Type); StructureBuilder symtabBuilder; symtabBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); symtabBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); symtabBuilder.AddMember(Type::IntegerType(4, false), "symoff"); symtabBuilder.AddMember(Type::IntegerType(4, false), "nsyms"); symtabBuilder.AddMember(Type::IntegerType(4, false), "stroff"); symtabBuilder.AddMember(Type::IntegerType(4, false), "strsize"); Ref symtabStruct = symtabBuilder.Finalize(); QualifiedName symtabName = std::string("symtab"); std::string symtabTypeId = Type::GenerateAutoTypeId("macho", symtabName); Ref symtabType = Type::StructureType(symtabStruct); DefineType(symtabTypeId, symtabName, symtabType); StructureBuilder dynsymtabBuilder; dynsymtabBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "ilocalsym"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nlocalsym"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "iextdefsym"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextdefsym"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "iundefsym"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nundefsym"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "tocoff"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "ntoc"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "modtaboff"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nmodtab"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "extrefsymoff"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextrefsyms"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "indirectsymoff"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nindirectsyms"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "extreloff"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextrel"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "locreloff"); dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nlocrel"); Ref dynsymtabStruct = dynsymtabBuilder.Finalize(); QualifiedName dynsymtabName = std::string("dysymtab"); std::string dynsymtabTypeId = Type::GenerateAutoTypeId("macho", dynsymtabName); Ref dynsymtabType = Type::StructureType(dynsymtabStruct); DefineType(dynsymtabTypeId, dynsymtabName, dynsymtabType); StructureBuilder uuidBuilder; uuidBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); uuidBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); uuidBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, false), 16), "uuid"); Ref uuidStruct = uuidBuilder.Finalize(); QualifiedName uuidName = std::string("uuid"); std::string uuidTypeId = Type::GenerateAutoTypeId("macho", uuidName); Ref uuidType = Type::StructureType(uuidStruct); DefineType(uuidTypeId, uuidName, uuidType); StructureBuilder linkeditDataBuilder; linkeditDataBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "dataoff"); linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "datasize"); Ref linkeditDataStruct = linkeditDataBuilder.Finalize(); QualifiedName linkeditDataName = std::string("linkedit_data"); std::string linkeditDataTypeId = Type::GenerateAutoTypeId("macho", linkeditDataName); Ref linkeditDataType = Type::StructureType(linkeditDataStruct); DefineType(linkeditDataTypeId, linkeditDataName, linkeditDataType); StructureBuilder encryptionInfoBuilder; encryptionInfoBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptoff"); encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptsize"); encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptid"); Ref encryptionInfoStruct = encryptionInfoBuilder.Finalize(); QualifiedName encryptionInfoName = std::string("encryption_info"); std::string encryptionInfoTypeId = Type::GenerateAutoTypeId("macho", encryptionInfoName); Ref encryptionInfoType = Type::StructureType(encryptionInfoStruct); DefineType(encryptionInfoTypeId, encryptionInfoName, encryptionInfoType); StructureBuilder versionMinBuilder; versionMinBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); versionMinBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); versionMinBuilder.AddMember(Type::IntegerType(4, false), "version"); versionMinBuilder.AddMember(Type::IntegerType(4, false), "sdk"); Ref versionMinStruct = versionMinBuilder.Finalize(); QualifiedName versionMinName = std::string("version_min"); std::string versionMinTypeId = Type::GenerateAutoTypeId("macho", versionMinName); Ref versionMinType = Type::StructureType(versionMinStruct); DefineType(versionMinTypeId, versionMinName, versionMinType); StructureBuilder dyldInfoBuilder; dyldInfoBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "rebase_off"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "rebase_size"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "bind_off"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "bind_size"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "weak_bind_off"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "weak_bind_size"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "lazy_bind_off"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "lazy_bind_size"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "export_off"); dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "export_size"); Ref dyldInfoStruct = dyldInfoBuilder.Finalize(); QualifiedName dyldInfoName = std::string("dyld_info"); std::string dyldInfoTypeId = Type::GenerateAutoTypeId("macho", dyldInfoName); Ref dyldInfoType = Type::StructureType(dyldInfoStruct); DefineType(dyldInfoTypeId, dyldInfoName, dyldInfoType); StructureBuilder dylibBuilder; dylibBuilder.AddMember(Type::IntegerType(4, false), "name"); dylibBuilder.AddMember(Type::IntegerType(4, false), "timestamp"); dylibBuilder.AddMember(Type::IntegerType(4, false), "current_version"); dylibBuilder.AddMember(Type::IntegerType(4, false), "compatibility_version"); Ref dylibStruct = dylibBuilder.Finalize(); QualifiedName dylibName = std::string("dylib"); std::string dylibTypeId = Type::GenerateAutoTypeId("macho", dylibName); Ref dylibType = Type::StructureType(dylibStruct); DefineType(dylibTypeId, dylibName, dylibType); StructureBuilder dylibCommandBuilder; dylibCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); dylibCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); dylibCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("dylib")), "dylib"); Ref dylibCommandStruct = dylibCommandBuilder.Finalize(); QualifiedName dylibCommandName = std::string("dylib_command"); std::string dylibCommandTypeId = Type::GenerateAutoTypeId("macho", dylibCommandName); Ref dylibCommandType = Type::StructureType(dylibCommandStruct); DefineType(dylibCommandTypeId, dylibCommandName, dylibCommandType); StructureBuilder filesetEntryCommandBuilder; filesetEntryCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); filesetEntryCommandBuilder.AddMember(Type::IntegerType(8, false), "vmaddr"); filesetEntryCommandBuilder.AddMember(Type::IntegerType(8, false), "fileoff"); filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "entry_id"); filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "reserved"); Ref filesetEntryCommandStruct = filesetEntryCommandBuilder.Finalize(); QualifiedName filesetEntryCommandName = std::string("fileset_entry_command"); std::string filesetEntryCommandTypeId = Type::GenerateAutoTypeId("macho", filesetEntryCommandName); Ref filesetEntryCommandType = Type::StructureType(filesetEntryCommandStruct); DefineType(filesetEntryCommandTypeId, filesetEntryCommandName, filesetEntryCommandType); StructureBuilder unixThreadCommandBuilder; unixThreadCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd"); unixThreadCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize"); unixThreadCommandBuilder.AddMember(Type::IntegerType(4, false), "flavor"); unixThreadCommandBuilder.AddMember(Type::IntegerType(4, false), "count"); // The 'state' field is intentionally ignored. Ref unixThreadCommandStruct = unixThreadCommandBuilder.Finalize(); QualifiedName unixThreadCommandName = std::string("unix_thread_command"); std::string unixThreadCommandTypeId = Type::GenerateAutoTypeId("macho", unixThreadCommandName); Ref unixThreadCommandType = Type::StructureType(unixThreadCommandStruct); DefineType(unixThreadCommandTypeId, unixThreadCommandName, unixThreadCommandType); std::vector regionsMappedIntoMemory; if (auto metadata = KernelCacheCore::KernelCacheMetadata::LoadFromView(GetParentView())) { for (const auto& image : metadata->LoadedImages()) { auto header = KernelCacheCore::KernelCache::LoadHeaderForAddress(this, image.headerFileLocation, image.installName); if (!header) { LogError("Failed to load header for image %s", image.installName.c_str()); return false; } if (!KernelCacheCore::KernelCache::InitializeSegmentsForHeader(this, *header, image)) { LogError("Failed to initialize segments for image %s", image.installName.c_str()); return false; } KernelCacheCore::KernelCache::InitializeHeader(this, *header); } } // Technically the header is executable, but there shouldn't reasonably be code in the header. AddAutoSegment(textSegOffset, sizeofcmds + 0x20, 0, sizeofcmds + 0x20, SegmentReadable); AddAutoSection("kernelcache_header", textSegOffset, sizeofcmds + 0x20, ReadOnlyDataSectionSemantics); if (m_parseOnly) return true; DefineDataVariable(textSegOffset, Type::NamedType(this, QualifiedName("mach_header_64"))); DefineAutoSymbol( new Symbol(DataSymbol, "kernelcache_header", textSegOffset, LocalBinding)); try { reader.Seek(sizeof(mach_header_64)); size_t sectionNum = 0; for (size_t i = 0; i < ncmds; i++) { load_command load; uint64_t curOffset = reader.GetOffset(); load.cmd = reader.Read32(); load.cmdsize = reader.Read32(); uint64_t nextOffset = curOffset + load.cmdsize; switch (load.cmd) { case LC_SEGMENT: { DefineDataVariable(reader.GetOffset() + textSegOffset, Type::NamedType(this, QualifiedName("segment_command"))); reader.SeekRelative(5 * 8); size_t numSections = reader.Read32(); reader.SeekRelative(4); for (size_t j = 0; j < numSections; j++) { DefineDataVariable( reader.GetOffset() + textSegOffset, Type::NamedType(this, QualifiedName("section"))); DefineAutoSymbol(new Symbol(DataSymbol, "__macho_section::kernelcache[" + std::to_string(sectionNum++) + "]", reader.GetOffset() + textSegOffset, LocalBinding)); reader.SeekRelative((8 * 8) + 4); } break; } case LC_SEGMENT_64: { DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("segment_command_64"))); reader.SeekRelative(7 * 8); size_t numSections = reader.Read32(); reader.SeekRelative(4); for (size_t j = 0; j < numSections; j++) { DefineDataVariable( reader.GetOffset() + textSegOffset, Type::NamedType(this, QualifiedName("section_64"))); DefineAutoSymbol(new Symbol(DataSymbol, "__macho_section_64::kernelcache[" + std::to_string(sectionNum++) + "]", reader.GetOffset() + textSegOffset, LocalBinding)); reader.SeekRelative(10 * 8); } break; } case LC_SYMTAB: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("symtab"))); break; case LC_DYSYMTAB: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("dysymtab"))); break; case LC_UUID: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("uuid"))); break; case LC_ID_DYLIB: case LC_LOAD_DYLIB: case LC_REEXPORT_DYLIB: case LC_LOAD_WEAK_DYLIB: case LC_LOAD_UPWARD_DYLIB: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("dylib_command"))); if (load.cmdsize - 24 <= 150) DefineDataVariable( curOffset + textSegOffset + 24, Type::ArrayType(Type::IntegerType(1, true), load.cmdsize - 24)); break; case LC_CODE_SIGNATURE: case LC_SEGMENT_SPLIT_INFO: case LC_FUNCTION_STARTS: case LC_DATA_IN_CODE: case LC_DYLIB_CODE_SIGN_DRS: case LC_DYLD_EXPORTS_TRIE: case LC_DYLD_CHAINED_FIXUPS: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("linkedit_data"))); break; case LC_ENCRYPTION_INFO: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("encryption_info"))); break; case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("version_min"))); break; case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("dyld_info"))); break; case LC_FILESET_ENTRY: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("fileset_entry_command"))); break; case LC_UNIXTHREAD: { DefineDataVariable( curOffset + textSegOffset, Type::NamedType(this, QualifiedName("unix_thread_command"))); reader.SeekRelative(4); uint32_t count = reader.Read32(); DefineDataVariable(reader.GetOffset() + textSegOffset, Type::ArrayType(Type::IntegerType(8, true), count)); break; } default: DefineDataVariable(curOffset + textSegOffset, Type::NamedType(this, QualifiedName("load_command"))); break; } DefineAutoSymbol(new Symbol(DataSymbol, "__macho_load_command::kernelcache[" + std::to_string(i) + "]", curOffset + textSegOffset, LocalBinding)); reader.Seek(nextOffset); } } catch (ReadException&) { LogError("Error when applying Mach-O header types at %" PRIx64, textSegOffset); } return true; } KCViewType::KCViewType() : BinaryViewType(KC_VIEW_NAME, KC_VIEW_NAME) { } BinaryNinja::Ref KCViewType::Create(BinaryNinja::BinaryView* data) { uint32_t magic; data->Read(&magic, data->GetStart(), 4); if (magic != MH_CIGAM_64 && magic != MH_MAGIC_64) // FIXME 32 bit { uint32_t im4pMagic; data->Read(&im4pMagic, data->GetStart() + 0x8, 4); if (im4pMagic == 0x50344d49) // P4MI { auto img4 = Transform::GetByName("IMG4-Unencrypted"); DataBuffer img4Payload; img4->Decode(data->ReadBuffer(data->GetStart(), data->GetLength()), img4Payload); DataBuffer machOPayload; uint32_t magic = ((uint32_t*)img4Payload.GetData())[0]; if (magic == FAT_MAGIC_64 || magic == MH_MAGIC_64 || magic == MH_MAGIC || magic == MH_CIGAM_64 || magic == MH_CIGAM ) { machOPayload = img4Payload; } else if (strncmp((char*)img4Payload.GetData(), "bvx2", 4) == 0) { auto lzfse = Transform::GetByName("LZFSE"); if (lzfse) lzfse->Decode(img4Payload, machOPayload); } else { #ifdef COMPRESSION_DEBUG LogError("Unknown compression type in IMG4 Payload, writing img4 payload to RAW view for debug purposes."); LogError("KernelCache parsing will now fail to proceed."); data->WriteBuffer(0, img4Payload); return new KCView(KC_VIEW_NAME, data, false); #else LogError("Unknown compression type in IMG4 Payload, unable to proceed."); LogError("You can manually extract the kernelcache using `kerneldec`,`ipsw`, or other tools.") return nullptr; #endif } if (machOPayload.GetLength() == 0) { #ifdef COMPRESSION_DEBUG LogError("Failed to perform extraction on IMG4 Payload, writing img4 payload to RAW view for debug purposes."); LogError("KernelCache parsing will now fail to proceed."); data->WriteBuffer(0, img4Payload); return new KCView(KC_VIEW_NAME, data, false); #else return nullptr; #endif } uint32_t machoMagic = ((uint32_t*)machOPayload.GetData())[0]; if (machoMagic == FAT_MAGIC_64) { DataBuffer output = machOPayload.GetSlice(0x1c, machOPayload.GetLength()-0x1c); data->WriteBuffer(0, output); } else if (machoMagic == MH_MAGIC_64 || machoMagic == MH_MAGIC || machoMagic == MH_CIGAM_64 || machoMagic == MH_CIGAM) { data->WriteBuffer(0, machOPayload); } else { #ifdef COMPRESSION_DEBUG LogError("Unknown Mach-O magic in IMG4 Payload, writing img4 payload to RAW view for debug purposes."); LogError("KernelCache parsing will now fail to proceed."); data->WriteBuffer(0, machOPayload); return new KCView(KC_VIEW_NAME, data, false); #else return nullptr; #endif } return new KCView(KC_VIEW_NAME, data, false); } return nullptr; } return new KCView(KC_VIEW_NAME, data, false); } Ref KCViewType::GetLoadSettingsForData(BinaryView* data) { Ref viewRef = Parse(data); if (!viewRef || !viewRef->Init()) { LogWarn("Failed to initialize view of type '%s'. Generating default load settings.", GetName().c_str()); viewRef = data; } Ref settings = GetDefaultLoadSettingsForData(viewRef); // specify default load settings that can be overridden std::vector overrides = {"loader.imageBase", "loader.platform"}; settings->UpdateProperty("loader.imageBase", "message", "Note: File indicates image is not relocatable."); for (const auto& override : overrides) { if (settings->Contains(override)) settings->UpdateProperty(override, "readOnly", false); } // Merge existing load settings if they exist. This allows for the selection of a specific object file from a Mach-O // Universal file. The 'Universal' BinaryViewType generates a schema with 'loader.universal.architectures'. This // schema contains an appropriate 'Mach-O' load schema for selecting a specific object file. The embedded schema // contains 'loader.macho.universalImageOffset'. Ref loadSettings = viewRef->GetLoadSettings(GetName()); if (loadSettings && !loadSettings->IsEmpty()) settings->DeserializeSchema(loadSettings->SerializeSchema()); return settings; } BinaryNinja::Ref KCViewType::Parse(BinaryNinja::BinaryView* data) { uint32_t magic; data->Read(&magic, data->GetStart(), 4); if (magic != MH_CIGAM_64 && magic != MH_MAGIC_64) // FIXME 32 bit { uint32_t im4pMagic; data->Read(&im4pMagic, data->GetStart() + 0x8, 4); if (im4pMagic == 0x50344d49) // P4MI { auto img4 = Transform::GetByName("IMG4-Unencrypted"); auto lzfse = Transform::GetByName("LZFSE"); DataBuffer img4Payload; img4->Decode(data->ReadBuffer(data->GetStart(), data->GetLength()), img4Payload); DataBuffer machOPayload; lzfse->Decode(img4Payload, machOPayload); uint32_t magic = ((uint32_t*)machOPayload.GetData())[0]; auto id = data->BeginUndoActions(); if (magic == FAT_MAGIC_64) { DataBuffer output = machOPayload.GetSlice(0x1c, machOPayload.GetLength()-0x1c); data->WriteBuffer(0, output); } else { data->WriteBuffer(0, machOPayload); } data->ForgetUndoActions(id); return new KCView(KC_VIEW_NAME, data, true); } return nullptr; } return new KCView(KC_VIEW_NAME, data, true); } bool KCViewType::IsTypeValidForData(BinaryNinja::BinaryView* data) { if (!data) return false; uint32_t magic; data->Read(&magic, data->GetStart(), 4); if (magic != MH_CIGAM_64 && magic != MH_MAGIC_64) // FIXME 32 bit { uint32_t im4pMagic; data->Read(&im4pMagic, data->GetStart() + 0x8, 4); if (im4pMagic == 0x50344d49) // P4MI { auto img4 = Transform::GetByName("IMG4-Unencrypted"); auto lzfse = Transform::GetByName("LZFSE"); DataBuffer img4Payload; img4->Decode(data->ReadBuffer(data->GetStart(), data->GetLength()), img4Payload); DataBuffer machOPayload; lzfse->Decode(img4Payload, machOPayload); uint32_t magic = ((uint32_t*)machOPayload.GetData())[0]; if (magic == FAT_MAGIC_64 || magic == MH_CIGAM_64 || magic == MH_MAGIC_64) return true; return false; } return false; } uint32_t fileType; data->Read(&fileType, data->GetStart() + 0xc, 4); if (fileType != MH_FILESET) { return false; } return true; } extern "C" { void InitKCViewType() { static KCViewType type; BinaryViewType::Register(&type); g_kcViewType = &type; } }