diff --git a/README.md b/README.md index d108bf2..345bbb6 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed | GIF | `image/gif` | [`patterns/gif.hexpat`](patterns/gif.hexpat) | GIF image files | | ZSTD | `application/zstd` | [`patterns/zstd.hexpat`](patterns/zstd.hexpat) | Zstandard compressed data format | | COFF | `application/x-coff` | [`patterns/coff.hexpat`](patterns/coff.hexpat) | Common Object File Format (COFF) executable | +| Mach-O | `application/x-mach-binary` | [`patterns/macho.hexpat`](patterns/macho.hexpat) | Mach-O executable | ### Scripts diff --git a/patterns/macho.hexpat b/patterns/macho.hexpat new file mode 100644 index 0000000..8616be1 --- /dev/null +++ b/patterns/macho.hexpat @@ -0,0 +1,383 @@ +#pragma MIME application/x-mach-binary + +#include + +enum Magic : u32 { + _32BitMagic = 0xFEEDFACE, + _64BitMagic = 0xFEEDFACF +}; + +enum CpuType : u32 { + VAX = 1, + ROMP = 2, + BS32032 = 4, + BS32332 = 5, + MC680x0 = 6, + I386 = 7, + X86_64 = CpuType::I386 | 0x100'0000, + MIPS = 8, + NS32532 = 9, + HPPA = 11, + ARM = 12, + MC88000 = 13, + SPARC = 14, + I860 = be u32(15), + I860_LITTLE = 16, + RS6000 = 17, + MC980000 = 18, + POWERPC = 18, + POWERPC64 = CpuType::POWERPC | 0x100'0000, + VEO = 255 +}; + +enum SubCpuTypeVAX : u24 { + ALL = 0, + VAX780 = 1, + VAX785 = 2, + VAX750 = 3, + VAX730 = 4, + UVAXI = 5, + UVAXII = 6, + VAX8200 = 7, + VAX8500 = 8, + VAX8600 = 9, + VAX8650 = 10, + VAX8800 = 11, + UVAXIII = 12 +}; + +enum SubCpuTypeROMP : u24 { + ALL = 0, + PC = 1, + APC = 2, + _135 = 3 +}; + +enum SubCpuType32XXX : u24 { + ALL = 0, + MMAX_DPC = 1, + SQT = 2, + MMAX_APC_FPU = 3, + MMAX_APC_FPA = 4, + MMAX_XPC = 5 +}; + +enum SubCpuTypeI386 : u24 { + _386 = 3, + _486 = 4, + _486SX = SubCpuTypeI386::_486 + 128, + _586 = 5, + IntelPentium = 5 + (0 << 4), + IntelPentiumPro = 6 + (1 << 4), + IntelPentiumIIM3 = 6 + (3 << 4), + IntelPentiumIIM5 = 6 + (5 << 4), + IntelPentium4 = 10 + (0 << 4), +}; + +enum SubCpuTypeMips : u24 { + ALL = 0, + R2300 = 1, + R2600 = 2, + R2800 = 3, + R2000a = 4 +}; + +enum SubCpuType680x0 : u24 { + ALL = 1, + MC68030 = 1, + MC68040 = 2, + MC68030_Only = 3 +}; + +enum SubCpuTypeHPPA : u24 { + ALL = 0, + _7100 = 0, + _7100LC = 1 +}; + +enum SubCpuTypeARM : u24 { + ALL = 0, + A500_ARCH = 1, + A500 = 2, + A440 = 3, + M4 = 4, + V4T = 5, + V6 = 6, + V5TEJ = 7, + XSCALE = 8, + V7 = 9, + V7F = 10, /* Cortex A9 */ + V7S = 11, /* Swift */ + V7K = 12 /* Kirkwood40 */ +}; + +enum SubCpuTypeMC88000 : u24 { + ALL = 0, + MMAX_JPC = 1, + MC88100 = 1, + MC88110 = 2 +}; + +enum SubCpuTypeMC98000 : u24 { + ALL = 0, + MC98601 = 1 +}; + +enum SubCpuTypeI860 : u24 { + ALL = 0, + _860 = 1 +}; + +enum SubCpuTypeI860Little : u24 { + ALL = 0 ... 1 +}; + +enum SubCpuTypeRS6000 : u24 { + ALL = 0 ... 1 +}; + +enum SubCpuTypeSparc : u24 { + ALL = 0, + _260 = 1, + _110 = 2 +}; + +enum SubCpuTypePowerPC : u24 { + ALL = 0, + _601 = 1, + _602 = 2, + _603 = 3, + _603e = 4, + _603ev = 5, + _604 = 6, + _604e = 7, + _620 = 8, + _750 = 9, + _7400 = 10, + _7450 = 11, + _970 = 100 +}; + +enum SubCpuTypeVEO : u24 { + _1 = 1, + _2 = 2, + _3 = 3, + _4 = 4, + ALL = SubCpuTypeVEO::_2 +}; + +bitfield Capabilities { + padding : 7; + lib64 : 1; +} [[right_to_left]]; + +enum FileType : u32 { + Object = 1, + Execute = 2, + FVMLib = 3, + Core = 4, + Preload = 5, + DyLib = 6, + DyLinker = 7, + Bundle = 8, + DyLibStub = 9, + DSym = 10, + KExtBundle = 11, +}; + +bitfield Flags { + noUndefs : 1; + incrLink : 1; + dyldLink : 1; + binDatLoad : 1; + prebound : 1; + splitSegs : 1; + lazyInit : 1; + twoLevel : 1; + forceFlat : 1; + noMultiDefs : 1; + noFixPrebinding : 1; + prebindable : 1; + allModsBound : 1; + subSectionsViaSymbols : 1; + canonical : 1; + weakDefines : 1; + bindsToWeak : 1; + allowStackExecution : 1; + rootSafe : 1; + setuidSafe : 1; + noReexportedDylibs : 1; + pie : 1; + deadStrippableDylib : 1; + hasTlvDescriptors : 1; + noHeapExecution : 1; + appExtensionSafe : 1; + nlistOutOfSyncWithDyldinof : 1; + simSupport : 1; +} [[right_to_left]]; + +struct Header { + Magic magic; + CpuType cpuType; + if (cpuType == CpuType::VAX) SubCpuTypeVAX subCpuType; + else if (cpuType == CpuType::ROMP) SubCpuTypeROMP subCpuType; + else if (cpuType == CpuType::BS32032 || cpuType == CpuType::BS32332 || cpuType == CpuType::NS32532) SubCpuType32XXX subCpuType; + else if (cpuType == CpuType::I386 || cpuType == CpuType::X86_64) SubCpuTypeI386 subCpuType; + else if (cpuType == CpuType::MIPS) SubCpuTypeMips subCpuType; + else if (cpuType == CpuType::HPPA) SubCpuTypeHPPA subCpuType; + else if (cpuType == CpuType::ARM) SubCpuTypeARM subCpuType; + else if (cpuType == CpuType::MC88000) SubCpuTypeMC88000 subCpuType; + else if (cpuType == CpuType::MC98000) SubCpuTypeMC98000 subCpuType; + else if (cpuType == CpuType::I860 || cpuType == CpuType::I860_LITTLE) SubCpuTypeI860 subCpuType; + else if (cpuType == CpuType::SPARC) SubCpuTypeSparc subCpuType; + else if (cpuType == CpuType::POWERPC || cpuType == CpuType::POWERPC64) SubCpuTypePowerPC subCpuType; + else if (cpuType == CpuType::VEO) SubCpuTypeVEO subCpuType; + else u24 subCpuType; + Capabilities capabilities; + FileType fileType; + u32 numCommands; + type::Size sizeOfCommands; + Flags flags; + + if (magic == Magic::_64BitMagic) padding[sizeof(u32)]; +}; + +enum Command : u32 { + ReqDyLd = 0x8000'0000, + + Segment = 0x01, + SymTab = 0x02, + SymSeg = 0x03, + Thread = 0x04, + UnixThread = 0x05, + LoadFVMLib = 0x06, + IdFVMLib = 0x07, + Ident = 0x08, + FVMFile = 0x09, + PrePage = 0x0A, + DySymTab = 0x0B, + LoadDyLib = 0x0C, + IdDyLib = 0x0D, + LoadDyLinker = 0x0E, + IdDyLinker = 0x0F, + PreboundDyLib = 0x10, + Routines = 0x11, + SubFramework = 0x12, + SubUmbrella = 0x13, + SubClient = 0x14, + SubLibrary = 0x15, + TwoLevelHints = 0x16, + PrebindCksum = 0x17, + LoadWeakDyLib = 0x18 | Command::ReqDyLd, + Segment64 = 0x19, + Routines64 = 0x1A, + UUID = 0x1B, + RPath = 0x1C | 0x8000'0000, + CodeSignature = 0x1D, + SegmentSplitInfo = 0x1E, + ReExportDyLib = 0x1F | Command::ReqDyLd, + LazyLoadDyLib = 0x20, + EncryptionInfo = 0x21, + DyLdInfo = 0x22, + DyLdInfoOnly = 0x22 | Command::ReqDyLd, + LoadUpwardDyLib = 0x23 | Command::ReqDyLd, + VersionMinMacOSX = 0x24, + VersionMinIPhoneOS = 0x25, + FunctionStarts = 0x26, + DyLdEnvironment = 0x27, + Main = 0x28 | Command::ReqDyLd, + DataInCode = 0x29, + SourceVersion = 0x2A, + DyLibCodeSignDRS = 0x2B +}; + +struct CommandUUID { + u128 uuid; +}; + +struct Section { + char sectionName[16]; + char segmentName[16]; + u32 address; + type::Size size; + u32 offset; + u32 align; + u32 reloff; + u32 numRelocs; + u32 flags; + padding[8]; + + if (offset > 0) + u8 data[size] @ offset [[sealed]]; +}; + +struct CommandSegment { + char segmentName[16]; + u32 vmAddress; + type::Size vmSize; + u32 fileOffset; + type::Size fileSize; + u32 maxProtection; + u32 initProtection; + u32 numSections; + u32 flags; + + Section sections[numSections]; + + if (fileOffset > 0) + u8 data[fileSize] @ fileOffset [[sealed]]; +}; + +struct Section64 { + char sectionName[16]; + char segmentName[16]; + u64 address; + type::Size size; + u32 offset; + u32 align; + u32 reloff; + u32 numRelocs; + u32 flags; + padding[12]; + + if (offset > 0) + u8 data[size] @ offset [[sealed]]; +}; + +struct CommandSegment64 { + char segmentName[16]; + u64 vmAddress; + type::Size vmSize; + u64 fileOffset; + type::Size fileSize; + u32 maxProtection; + u32 initProtection; + u32 numSections; + u32 flags; + + Section64 sections[numSections]; + + if (fileOffset > 0) + u8 data[fileSize] @ fileOffset [[sealed]]; +}; + +struct LoadCommand { + Command command; + type::Size commandSize; + + if (command == Command::UUID) + CommandUUID data; + else if (command == Command::Segment) + CommandSegment data; + else if (command == Command::Segment64) + CommandSegment64 data; + else + u8 data[commandSize - 8] [[sealed]]; +}; + +struct MachO { + Header header; + LoadCommand loadCommands[header.numCommands]; +}; + +MachO macho @ 0x00; \ No newline at end of file diff --git a/tests/patterns/test_data/macho.hexpat.o b/tests/patterns/test_data/macho.hexpat.o new file mode 100644 index 0000000..d80548d Binary files /dev/null and b/tests/patterns/test_data/macho.hexpat.o differ