summaryrefslogtreecommitdiff
path: root/view/macho/machoview.h
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-03-06 19:20:34 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2024-03-06 19:20:34 -0500
commit828fff839f4e4de3e9582405dfec567531000ebc (patch)
treeee0db0607edb0c76c653078672201c85e8a96d19 /view/macho/machoview.h
parent47894a1ce20090849ad304c68e6c0b889665eda3 (diff)
Move view modules into the API repo
Diffstat (limited to 'view/macho/machoview.h')
-rw-r--r--view/macho/machoview.h1375
1 files changed, 1375 insertions, 0 deletions
diff --git a/view/macho/machoview.h b/view/macho/machoview.h
new file mode 100644
index 00000000..20d2ea78
--- /dev/null
+++ b/view/macho/machoview.h
@@ -0,0 +1,1375 @@
+#pragma once
+
+#include <exception>
+#include <vector>
+#include <string.h>
+
+#include "binaryninjaapi.h"
+
+//These are laready defined in one of the osx headers we want to override
+#undef CPU_SUBTYPE_INTEL
+#undef CPU_SUBTYPE_I386_ALL
+#undef CPU_SUBTYPE_POWERPC_ALL
+#undef LC_MAIN
+#undef LC_SOURCE_VERSION
+#undef LC_DYLIB_CODE_SIGN_DRS
+#undef LC_DYLD_INFO_ONLY
+
+#define MH_MAGIC 0xfeedface
+#define MH_MAGIC_64 0xfeedfacf
+#define MH_CIGAM 0xcefaedfe
+#define MH_CIGAM_64 0xcffaedfe
+#define FAT_MAGIC 0xcafebabe
+#define FAT_MAGIC_64 0xcafebabf
+
+typedef int32_t cpu_type_t;
+typedef int32_t cpu_subtype_t;
+typedef int vm_prot_t;
+
+//Cpu types
+#define MACHO_CPU_ARCH_ABI64 0x01000000
+#define MACHO_CPU_ARCH_ABI64_32 0x02000000
+
+#define MACHO_CPU_TYPE_ANY ((cpu_type_t) -1)
+#define MACHO_CPU_TYPE_VAX ((cpu_type_t) 1)
+#define MACHO_CPU_TYPE_MC680x0 ((cpu_type_t) 6)
+#define MACHO_CPU_TYPE_X86 ((cpu_type_t) 7)
+#define MACHO_CPU_TYPE_X86_64 (MACHO_CPU_TYPE_X86 | MACHO_CPU_ARCH_ABI64)
+#define MACHO_CPU_TYPE_MIPS ((cpu_type_t) 8)
+#define MACHO_CPU_TYPE_MC98000 ((cpu_type_t) 10)
+#define MACHO_CPU_TYPE_HPPA ((cpu_type_t) 11)
+#define MACHO_CPU_TYPE_ARM ((cpu_type_t) 12)
+#define MACHO_CPU_TYPE_ARM64 (MACHO_CPU_TYPE_ARM | MACHO_CPU_ARCH_ABI64)
+#define MACHO_CPU_TYPE_ARM64_32 (MACHO_CPU_TYPE_ARM | MACHO_CPU_ARCH_ABI64_32)
+#define MACHO_CPU_TYPE_MC88000 ((cpu_type_t) 13)
+#define MACHO_CPU_TYPE_SPARC ((cpu_type_t) 14)
+#define MACHO_CPU_TYPE_I860 ((cpu_type_t) 15)
+#define MACHO_CPU_TYPE_ALPHA ((cpu_type_t) 16)
+#define MACHO_CPU_TYPE_POWERPC ((cpu_type_t) 18)
+#define MACHO_CPU_TYPE_POWERPC64 (MACHO_CPU_TYPE_POWERPC | MACHO_CPU_ARCH_ABI64)
+
+//Cpu subtype capability bits
+#define MACHO_CPU_SUBTYPE_MASK ((cpu_subtype_t)0xff000000)
+#define MACHO_CPU_SUBTYPE_LIB64 ((cpu_subtype_t)0x80000000)
+
+//Cpu subtypes
+#define MACHO_CPU_SUBTYPE_INTEL(f,m) ((cpu_subtype_t) (f)+((m)<<4))
+#define MACHO_CPU_SUBTYPE_I386_ALL MACHO_CPU_SUBTYPE_INTEL(3,0)
+#define MACHO_CPU_SUBTYPE_X86_ALL ((cpu_subtype_t) 3)
+#define MACHO_CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t) 4)
+#define MACHO_CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t) 3)
+#define MACHO_CPU_SUBTYPE_X86_64_H ((cpu_subtype_t) 8)
+
+#define MACHO_CPU_SUBTYPE_ARM_ALL ((cpu_subtype_t) 0)
+#define MACHO_CPU_SUBTYPE_ARM_V4T ((cpu_subtype_t) 5)
+#define MACHO_CPU_SUBTYPE_ARM_V6 ((cpu_subtype_t) 6)
+#define MACHO_CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
+#define MACHO_CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
+#define MACHO_CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
+#define MACHO_CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10)
+#define MACHO_CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11)
+#define MACHO_CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12)
+#define MACHO_CPU_SUBTYPE_ARM_V8 ((cpu_subtype_t) 13)
+#define MACHO_CPU_SUBTYPE_ARM_V6M ((cpu_subtype_t) 14)
+#define MACHO_CPU_SUBTYPE_ARM_V7M ((cpu_subtype_t) 15)
+#define MACHO_CPU_SUBTYPE_ARM_V7EM ((cpu_subtype_t) 16)
+
+#define MACHO_CPU_SUBTYPE_ARM64_ALL ((cpu_subtype_t) 0)
+#define MACHO_CPU_SUBTYPE_ARM64_V8 ((cpu_subtype_t) 1)
+#define MACHO_CPU_SUBTYPE_ARM64E ((cpu_subtype_t) 2)
+
+#define MACHO_CPU_SUBTYPE_ARM64_32_ALL ((cpu_subtype_t) 0)
+#define MACHO_CPU_SUBTYPE_ARM64_32_V8 ((cpu_subtype_t) 1)
+
+#define MACHO_CPU_SUBTYPE_POWERPC_ALL ((cpu_subtype_t) 0)
+#define MACHO_CPU_SUBTYPE_POWERPC_601 ((cpu_subtype_t) 1)
+#define MACHO_CPU_SUBTYPE_POWERPC_602 ((cpu_subtype_t) 2)
+#define MACHO_CPU_SUBTYPE_POWERPC_603 ((cpu_subtype_t) 3)
+#define MACHO_CPU_SUBTYPE_POWERPC_603e ((cpu_subtype_t) 4)
+#define MACHO_CPU_SUBTYPE_POWERPC_603ev ((cpu_subtype_t) 5)
+#define MACHO_CPU_SUBTYPE_POWERPC_604 ((cpu_subtype_t) 6)
+#define MACHO_CPU_SUBTYPE_POWERPC_604e ((cpu_subtype_t) 7)
+#define MACHO_CPU_SUBTYPE_POWERPC_620 ((cpu_subtype_t) 8)
+#define MACHO_CPU_SUBTYPE_POWERPC_750 ((cpu_subtype_t) 9)
+#define MACHO_CPU_SUBTYPE_POWERPC_7400 ((cpu_subtype_t) 10)
+#define MACHO_CPU_SUBTYPE_POWERPC_7450 ((cpu_subtype_t) 11)
+#define MACHO_CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
+
+//Page protections
+#define MACHO_VM_PROT_NONE ((vm_prot_t) 0x00)
+#define MACHO_VM_PROT_READ ((vm_prot_t) 0x01)
+#define MACHO_VM_PROT_WRITE ((vm_prot_t) 0x02)
+#define MACHO_VM_PROT_EXECUTE ((vm_prot_t) 0x04)
+#define MACHO_VM_PROT_DEFAULT (VM_PROT_READ|VM_PROT_WRITE)
+#define MACHO_VM_PROT_ALL (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)
+#define MACHO_VM_PROT_NO_CHANGE ((vm_prot_t) 0x08)
+#define MACHO_VM_PROT_COPY ((vm_prot_t) 0x10)
+#define MACHO_VM_PROT_WANTS_COPY ((vm_prot_t) 0x10)
+
+//Segment flags
+#define SG_HIGHVM 0x1
+#define SG_FVMLIB 0x2
+#define SG_NORELOC 0x4
+#define SG_PROTECTED_VERSION_1 0x8
+
+//Section flags
+#define S_ATTR_SOME_INSTRUCTIONS 0x00000400
+#define S_ATTR_PURE_INSTRUCTIONS 0x80000000 // section contains only true machine instructions
+#define S_ATTR_NO_TOC 0x40000000 // section contains coalesced symbols that are not to be in a ranlib table of contents
+#define S_ATTR_STRIP_STATIC_SYMS 0x20000000 // ok to strip static symbols in this section in files with the MH_DYLDLINK flag
+#define S_ATTR_NO_DEAD_STRIP 0x10000000 // no dead stripping
+#define S_ATTR_LIVE_SUPPORT 0x08000000 // blocks are live if they reference live blocks
+#define S_ATTR_SELF_MODIFYING_CODE 0x04000000 // Used with i386 code stubs written on by dyld
+
+#define S_REGULAR 0x0
+#define S_ZEROFILL 0x1
+#define S_CSTRING_LITERALS 0x2
+#define S_4BYTE_LITERALS 0x3
+#define S_8BYTE_LITERALS 0x4
+#define S_LITERAL_POINTERS 0x5
+#define S_NON_LAZY_SYMBOL_POINTERS 0x6
+#define S_LAZY_SYMBOL_POINTERS 0x7
+#define S_SYMBOL_STUBS 0x8
+#define S_MOD_INIT_FUNC_POINTERS 0x9
+#define S_MOD_TERM_FUNC_POINTERS 0xa
+#define S_COALESCED 0xb
+#define S_GB_ZEROFILL 0xc
+#define S_INTERPOSING 0xd
+#define S_16BYTE_LITERALS 0xe
+#define S_DTRACE_DOF 0xf
+#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
+#define S_THREAD_LOCAL_REGULAR 0x11
+#define S_THREAD_LOCAL_ZEROFILL 0x12
+#define S_THREAD_LOCAL_VARIABLES 0x13
+#define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14
+#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15
+
+//Mach-O Commands
+#define LC_REQ_DYLD 0x80000000
+#define LC_SEGMENT 0x1
+#define LC_SYMTAB 0x2
+#define LC_SYMSEG 0x3
+#define LC_THREAD 0x4
+#define LC_UNIXTHREAD 0x5
+#define LC_LOADFVMLIB 0x6
+#define LC_IDFVMLIB 0x7
+#define LC_IDENT 0x8
+#define LC_FVMFILE 0x9
+#define LC_PREPAGE 0xa
+#define LC_DYSYMTAB 0xb
+#define LC_LOAD_DYLIB 0xc
+#define LC_ID_DYLIB 0xd
+#define LC_LOAD_DYLINKER 0xe
+#define LC_ID_DYLINKER 0xf
+#define LC_PREBOUND_DYLIB 0x10
+#define LC_ROUTINES 0x11
+#define LC_SUB_FRAMEWORK 0x12
+#define LC_SUB_UMBRELLA 0x13
+#define LC_SUB_CLIENT 0x14
+#define LC_SUB_LIBRARY 0x15
+#define LC_TWOLEVEL_HINTS 0x16
+#define LC_PREBIND_CKSUM 0x17
+#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
+#define LC_SEGMENT_64 0x19
+#define LC_ROUTINES_64 0x1a
+#define LC_UUID 0x1b
+#define LC_RPATH (0x1c | LC_REQ_DYLD)
+#define LC_CODE_SIGNATURE 0x1d
+#define LC_SEGMENT_SPLIT_INFO 0x1e
+#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD)
+#define LC_LAZY_LOAD_DYLIB 0x20
+#define LC_ENCRYPTION_INFO 0x21
+#define LC_DYLD_INFO 0x22
+#define LC_DYLD_INFO_ONLY (0x22 | LC_REQ_DYLD)
+#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD)
+#define LC_VERSION_MIN_MACOSX 0x24
+#define LC_VERSION_MIN_IPHONEOS 0x25
+#define LC_FUNCTION_STARTS 0x26
+#define LC_DYLD_ENVIRONMENT 0x27
+#define LC_MAIN (0x28 | LC_REQ_DYLD)
+#define LC_DATA_IN_CODE 0x29
+#define LC_SOURCE_VERSION 0x2a
+#define LC_DYLIB_CODE_SIGN_DRS 0x2b
+#define _LC_ENCRYPTION_INFO_64 0x2c /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
+#define _LC_LINKER_OPTION 0x2d /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
+#define _LC_LINKER_OPTIMIZATION_HINT 0x2e /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
+#define _LC_VERSION_MIN_TVOS 0x2f /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
+#define LC_VERSION_MIN_WATCHOS 0x30
+#define LC_NOTE 0x31
+#define LC_BUILD_VERSION 0x32
+#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD)
+#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD)
+#define LC_FILESET_ENTRY (0x35 | LC_REQ_DYLD)
+
+//Mach-O File types
+#define MH_OBJECT 0x1
+#define MH_EXECUTE 0x2
+#define MH_FVMLIB 0x3
+#define MH_CORE 0x4
+#define MH_PRELOAD 0x5
+#define MH_DYLIB 0x6
+#define MH_DYLINKER 0x7
+#define MH_BUNDLE 0x8
+#define MH_DYLIB_STUB 0x9
+#define MH_DSYM 0xa
+#define MH_KEXT_BUNDLE 0xb
+#define MH_FILESET 0xc
+
+#define MH_NOUNDEFS 0x1
+#define MH_INCRLINK 0x2
+#define MH_DYLDLINK 0x4
+#define MH_BINDATLOAD 0x8
+#define MH_PREBOUND 0x10
+#define MH_SPLIT_SEGS 0x20
+#define MH_LAZY_INIT 0x40
+#define MH_TWOLEVEL 0x80
+#define MH_FORCE_FLAT 0x100
+#define MH_NOMULTIDEFS 0x200
+#define MH_NOFIXPREBINDING 0x400
+#define MH_PREBINDABLE 0x800
+#define MH_ALLMODSBOUND 0x1000
+#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000
+#define MH_CANONICAL 0x4000
+#define MH_WEAK_DEFINES 0x8000
+#define MH_BINDS_TO_WEAK 0x10000
+#define MH_ALLOW_STACK_EXECUTION 0x20000
+#define MH_ROOT_SAFE 0x40000
+#define MH_SETUID_SAFE 0x80000
+#define MH_NO_REEXPORTED_DYLIBS 0x100000
+#define MH_PIE 0x200000
+#define MH_DEAD_STRIPPABLE_DYLIB 0x400000
+#define MH_HAS_TLV_DESCRIPTORS 0x800000
+#define MH_NO_HEAP_EXECUTION 0x1000000
+#define _MH_APP_EXTENSION_SAFE 0x2000000 /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
+#define _MH_NLIST_OUTOFSYNC_WITH_DYLDINFO 0x04000000u
+#define _MH_SIM_SUPPORT 0x08000000u
+#define _MH_DYLIB_IN_CACHE 0x80000000u
+
+//Segment Names
+#define SEG_PAGEZERO "__PAGEZERO"
+#define SEG_TEXT "__TEXT"
+#define SECT_TEXT "__text"
+#define SECT_FVMLIB_INIT0 "__fvmlib_init0"
+#define SECT_FVMLIB_INIT1 "__fvmlib_init1"
+#define SEG_DATA "__DATA"
+#define SECT_DATA "__data"
+#define SECT_BSS "__bss"
+#define SECT_COMMON "__common"
+#define SEG_OBJC "__OBJC"
+#define SECT_OBJC_SYMBOLS "__symbol_table"
+#define SECT_OBJC_MODULES "__module_info"
+#define SECT_OBJC_STRINGS "__selector_strs"
+#define SECT_OBJC_REFS "__selector_refs"
+#define SEG_ICON "__ICON"
+#define SECT_ICON_HEADER "__header"
+#define SECT_ICON_TIFF "__tiff"
+#define SEG_LINKEDIT "__LINKEDIT"
+#define SEG_UNIXSTACK "__UNIXSTACK"
+#define SEG_IMPORT "__IMPORT"
+
+//Symbol Types (N_TYPE)
+#define N_UNDF 0x0
+#define N_ABS 0x2
+#define N_SECT 0xe
+#define N_PBUD 0xc
+#define N_INDR 0xa
+
+#define N_ARM_THUMB_DEF 0x0008
+
+/*
+ * An indirect symbol table entry is simply a 32bit index into the symbol table
+ * to the symbol that the pointer or stub is referring to. Unless it is for a
+ * non-lazy symbol pointer section for a defined symbol which strip(1) as
+ * removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the
+ * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
+ */
+#define INDIRECT_SYMBOL_ABS 0x40000000
+#define INDIRECT_SYMBOL_LOCAL 0x80000000
+
+#define SECTION_TYPE 0x000000ff /* 256 section types */
+#define SECTION_ATTRIBUTES 0xffffff00 /* 24 section attributes */
+
+#define BINARYNINJA_MANUAL_RELOCATION ((uint64_t)-2)
+
+enum MachoRelocationType
+{
+ GENERIC_RELOC_VANILLA = 0,
+ GENERIC_RELOC_PAIR = 1,
+ GENERIC_RELOC_SECTDIFF = 2,
+ GENERIC_RELOC_PB_LA_PTR = 3,
+ GENERIC_RELOC_LOCAL_SECTDIFF = 4,
+ GENERIC_RELOC_TLV = 5
+};
+
+
+namespace BinaryNinja
+{
+ class MachoFormatException: public std::exception
+ {
+ std::string m_message;
+
+ public:
+ MachoFormatException(const std::string& msg = "invalid format"): m_message(msg) {}
+ virtual const char* what() const NOEXCEPT { return m_message.c_str(); }
+ };
+
+ struct FatHeader {
+ uint32_t magic;
+ uint32_t nfat_arch;
+ };
+
+ struct FatArch32 {
+ cpu_type_t cputype;
+ cpu_subtype_t cpusubtype;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t align;
+ };
+
+ struct FatArch64 {
+ cpu_type_t cputype;
+ cpu_subtype_t cpusubtype;
+ uint64_t offset;
+ uint64_t size;
+ uint32_t align;
+ uint32_t reserved;
+ };
+
+ struct mach_header {
+ uint32_t magic;
+ cpu_type_t cputype;
+ cpu_subtype_t cpusubtype;
+ uint32_t filetype;
+ uint32_t ncmds;
+ uint32_t sizeofcmds;
+ uint32_t flags;
+ };
+
+ struct mach_header_64 {
+ uint32_t magic;
+ cpu_type_t cputype;
+ cpu_subtype_t cpusubtype;
+ uint32_t filetype;
+ uint32_t ncmds;
+ uint32_t sizeofcmds;
+ uint32_t flags;
+ uint32_t reserved;
+ };
+
+ struct load_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ };
+
+ struct segment_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ char segname[16];
+ uint32_t vmaddr;
+ uint32_t vmsize;
+ uint32_t fileoff;
+ uint32_t filesize;
+ vm_prot_t maxprot;
+ vm_prot_t initprot;
+ uint32_t nsects;
+ uint32_t flags;
+ };
+
+ struct section { // for 32-bit architectures
+ char sectname[16]; // name of this section
+ char segname[16]; // segment this section goes in
+ uint32_t addr; // memory address of this section
+ uint32_t size; // size in bytes of this section
+ uint32_t offset; // file offset of this section
+ uint32_t align; // section alignment (power of 2)
+ uint32_t reloff; // file offset of relocation entries
+ uint32_t nreloc; // number of relocation entries
+ uint32_t flags; // flags (section type and attributes)
+ uint32_t reserved1; // reserved (for offset or index)
+ uint32_t reserved2; // reserved (for count or sizeof)
+ };
+
+ struct section_64 { // for 64-bit architectures
+ char sectname[16]; // name of this section
+ char segname[16]; // segment this section goes in
+ uint64_t addr; // memory address of this section
+ uint64_t size; // size in bytes of this section
+ uint32_t offset; // file offset of this section
+ uint32_t align; // section alignment (power of 2)
+ uint32_t reloff; // file offset of relocation entries
+ uint32_t nreloc; // number of relocation entries
+ uint32_t flags; // flags (section type and attributes)
+ uint32_t reserved1; // reserved (for offset or index)
+ uint32_t reserved2; // reserved (for count or sizeof)
+ uint32_t reserved3; // reserved
+ };
+
+ struct segment_command_64 {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ char segname[16];
+ uint64_t vmaddr;
+ uint64_t vmsize;
+ uint64_t fileoff;
+ uint64_t filesize;
+ vm_prot_t maxprot;
+ vm_prot_t initprot;
+ uint32_t nsects;
+ uint32_t flags;
+ };
+
+ struct uuid_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ char uuid[16];
+ };
+
+ struct fvmlib_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ char segname[16];
+ uint32_t minor_version;
+ uint32_t header_addr;
+ };
+
+ struct dylib {
+ uint32_t name;
+ uint32_t timestamp;
+ uint32_t current_version;
+ uint32_t compatibility_version;
+ };
+
+ struct dylib_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ struct dylib dylib;
+ };
+
+ struct sub_framework_command {
+ uint32_t cmd; // LC_SUB_FRAMEWORK
+ uint32_t cmdsize; // includes umbrella string
+ uint32_t umbrella; // the umbrella framework name
+ };
+
+ struct sub_client_command {
+ uint32_t cmd; // LC_SUB_CLIENT
+ uint32_t cmdsize; // includes client string
+ uint32_t client; // offset to the string
+ };
+
+ struct sub_umbrella_command {
+ uint32_t cmd; // LC_SUB_UMBRELLA
+ uint32_t cmdsize; // includes sub_umbrella string
+ uint32_t sub_umbrella; // the sub_umbrella framework name
+ };
+
+ struct sub_library_command {
+ uint32_t cmd; // LC_SUB_LIBRARY
+ uint32_t cmdsize; // includes sub_library string
+ uint32_t sub_library; // the sub_library name
+ };
+
+ struct prebound_dylib_command {
+ uint32_t cmd; // LC_PREBOUND_DYLIB
+ uint32_t cmdsize; // includes strings
+ uint32_t name; // library's path name
+ uint32_t nmodules; // number of modules in library
+ uint32_t linked_modules; // bit vector of linked modules
+ };
+
+ struct dylinker_command {
+ uint32_t cmd; // LC_ID_DYLINKER or LC_LOAD_DYLINKER
+ uint32_t cmdsize; // includes pathname string
+ uint32_t name; // dynamic linker's path name
+ };
+
+ struct x86_thread_state64 {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct x86_thread_state32 {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct armv7_thread_state {
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t r12;
+ uint32_t r13;
+ uint32_t r14; //SP
+ uint32_t r15; //PC
+ };
+
+ struct arm_thread_state64 {
+ uint64_t x[29]; // GPR x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // Program Counter
+ uint32_t cpsr; // Current program status register
+ };
+
+ struct ppc_thread_state {
+ uint32_t srr0; //Machine state register (PC)
+ uint32_t srr1;
+ uint32_t r0;
+ uint32_t r1; //Stack pointer
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t r12;
+ uint32_t r13;
+ uint32_t r14;
+ uint32_t r15;
+ uint32_t r16;
+ uint32_t r17;
+ uint32_t r18;
+ uint32_t r19;
+ uint32_t r20;
+ uint32_t r21;
+ uint32_t r22;
+ uint32_t r23;
+ uint32_t r24;
+ uint32_t r25;
+ uint32_t r26;
+ uint32_t r27;
+ uint32_t r28;
+ uint32_t r29;
+ uint32_t r30;
+ uint32_t r31;
+ uint32_t cr;
+ uint32_t xer;
+ uint32_t lr;
+ uint32_t ctr;
+ uint32_t mq;
+ uint32_t vrsave;
+ };
+
+ #pragma pack(push, 4)
+ struct ppc_thread_state64 {
+ uint64_t srr0; //Machine state register (PC)
+ uint64_t srr1;
+ uint64_t r0; //Stack pointer
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+ uint32_t cr; // Condition register
+ uint64_t xer; // User's integer exception register
+ uint64_t lr; // Link register
+ uint64_t ctr; // Count register
+ uint32_t vrsave; // Vector Save Register
+ };
+ #pragma pack(pop)
+
+ struct thread_command {
+ uint32_t cmd; // LC_THREAD or LC_UNIXTHREAD
+ uint32_t cmdsize; // total size of this command
+ uint32_t flavor; // flavor of thread state
+ uint32_t count; //count of longs in thread state
+ union {
+ x86_thread_state64 statex64;
+ x86_thread_state32 statex86;
+ armv7_thread_state statearmv7;
+ arm_thread_state64 stateaarch64;
+ ppc_thread_state stateppc;
+ ppc_thread_state64 stateppc64;
+ };
+ };
+
+ struct linkedit_data_command {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ uint32_t dataoff;
+ uint32_t datasize;
+ };
+
+
+ enum MachOArchitecture {
+ MachOABIMask = 0xff000000,
+ MachOABI64 = 0x01000000, // 64 bit ABI
+ MachOABI6432 = 0x02000000, // "ABI for 64-bit hardware with 32-bit types; LP32"
+
+ // Constants for the cputype field.
+ MachOx86 = 7,
+ MachOx64 = MachOx86 | MachOABI64,
+ MachOArm = 0xc,
+ MachOAarch64 = MachOABI64 | MachOArm,
+ MachOAarch6432 = MachOABI6432 | MachOArm,
+ MachOSPARC = 0xe,
+ MachOPPC = 0x12,
+ MachOPPC64 = MachOABI64 | MachOPPC,
+ };
+
+ enum BindOpcode {
+ BindOpcodeMask = 0xF0u, // BIND_OPCODE_MASK
+ BindImmediateMask = 0x0Fu, // BIND_IMMEDIATE_MASK
+ BindOpcodeDone = 0x00u, // BIND_OPCODE_DONE
+ BindOpcodeSetDylibOrdinalImmediate = 0x10u, // BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+ BindOpcodeSetDylibOrdinalULEB = 0x20u, // BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
+ BindOpcodeSetDylibSpecialImmediate = 0x30u, // BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
+ BindOpcodeSetSymbolTrailingFlagsImmediate = 0x40u, // BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ BindOpcodeSetTypeImmediate = 0x50u, // BIND_OPCODE_SET_TYPE_IMM
+ BindOpcodeSetAddendSLEB = 0x60u, // BIND_OPCODE_SET_ADDEND_SLEB
+ BindOpcodeSetSegmentAndOffsetULEB = 0x70u, // BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ BindOpcodeAddAddressULEB = 0x80u, // BIND_OPCODE_ADD_ADDR_ULEB
+ BindOpcodeDoBind = 0x90u, // BIND_OPCODE_DO_BIND
+ BindOpcodeDoBindAddAddressULEB = 0xA0u, // BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
+ BindOpcodeDoBindAddAddressImmediateScaled = 0xB0u, // BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
+ BindOpcodeDoBindULEBTimesSkippingULEB = 0xC0u, // BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
+ };
+
+ enum X86ThreadFlavor {
+ X86_THREAD_STATE32 = 0x1,
+ X86_FLOAT_STATE32 = 0x2,
+ X86_EXCEPTION_STATE32 = 0x3,
+ X86_THREAD_STATE64 = 0x4,
+ X86_FLOAT_STATE64 = 0x5,
+ X86_EXCEPTION_STATE64 = 0x6,
+ X86_THREAD_STATE = 0x7,
+ X86_FLOAT_STATE = 0x8,
+ X86_EXCEPTION_STATE = 0x9,
+ X86_DEBUG_STATE32 = 0xA,
+ X86_DEBUG_STATE64 = 0xB,
+ X86_DEBUG_STATE = 0xC,
+ _THREAD_STATE_NONE = 0xD
+ };
+
+ enum PPCThreadFlavor {
+ PPC_THREAD_STATE = 0x1,
+ PPC_FLOAT_STATE = 0x2,
+ PPC_EXCEPTION_STATE = 0x3,
+ PPC_VECTOR_STATE = 0x4,
+ PPC_THREAD_STATE64 = 0x5,
+ PPC_EXCEPTION_STATE64 = 0x6
+ };
+
+ enum ARMThreadFlavor
+ {
+ _ARM_THREAD_STATE = 1,
+ _ARM_VFP_STATE = 2,
+ _ARM_EXCEPTION_STATE = 3,
+ _ARM_DEBUG_STATE = 4, /* pre-armv8 */
+ _ARM_THREAD_STATE64 = 6,
+ _ARM_EXCEPTION_STATE64 = 7
+ };
+
+ struct routines_command { // for 32-bit architectures
+ uint32_t cmd; // LC_ROUTINES
+ uint32_t cmdsize; // total size of this command
+ uint32_t init_address; // address of initialization routine
+ uint32_t init_module; // index into the module table that the init routine is defined in
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+ uint32_t reserved4;
+ uint32_t reserved5;
+ uint32_t reserved6;
+ };
+
+ struct routines_command_64 { // for 64-bit architectures
+ uint32_t cmd; // LC_ROUTINES_64
+ uint32_t cmdsize; // total size of this command
+ uint64_t init_address; // address of initialization routine
+ uint64_t init_module; // index into the module table that the init routine is defined in
+ uint64_t reserved1;
+ uint64_t reserved2;
+ uint64_t reserved3;
+ uint64_t reserved4;
+ uint64_t reserved5;
+ uint64_t reserved6;
+ };
+
+ struct symtab_command {
+ uint32_t cmd; // LC_SYMTAB
+ uint32_t cmdsize; // sizeof(struct symtab_command)
+ uint32_t symoff; // symbol table offset
+ uint32_t nsyms; // number of symbol table entries
+ uint32_t stroff; // string table offset
+ uint32_t strsize; // string table size in bytes
+ };
+
+ // Lots of good information on how to use dysymtab for relocations
+ // https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/loader.h
+ struct dysymtab_command {
+ uint32_t cmd; // LC_DYSYMTAB
+ uint32_t cmdsize; // sizeof(struct dysymtab_command)
+ uint32_t ilocalsym; // index to local symbols
+ uint32_t nlocalsym; // number of local symbols
+ uint32_t iextdefsym; // index to externally defined symbols
+ uint32_t nextdefsym; // number of externally defined symbols
+ uint32_t iundefsym; // index to undefined symbols
+ uint32_t nundefsym; // number of undefined symbols
+ uint32_t tocoff; // file offset to table of contents
+ uint32_t ntoc; // number of entries in table of contents
+ uint32_t modtaboff; // file offset to module table
+ uint32_t nmodtab; // number of module table entries
+ uint32_t extrefsymoff; // offset to referenced symbol table
+ uint32_t nextrefsyms; // number of referenced symbol table entries
+ uint32_t indirectsymoff; // file offset to the indirect symbol table
+ uint32_t nindirectsyms; // number of indirect symbol table entries
+ uint32_t extreloff; // offset to external relocation entries
+ uint32_t nextrel; // number of external relocation entries
+ uint32_t locreloff; // offset to local relocation entries
+ uint32_t nlocrel; // number of local relocation entries
+ };
+
+ struct twolevel_hints_command {
+ uint32_t cmd; // LC_TWOLEVEL_HINTS
+ uint32_t cmdsize; // sizeof(struct twolevel_hints_command)
+ uint32_t offset; // offset to the hint table
+ uint32_t nhints; // number of hints in the hint table
+ };
+
+ struct dyld_info_command {
+ uint32_t cmd; // LC_DYLD_INFO or LC_DYLD_INFO_ONLY
+ uint32_t cmdsize; // sizeof(struct dyld_info_command)
+ uint32_t rebase_off; // file offset to rebase info
+ uint32_t rebase_size; // size of rebase info
+ uint32_t bind_off; // file offset to binding info
+ uint32_t bind_size; // size of binding info
+ uint32_t weak_bind_off; // file offset to weak binding info
+ uint32_t weak_bind_size; // size of weak binding info
+ uint32_t lazy_bind_off; // file offset to lazy binding info
+ uint32_t lazy_bind_size; // size of lazy binding infs
+ uint32_t export_off; // file offset to lazy binding info
+ uint32_t export_size; // size of lazy binding infs
+ };
+
+ struct function_starts_command {
+ uint32_t cmd; //LC_FUNCTION_STARTS
+ uint32_t cmdsize; //sizeof(struct function_starts_command)
+ uint32_t funcoff; //offset to function starts list
+ uint32_t funcsize; //sizeof function starts list
+ };
+
+ enum MachoPlatform {
+ MACHO_PLATFORM_MACOS = 1,
+ MACHO_PLATFORM_IOS = 2,
+ MACHO_PLATFORM_TVOS = 3,
+ MACHO_PLATFORM_WATCHOS = 4,
+ MACHO_PLATFORM_BRIDGEOS = 5
+ };
+
+ enum MachoBuildTool {
+ MACHO_TOOL_CLANG = 1,
+ MACHO_TOOL_SWIFT = 2,
+ MACHO_TOOL_LD = 3
+ };
+
+ struct build_tool_version {
+ uint32_t tool;
+ uint32_t version;
+ };
+
+ struct build_version_command {
+ uint32_t cmd; // LC_BUILD_VERSION
+ uint32_t cmdsize; // sizeof(build_version_command) + (ntools * sizeof(build_tool_version)
+ uint32_t platform; // MachoPlatform
+ uint32_t minos; // X.Y.Z is encoded in nibbles xxxx.yy.zz
+ uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
+ uint32_t ntools; // number build_tool_version entries
+ };
+
+#pragma pack(push, 1)
+ struct nlist {
+ int32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_sect;
+ int16_t n_desc;
+ uint32_t n_value;
+ };
+
+ struct nlist_64 {
+ uint32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_sect;
+ uint16_t n_desc;
+ uint64_t n_value;
+ };
+#pragma pack(pop)
+
+#define R_ABS 0
+ struct relocation_info
+ {
+ int32_t r_address;
+ uint32_t r_symbolnum:24;
+ uint32_t r_pcrel:1;
+ uint32_t r_length:2;
+ uint32_t r_extern:1;
+ uint32_t r_type:4;
+ };
+#define R_SCATTERED 0x80000000
+ struct scattered_relocation_info_be_64 {
+ uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
+ uint32_t r_pcrel:1; // was relocated pc relative already
+ uint32_t r_length:2; // 0=byte, 1=word, 2=long
+ uint32_t r_type:4; // if not 0, machine specific relocation type
+ uint32_t r_address:24; // offset in the section to what is being relocated
+ int64_t r_value; // the value the item to be relocated is refering to (without any offset added)
+ };
+ struct scattered_relocation_info_le_64 {
+ uint32_t r_address:24; // offset in the section to what is being relocated
+ uint32_t r_type:4; // if not 0, machine specific relocation type
+ uint32_t r_length:2; // 0=byte, 1=word, 2=long
+ uint32_t r_pcrel:1; // was relocated pc relative already
+ uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
+ int64_t r_value; // the value the item to be relocated is refering to (without any offset added)
+ };
+ struct scattered_relocation_info_be {
+ uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
+ uint32_t r_pcrel:1; // was relocated pc relative already
+ uint32_t r_length:2; // 0=byte, 1=word, 2=long
+ uint32_t r_type:4; // if not 0, machine specific relocation type
+ uint32_t r_address:24; // offset in the section to what is being relocated
+ int32_t r_value; // the value the item to be relocated is refering to (without any offset added)
+ };
+ struct scattered_relocation_info_le {
+ uint32_t r_address:24; // offset in the section to what is being relocated
+ uint32_t r_type:4; // if not 0, machine specific relocation type
+ uint32_t r_length:2; // 0=byte, 1=word, 2=long
+ uint32_t r_pcrel:1; // was relocated pc relative already
+ uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
+ int32_t r_value; // the value the item to be relocated is refering to (without any offset added)
+ };
+
+ enum reloc_type_generic
+ {
+ GENERIC_RELOC_VANILLA, // generic relocation as discribed above
+ GENERIC_RELOC_PAIR, // Only follows a GENRIC_RELOC_SECTDIFF
+ GENERIC_RELOC_SECTDIFF,
+ GENERIC_RELOC_PB_LA_PTR // prebound lazy pointer
+ };
+
+ struct dyld_chained_fixups_header
+ {
+ uint32_t fixups_version; // 0
+ uint32_t starts_offset; // offset of dyld_chained_starts_in_image in chain_data
+ uint32_t imports_offset; // offset of imports table in chain_data
+ uint32_t symbols_offset; // offset of symbol strings in chain_data
+ uint32_t imports_count; // number of imported symbol names
+ uint32_t imports_format; // DYLD_CHAINED_IMPORT*
+ uint32_t symbols_format; // 0 => uncompressed, 1 => zlib compressed
+ };
+
+ // This struct is embedded in LC_DYLD_CHAINED_FIXUPS payload
+ struct dyld_chained_starts_in_image
+ {
+ uint32_t seg_count;
+ uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment
+ // followed by pool of dyld_chain_starts_in_segment data
+ };
+
+ // This struct is embedded in dyld_chain_starts_in_image
+ // and passed down to the kernel for page-in linking
+ struct dyld_chained_starts_in_segment
+ {
+ uint32_t size; // size of this (amount kernel needs to copy)
+ uint16_t page_size; // 0x1000 or 0x4000
+ uint16_t pointer_format; // DYLD_CHAINED_PTR_*
+ uint64_t segment_offset; // offset in memory to start of segment
+ uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer
+ uint16_t page_count; // how many pages are in array
+ uint16_t page_start[1]; // each entry is offset in each page of first element in chain
+ // or DYLD_CHAINED_PTR_START_NONE if no fixups on page
+
+ // uint16_t chain_starts[1]; // some 32-bit formats may require multiple starts per page.
+ // for those, if high bit is set in page_starts[], then it
+ // is index into chain_starts[] which is a list of starts
+ // the last of which has the high bit set
+ };
+
+ enum {
+ DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups
+ DYLD_CHAINED_PTR_START_MULTI = 0x8000, // used in page_start[] to denote a page which has multiple starts
+ DYLD_CHAINED_PTR_START_LAST = 0x8000, // used in chain_starts[] to denote last start in list for page
+ };
+
+ // This struct is embedded in __TEXT,__chain_starts section in firmware
+ struct dyld_chained_starts_offsets
+ {
+ uint32_t pointer_format; // DYLD_CHAINED_PTR_32_FIRMWARE
+ uint32_t starts_count; // number of starts in array
+ uint32_t chain_starts[1]; // array chain start offsets
+ };
+
+ // values for dyld_chained_starts_in_segment.pointer_format
+ enum {
+ DYLD_CHAINED_PTR_ARM64E = 1, // stride 8, unauth target is vmaddr
+ DYLD_CHAINED_PTR_64 = 2, // target is vmaddr
+ DYLD_CHAINED_PTR_32 = 3,
+ DYLD_CHAINED_PTR_32_CACHE = 4,
+ DYLD_CHAINED_PTR_32_FIRMWARE = 5,
+ DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset
+ DYLD_CHAINED_PTR_ARM64E_OFFSET = 7, // old name
+ DYLD_CHAINED_PTR_ARM64E_KERNEL = 7, // stride 4, unauth target is vm offset
+ DYLD_CHAINED_PTR_64_KERNEL_CACHE = 8,
+ DYLD_CHAINED_PTR_ARM64E_USERLAND = 9, // stride 8, unauth target is vm offset
+ DYLD_CHAINED_PTR_ARM64E_FIRMWARE = 10, // stride 4, unauth target is vmaddr
+ DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE = 11, // stride 1, x86_64 kernel caches
+ DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12, // stride 8, unauth target is vm offset, 24-bit bind
+ };
+
+ // DYLD_CHAINED_PTR_ARM64E
+ struct dyld_chained_ptr_arm64e_rebase
+ {
+ uint64_t target : 43,
+ high8 : 8,
+ next : 11, // 4 or 8-byte stide
+ bind : 1, // == 0
+ auth : 1; // == 0
+ };
+
+ // DYLD_CHAINED_PTR_ARM64E
+ struct dyld_chained_ptr_arm64e_bind
+ {
+ uint64_t ordinal : 16,
+ zero : 16,
+ addend : 19, // +/-256K
+ next : 11, // 4 or 8-byte stide
+ bind : 1, // == 1
+ auth : 1; // == 0
+ };
+
+ // DYLD_CHAINED_PTR_ARM64E
+ struct dyld_chained_ptr_arm64e_auth_rebase
+ {
+ uint64_t target : 32, // runtimeOffset
+ diversity : 16,
+ addrDiv : 1,
+ key : 2,
+ next : 11, // 4 or 8-byte stide
+ bind : 1, // == 0
+ auth : 1; // == 1
+ };
+
+ // DYLD_CHAINED_PTR_ARM64E
+ struct dyld_chained_ptr_arm64e_auth_bind
+ {
+ uint64_t ordinal : 16,
+ zero : 16,
+ diversity : 16,
+ addrDiv : 1,
+ key : 2,
+ next : 11, // 4 or 8-byte stide
+ bind : 1, // == 1
+ auth : 1; // == 1
+ };
+
+ // DYLD_CHAINED_PTR_64/DYLD_CHAINED_PTR_64_OFFSET
+ struct dyld_chained_ptr_64_rebase
+ {
+ uint64_t target : 36, // 64GB max image size (DYLD_CHAINED_PTR_64 => vmAddr, DYLD_CHAINED_PTR_64_OFFSET => runtimeOffset)
+ high8 : 8, // top 8 bits set to this (DYLD_CHAINED_PTR_64 => after slide added, DYLD_CHAINED_PTR_64_OFFSET => before slide added)
+ reserved : 7, // all zeros
+ next : 12, // 4-byte stride
+ bind : 1; // == 0
+ };
+
+
+ // DYLD_CHAINED_PTR_ARM64E_USERLAND24
+ struct dyld_chained_ptr_arm64e_bind24
+ {
+ uint64_t ordinal : 24,
+ zero : 8,
+ addend : 19, // +/-256K
+ next : 11, // 8-byte stide
+ bind : 1, // == 1
+ auth : 1; // == 0
+ };
+
+ // DYLD_CHAINED_PTR_ARM64E_USERLAND24
+ struct dyld_chained_ptr_arm64e_auth_bind24
+ {
+ uint64_t ordinal : 24,
+ zero : 8,
+ diversity : 16,
+ addrDiv : 1,
+ key : 2,
+ next : 11, // 8-byte stide
+ bind : 1, // == 1
+ auth : 1; // == 1
+ };
+
+
+ // DYLD_CHAINED_PTR_64
+ struct dyld_chained_ptr_64_bind
+ {
+ uint64_t ordinal : 24,
+ addend : 8, // 0 thru 255
+ reserved : 19, // all zeros
+ next : 12, // 4-byte stride
+ bind : 1; // == 1
+ };
+
+ // DYLD_CHAINED_PTR_64_KERNEL_CACHE, DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE
+ struct dyld_chained_ptr_64_kernel_cache_rebase
+ {
+ uint64_t target : 30, // basePointers[cacheLevel] + target
+ cacheLevel : 2, // what level of cache to bind to (indexes a mach_header array)
+ diversity : 16,
+ addrDiv : 1,
+ key : 2,
+ next : 12, // 1 or 4-byte stide
+ isAuth : 1; // 0 -> not authenticated. 1 -> authenticated
+ };
+
+ // DYLD_CHAINED_PTR_32
+ // Note: for DYLD_CHAINED_PTR_32 some non-pointer values are co-opted into the chain
+ // as out of range rebases. If an entry in the chain is > max_valid_pointer, then it
+ // is not a pointer. To restore the value, subtract off the bias, which is
+ // (64MB+max_valid_pointer)/2.
+ struct dyld_chained_ptr_32_rebase
+ {
+ uint32_t target : 26, // vmaddr, 64MB max image size
+ next : 5, // 4-byte stride
+ bind : 1; // == 0
+ };
+
+ // DYLD_CHAINED_PTR_32
+ struct dyld_chained_ptr_32_bind
+ {
+ uint32_t ordinal : 20,
+ addend : 6, // 0 thru 63
+ next : 5, // 4-byte stride
+ bind : 1; // == 1
+ };
+
+ // DYLD_CHAINED_PTR_32_CACHE
+ struct dyld_chained_ptr_32_cache_rebase
+ {
+ uint32_t target : 30, // 1GB max dyld cache TEXT and DATA
+ next : 2; // 4-byte stride
+ };
+
+
+ // DYLD_CHAINED_PTR_32_FIRMWARE
+ struct dyld_chained_ptr_32_firmware_rebase
+ {
+ uint32_t target : 26, // 64MB max firmware TEXT and DATA
+ next : 6; // 4-byte stride
+ };
+
+ enum ChainedFixupPointerGeneric {
+ GenericArm64eFixupFormat,
+ Generic64FixupFormat,
+ Generic32FixupFormat,
+ Firmware32FixupFormat
+ };
+
+ union Arm64e {
+ dyld_chained_ptr_arm64e_auth_rebase authRebase;
+ dyld_chained_ptr_arm64e_auth_bind authBind;
+ dyld_chained_ptr_arm64e_rebase rebase;
+ dyld_chained_ptr_arm64e_bind bind;
+ dyld_chained_ptr_arm64e_bind24 bind24;
+ dyld_chained_ptr_arm64e_auth_bind24 authBind24;
+ };
+
+ union Generic64 {
+ dyld_chained_ptr_64_rebase rebase;
+ dyld_chained_ptr_64_bind bind;
+ };
+
+ union Generic32 {
+ dyld_chained_ptr_32_rebase rebase;
+ dyld_chained_ptr_32_bind bind;
+ };
+
+ union ChainedFixupPointer
+ {
+ dyld_chained_ptr_64_kernel_cache_rebase kernel64;
+ dyld_chained_ptr_32_firmware_rebase firmware32;
+
+ uint64_t raw64;
+ Arm64e arm64e;
+ Generic64 generic64;
+
+ uint32_t raw32;
+ Generic32 generic32;
+ dyld_chained_ptr_32_cache_rebase cache32;
+ };
+
+ // values for dyld_chained_fixups_header.imports_format
+ enum {
+ DYLD_CHAINED_IMPORT = 1,
+ DYLD_CHAINED_IMPORT_ADDEND = 2,
+ DYLD_CHAINED_IMPORT_ADDEND64 = 3,
+ };
+
+ // DYLD_CHAINED_IMPORT
+ struct dyld_chained_import
+ {
+ uint32_t lib_ordinal : 8,
+ weak_import : 1,
+ name_offset : 23;
+ };
+
+ // DYLD_CHAINED_IMPORT_ADDEND
+ struct dyld_chained_import_addend
+ {
+ uint32_t lib_ordinal : 8,
+ weak_import : 1,
+ name_offset : 23;
+ int32_t addend;
+ };
+
+ // DYLD_CHAINED_IMPORT_ADDEND64
+ struct dyld_chained_import_addend64
+ {
+ uint64_t lib_ordinal : 16,
+ weak_import : 1,
+ reserved : 15,
+ name_offset : 32;
+ uint64_t addend;
+ };
+
+ // When we preload the table, we store them in this format.
+ struct import_entry
+ {
+ uint64_t lib_ordinal;
+ uint64_t addend;
+ bool weak;
+ std::string name;
+ };
+
+#ifndef EXPORT_SYMBOL_FLAGS_KIND_MASK
+ enum EXPORT_SYMBOL_FLAGS {
+ EXPORT_SYMBOL_FLAGS_KIND_MASK = 0x03u, ///< Mask to access to EXPORT_SYMBOL_KINDS
+ EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION = 0x04u,
+ EXPORT_SYMBOL_FLAGS_REEXPORT = 0x08u,
+ EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER = 0x10u
+ };
+
+ enum EXPORT_SYMBOL_KINDS {
+ EXPORT_SYMBOL_FLAGS_KIND_REGULAR = 0x00u,
+ EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL = 0x01u,
+ EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE = 0x02u
+ };
+#endif
+
+ struct MachOHeader {
+ bool isMainHeader;
+
+ uint64_t textBase = 0;
+ uint64_t loadCommandOffset = 0;
+ mach_header_64 ident;
+ std::string identifierPrefix;
+
+ std::vector<std::pair<uint64_t, bool>> entryPoints;
+ std::vector<uint64_t> m_entryPoints; //list of entrypoints
+
+ symtab_command symtab;
+ dysymtab_command dysymtab;
+ dyld_info_command dyldInfo;
+ routines_command_64 routines64;
+ function_starts_command functionStarts;
+ std::vector<section_64> moduleInitSections;
+ linkedit_data_command exportTrie;
+ linkedit_data_command chainedFixups {};
+
+ DataBuffer* stringList;
+ size_t stringListSize;
+
+ uint64_t relocationBase;
+ // Section and program headers, internally use 64-bit form as it is a superset of 32-bit
+ std::vector<segment_command_64> segments; //only three types of sections __TEXT, __DATA, __IMPORT
+ std::vector<section_64> sections;
+ std::vector<std::string> sectionNames;
+
+ std::vector<section_64> symbolStubSections;
+ std::vector<section_64> symbolPointerSections;
+
+ std::vector<std::string> dylibs;
+
+ build_version_command buildVersion;
+ std::vector<build_tool_version> buildToolVersions;
+
+ bool dysymPresent = false;
+ bool dyldInfoPresent = false;
+ bool exportTriePresent = false;
+ bool chainedFixupsPresent = false;
+ bool routinesPresent = false;
+ bool functionStartsPresent = false;
+ bool relocatable = false;
+ };
+
+ class MachoView: public BinaryView
+ {
+ MachOHeader m_header;
+ std::map<uint64_t, MachOHeader> m_subHeaders; // Used for MH_FILESET entries.
+
+ struct HeaderQualifiedNames {
+ QualifiedName cpuTypeEnumQualName;
+ QualifiedName fileTypeEnumQualName;
+ QualifiedName flagsTypeEnumQualName;
+ QualifiedName headerQualName;
+ QualifiedName cmdTypeEnumQualName;
+ QualifiedName loadCommandQualName;
+ QualifiedName protTypeEnumQualName;
+ QualifiedName segFlagsTypeEnumQualName;
+ QualifiedName loadSegmentCommandQualName;
+ QualifiedName loadSegment64CommandQualName;
+ QualifiedName sectionQualName;
+ QualifiedName section64QualName;
+ QualifiedName symtabQualName;
+ QualifiedName dynsymtabQualName;
+ QualifiedName uuidQualName;
+ QualifiedName linkeditDataQualName;
+ QualifiedName encryptionInfoQualName;
+ QualifiedName versionMinQualName;
+ QualifiedName dyldInfoQualName;
+ QualifiedName dylibQualName;
+ QualifiedName dylibCommandQualName;
+ QualifiedName filesetEntryCommandQualName;
+ } m_typeNames;
+
+ uint64_t m_universalImageOffset;
+ bool m_parseOnly, m_backedByDatabase;
+ int64_t m_imageBaseAdjustment;
+ size_t m_addressSize; //Address size in bytes 4/8
+ BNEndianness m_endian;
+ uint32_t m_archId;
+ Ref<Architecture> m_arch;
+ Ref<Platform> m_plat = nullptr;
+ bool m_dylibFile;
+ bool m_objectFile;
+ std::vector<std::string> m_symbols;
+
+ bool m_relocatable = false;
+
+ bool m_extractMangledTypes;
+ bool m_simplifyTemplates;
+
+ SymbolQueue* m_symbolQueue = nullptr;
+ Ref<Logger> m_logger;
+
+ std::vector<segment_command_64> m_allSegments; //only three types of sections __TEXT, __DATA, __IMPORT
+ std::vector<section_64> m_allSections;
+
+ MachOHeader HeaderForAddress(BinaryView* data, uint64_t address, bool isMainHeader, std::string identifierPrefix = "");
+ bool InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_t preferredImageBase, std::string preferredImageBaseDesc);
+
+ void RebaseThreadStarts(BinaryReader& virtualReader, std::vector<uint32_t>& threadStarts, uint64_t stepMultiplier);
+ Ref<Symbol> DefineMachoSymbol(
+ BNSymbolType type, const std::string& name, uint64_t addr, BNSymbolBinding binding, bool deferred);
+ void ParseSymbolTable(BinaryReader& reader, MachOHeader& header, const symtab_command& symtab, const std::vector<uint32_t>& symbolStubsList);
+ bool IsValidFunctionStart(uint64_t addr);
+ void ParseFunctionStarts(Platform* platform, uint64_t textBase, function_starts_command functionStarts);
+ bool ParseRelocationEntry(const relocation_info& info, uint64_t start, BNRelocationInfo& result);
+
+ void ParseExportTrie(BinaryReader& reader, linkedit_data_command exportTrie);
+ void ReadExportNode(uint64_t viewStart, DataBuffer& buffer, const std::string& currentText,
+ size_t cursor, uint32_t endGuard);
+
+ void ParseDynamicTable(BinaryReader& reader, MachOHeader& header, BNSymbolType type, uint32_t tableOffset, uint32_t tableSize,
+ BNSymbolBinding binding);
+ bool GetSectionPermissions(MachOHeader& header, uint64_t address, uint32_t &flags);
+ bool GetSegmentPermissions(MachOHeader& header, uint64_t address, uint32_t &flags);
+ void ParseChainedFixups(linkedit_data_command chainedFixups);
+
+ virtual uint64_t PerformGetEntryPoint() const override;
+
+ virtual bool PerformIsExecutable() const override { return true; }
+ virtual BNEndianness PerformGetDefaultEndianness() const override;
+ virtual bool PerformIsRelocatable() const override;
+ virtual size_t PerformGetAddressSize() const override;
+ public:
+ MachoView(const std::string& typeName, BinaryView* data, bool parseOnly = false);
+
+ virtual bool Init() override;
+ };
+
+ class MachoViewType: public BinaryViewType
+ {
+ Ref<Logger> m_logger;
+ public:
+ MachoViewType();
+ virtual Ref<BinaryView> Create(BinaryView* data) override;
+ virtual Ref<BinaryView> Parse(BinaryView* data) override;
+ virtual bool IsTypeValidForData(BinaryView* data) override;
+ virtual uint64_t ParseHeaders(BinaryView* data, uint64_t imageOffset, mach_header_64& ident, Ref<Architecture>* arch, Ref<Platform>* platform, std::string& errorMsg);
+ virtual Ref<Settings> GetLoadSettingsForData(BinaryView* data) override;
+ };
+
+ void InitMachoViewType();
+}