From ee95990225c622227fd00bc94debfd30b4359d16 Mon Sep 17 00:00:00 2001 From: Nik Date: Mon, 2 Jan 2023 13:15:51 +0100 Subject: [PATCH] patterns/macho: Added Mach-O pattern --- README.md | 1 + patterns/macho.hexpat | 383 ++++++++++++++++++++++++ tests/patterns/test_data/macho.hexpat.o | Bin 0 -> 39584 bytes 3 files changed, 384 insertions(+) create mode 100644 patterns/macho.hexpat create mode 100644 tests/patterns/test_data/macho.hexpat.o 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 0000000000000000000000000000000000000000..d80548dd6a9f42d894b0ea0a6acebabd59104aed GIT binary patch literal 39584 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