summaryrefslogtreecommitdiff
path: root/view/kernelcache/core/KCView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'view/kernelcache/core/KCView.cpp')
-rw-r--r--view/kernelcache/core/KCView.cpp921
1 files changed, 921 insertions, 0 deletions
diff --git a/view/kernelcache/core/KCView.cpp b/view/kernelcache/core/KCView.cpp
new file mode 100644
index 00000000..f166eafd
--- /dev/null
+++ b/view/kernelcache/core/KCView.cpp
@@ -0,0 +1,921 @@
+//
+// 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> platform;
+ Ref<Architecture> 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<std::string, Ref<Metadata>> metadataMap = {
+ {"machoplatform", new Metadata((uint64_t) platformID)},
+ };
+ Ref<Metadata> metadata = new Metadata(metadataMap);
+ Ref<Platform> 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<Enumeration> cpuTypeEnum = cpuTypeBuilder.Finalize();
+
+ Ref<Type> 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<Enumeration> fileTypeEnum = fileTypeBuilder.Finalize();
+
+ Ref<Type> 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<Enumeration> flagsTypeEnum = flagsTypeBuilder.Finalize();
+
+ Ref<Type> 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<Structure> machoHeaderStruct = machoHeaderBuilder.Finalize();
+ QualifiedName headerName = (GetAddressSize() == 8) ? std::string("mach_header_64") : std::string("mach_header");
+
+ std::string headerTypeId = Type::GenerateAutoTypeId("macho", headerName);
+ Ref<Type> 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<Enumeration> cmdTypeEnum = cmdTypeBuilder.Finalize();
+
+ Ref<Type> 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<Structure> loadCommandStruct = loadCommandBuilder.Finalize();
+ QualifiedName loadCommandName = std::string("load_command");
+ std::string loadCommandTypeId = Type::GenerateAutoTypeId("macho", loadCommandName);
+ Ref<Type> 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<Enumeration> protTypeEnum = protTypeBuilder.Finalize();
+
+ Ref<Type> 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<Enumeration> segFlagsTypeEnum = segFlagsTypeBuilder.Finalize();
+
+ Ref<Type> 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<Structure> loadSegmentCommandStruct = loadSegmentCommandBuilder.Finalize();
+ QualifiedName loadSegmentCommandName = std::string("segment_command");
+ std::string loadSegmentCommandTypeId = Type::GenerateAutoTypeId("macho", loadSegmentCommandName);
+ Ref<Type> 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<Structure> loadSegmentCommand64Struct = loadSegmentCommand64Builder.Finalize();
+ QualifiedName loadSegment64CommandName = std::string("segment_command_64");
+ std::string loadSegment64CommandTypeId = Type::GenerateAutoTypeId("macho", loadSegment64CommandName);
+ Ref<Type> 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<Structure> sectionStruct = sectionBuilder.Finalize();
+ QualifiedName sectionName = std::string("section");
+ std::string sectionTypeId = Type::GenerateAutoTypeId("macho", sectionName);
+ Ref<Type> 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<Structure> section64Struct = section64Builder.Finalize();
+ QualifiedName section64Name = std::string("section_64");
+ std::string section64TypeId = Type::GenerateAutoTypeId("macho", section64Name);
+ Ref<Type> 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<Structure> symtabStruct = symtabBuilder.Finalize();
+ QualifiedName symtabName = std::string("symtab");
+ std::string symtabTypeId = Type::GenerateAutoTypeId("macho", symtabName);
+ Ref<Type> 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<Structure> dynsymtabStruct = dynsymtabBuilder.Finalize();
+ QualifiedName dynsymtabName = std::string("dysymtab");
+ std::string dynsymtabTypeId = Type::GenerateAutoTypeId("macho", dynsymtabName);
+ Ref<Type> 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<Structure> uuidStruct = uuidBuilder.Finalize();
+ QualifiedName uuidName = std::string("uuid");
+ std::string uuidTypeId = Type::GenerateAutoTypeId("macho", uuidName);
+ Ref<Type> 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<Structure> linkeditDataStruct = linkeditDataBuilder.Finalize();
+ QualifiedName linkeditDataName = std::string("linkedit_data");
+ std::string linkeditDataTypeId = Type::GenerateAutoTypeId("macho", linkeditDataName);
+ Ref<Type> 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<Structure> encryptionInfoStruct = encryptionInfoBuilder.Finalize();
+ QualifiedName encryptionInfoName = std::string("encryption_info");
+ std::string encryptionInfoTypeId = Type::GenerateAutoTypeId("macho", encryptionInfoName);
+ Ref<Type> 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<Structure> versionMinStruct = versionMinBuilder.Finalize();
+ QualifiedName versionMinName = std::string("version_min");
+ std::string versionMinTypeId = Type::GenerateAutoTypeId("macho", versionMinName);
+ Ref<Type> 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<Structure> dyldInfoStruct = dyldInfoBuilder.Finalize();
+ QualifiedName dyldInfoName = std::string("dyld_info");
+ std::string dyldInfoTypeId = Type::GenerateAutoTypeId("macho", dyldInfoName);
+ Ref<Type> 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<Structure> dylibStruct = dylibBuilder.Finalize();
+ QualifiedName dylibName = std::string("dylib");
+ std::string dylibTypeId = Type::GenerateAutoTypeId("macho", dylibName);
+ Ref<Type> 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<Structure> dylibCommandStruct = dylibCommandBuilder.Finalize();
+ QualifiedName dylibCommandName = std::string("dylib_command");
+ std::string dylibCommandTypeId = Type::GenerateAutoTypeId("macho", dylibCommandName);
+ Ref<Type> 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<Structure> filesetEntryCommandStruct = filesetEntryCommandBuilder.Finalize();
+ QualifiedName filesetEntryCommandName = std::string("fileset_entry_command");
+ std::string filesetEntryCommandTypeId = Type::GenerateAutoTypeId("macho", filesetEntryCommandName);
+ Ref<Type> 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<Structure> unixThreadCommandStruct = unixThreadCommandBuilder.Finalize();
+ QualifiedName unixThreadCommandName = std::string("unix_thread_command");
+ std::string unixThreadCommandTypeId = Type::GenerateAutoTypeId("macho", unixThreadCommandName);
+ Ref<Type> unixThreadCommandType = Type::StructureType(unixThreadCommandStruct);
+ DefineType(unixThreadCommandTypeId, unixThreadCommandName, unixThreadCommandType);
+
+ std::vector<KernelCacheCore::MemoryRegion> 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<BinaryNinja::BinaryView> 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<Settings> KCViewType::GetLoadSettingsForData(BinaryView* data)
+{
+ Ref<BinaryView> 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> settings = GetDefaultLoadSettingsForData(viewRef);
+
+ // specify default load settings that can be overridden
+ std::vector<std::string> 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<Settings> loadSettings = viewRef->GetLoadSettings(GetName());
+ if (loadSettings && !loadSettings->IsEmpty())
+ settings->DeserializeSchema(loadSettings->SerializeSchema());
+
+ return settings;
+}
+
+
+BinaryNinja::Ref<BinaryNinja::BinaryView> 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;
+ }
+}
+