syntax = "proto2";
import "yara.proto";
import "yaml.proto";

package macho;

option (yara.module_options) = {
  name : "macho"
  root_message: "macho.Macho"
  rust_module: "macho"
  cargo_feature: "macho-module"
};

message MinVersion {
  optional DEVICE_TYPE device = 1;
  optional string version = 2;
  optional string sdk = 3;
}

message BuildVersion {
  optional uint32 platform = 1;
  optional string minos = 2;
  optional string sdk = 3;
  optional uint32 ntools = 4;
  repeated BuildTool tools = 5;
}

message BuildTool {
  optional uint32 tool = 1;
  optional string version = 2;
}

message LinkedItData {
  optional uint32 dataoff = 1;
  optional uint32 datasize = 2;
}

message Certificates {
  repeated string common_names = 1;
  repeated string signer_names = 2;
}

message Dylib {
  required bytes name = 1;
  required uint32 timestamp = 2 [(yaml.field).fmt = "t"];
  required string compatibility_version = 3;
  required string current_version = 4;
}

message DyldInfo {
  optional uint32 rebase_off = 1;
  optional uint32 rebase_size = 2;
  optional uint32 bind_off = 3;
  optional uint32 bind_size = 4;
  optional uint32 weak_bind_off = 5;
  optional uint32 weak_bind_size = 6;
  optional uint32 lazy_bind_off = 7;
  optional uint32 lazy_bind_size = 8;
  optional uint32 export_off = 9;
  optional uint32 export_size = 10;
}

message Symtab {
  optional uint32 symoff = 1;
  optional uint32 nsyms = 2;
  optional uint32 stroff = 3;
  optional uint32 strsize = 4;
  repeated bytes entries = 5;
}

message Dysymtab {
  optional uint32 ilocalsym = 3;
  optional uint32 nlocalsym = 4;
  optional uint32 iextdefsym = 5;
  optional uint32 nextdefsym = 6;
  optional uint32 iundefsym = 7;
  optional uint32 nundefsym = 8;
  optional uint32 tocoff = 9;
  optional uint32 ntoc = 10;
  optional uint32 modtaboff = 11;
  optional uint32 nmodtab = 12;
  optional uint32 extrefsymoff = 13;
  optional uint32 nextrefsyms = 14;
  optional uint32 indirectsymoff = 15;
  optional uint32 nindirectsyms = 16;
  optional uint32 extreloff = 17;
  optional uint32 nextrel = 18;
  optional uint32 locreloff = 19;
  optional uint32 nlocrel = 20;
}

message Section {
  optional bytes segname = 1;
  optional bytes sectname = 2;
  optional uint64 addr = 3 [(yaml.field).fmt = "x"];
  optional uint64 size = 4 [(yaml.field).fmt = "x"];
  optional uint32 offset = 5;
  optional uint32 align = 6;
  optional uint32 reloff = 7;
  optional uint32 nreloc = 8;
  optional uint32 flags = 9 [(yaml.field).fmt = "x"];
  optional uint32 reserved1 = 10;
  optional uint32 reserved2 = 11;
  optional uint32 reserved3 = 12;
}

message Segment {
  optional bytes segname = 3;
  optional uint64 vmaddr = 4 [(yaml.field).fmt = "x"];
  optional uint64 vmsize = 5 [(yaml.field).fmt = "x"];
  optional uint64 fileoff = 6;
  optional uint64 filesize = 7;
  optional uint32 maxprot = 8 [(yaml.field).fmt = "x"];
  optional uint32 initprot = 9 [(yaml.field).fmt = "x"];
  optional uint32 nsects = 10;
  optional uint32 flags = 11 [(yaml.field).fmt = "flags:SEGMENT_FLAG"];
  repeated Section sections = 12;
}

message FatArch {
  optional uint32 cputype = 1 [(yaml.field).fmt = "x"];
  optional uint32 cpusubtype = 2 [(yaml.field).fmt = "x"];
  optional uint64 offset = 3;
  optional uint64 size = 4;
  optional uint32 align = 5;
  optional uint32 reserved = 6;
}

message File {
  optional uint32 magic = 1 [(yaml.field).fmt = "x"];
  optional uint32 cputype = 2 [(yaml.field).fmt = "x"];
  optional uint32 cpusubtype = 3 [(yaml.field).fmt = "x"];
  optional uint32 filetype = 4;
  optional uint32 ncmds = 5;
  optional uint32 sizeofcmds = 6;
  optional uint32 flags = 7 [(yaml.field).fmt = "flags:FILE_FLAG"];
  optional uint32 reserved = 8;
  optional uint64 number_of_segments = 9;
  optional bytes dynamic_linker = 10;
  optional uint64 entry_point = 11;
  optional uint64 stack_size = 12;
  optional string source_version = 13;
  repeated Segment segments = 14;
  repeated Dylib dylibs = 15;
  repeated bytes rpaths = 16;
  repeated string entitlements = 17;
  optional Symtab symtab = 18;
  optional Dysymtab dysymtab = 19;
  optional DyldInfo dyld_info = 20;
  optional LinkedItData code_signature_data = 21;
  optional Certificates certificates = 22;
  optional string uuid = 23;
  optional BuildVersion build_version = 24;
  optional MinVersion min_version = 25;
  repeated string exports = 26;
}

message Macho {
  // Set Mach-O header and basic fields
  optional uint32 magic = 1 [(yaml.field).fmt = "x"];
  optional uint32 cputype = 2 [(yaml.field).fmt = "x"];
  optional uint32 cpusubtype = 3 [(yaml.field).fmt = "x"];
  optional uint32 filetype = 4;
  optional uint32 ncmds = 5;
  optional uint32 sizeofcmds = 6;
  optional uint32 flags = 7 [(yaml.field).fmt = "x"];
  optional uint32 reserved = 8;
  optional uint64 number_of_segments = 9;
  optional bytes dynamic_linker = 10;
  optional uint64 entry_point = 11;
  optional uint64 stack_size = 12;
  optional string source_version = 13;
  optional Symtab symtab = 14;
  optional Dysymtab dysymtab = 15;
  optional LinkedItData code_signature_data = 16;
  repeated Segment segments = 17;
  repeated Dylib dylibs = 18;
  optional DyldInfo dyld_info = 19;
  repeated bytes rpaths = 20;
  repeated string entitlements = 21;
  optional Certificates certificates = 22;
  optional string uuid = 23;
  optional BuildVersion build_version = 24;
  optional MinVersion min_version = 25;
  repeated string exports = 26;


  // Add fields for Mach-O fat binary header
  optional uint32 fat_magic = 27 [(yaml.field).fmt = "x"];
  optional uint32 nfat_arch = 28;
  repeated FatArch fat_arch = 29;

  // Nested Mach-O files
  repeated File file = 30;
}

enum HEADER {
  option (yara.enum_options).inline = true;
  MH_MAGIC = 0 [(yara.enum_value).i64 = 0xfeedface];
  MH_CIGAM = 1 [(yara.enum_value).i64 = 0xcefaedfe];
  MH_MAGIC_64 = 2 [(yara.enum_value).i64 = 0xfeedfacf];
  MH_CIGAM_64 = 3 [(yara.enum_value).i64 = 0xcffaedfe];
}

enum FAT_HEADER {
  option (yara.enum_options).inline = true;
  FAT_MAGIC = 0 [(yara.enum_value).i64 = 0xcafebabe];
  FAT_CIGAM = 1 [(yara.enum_value).i64 = 0xbebafeca];
  FAT_MAGIC_64 = 2 [(yara.enum_value).i64 = 0xcafebabf];
  FAT_CIGAM_64 = 3 [(yara.enum_value).i64 = 0xbfbafeca];
}

enum MASK_64BIT {
  option (yara.enum_options).inline = true;
  CPU_ARCH_ABI64 = 0x01000000;
  CPU_SUBTYPE_LIB64 = 0 [(yara.enum_value).i64 = 0x80000000];
}

enum CPU_TYPE {
  option (yara.enum_options).inline = true;
  CPU_TYPE_MC680X0 = 0x00000006;
  CPU_TYPE_X86 = 0x00000007;
  CPU_TYPE_X86_64 = 0x01000007;
  CPU_TYPE_MIPS = 0x00000008;
  CPU_TYPE_MC98000 = 0x0000000a;
  CPU_TYPE_ARM = 0x0000000c;
  CPU_TYPE_ARM64 = 0x0100000c;
  CPU_TYPE_MC88000 = 0x0000000d;
  CPU_TYPE_SPARC = 0x0000000e;
  CPU_TYPE_POWERPC = 0x00000012;
  CPU_TYPE_POWERPC64 = 0x01000012;
}

enum CPU_I386_TYPE {
  option (yara.enum_options).inline = true;
  CPU_TYPE_I386 = 0x00000007;
}

enum CPU_INTEL_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_INTEL_MODEL_ALL = 0x00000000;
  CPU_SUBTYPE_386 = 0x00000003;
  CPU_SUBTYPE_486 = 0x00000004;
  CPU_SUBTYPE_486SX = 0x00000084;
  CPU_SUBTYPE_586 = 0x00000005;
  CPU_SUBTYPE_CELERON = 0x00000067;
  CPU_SUBTYPE_CELERON_MOBILE = 0x00000077;
  CPU_SUBTYPE_ITANIUM = 0x0000000b;
  CPU_SUBTYPE_ITANIUM_2 = 0x0000001b;
  CPU_SUBTYPE_XEON = 0x0000000c;
  CPU_SUBTYPE_XEON_MP = 0x0000001c;
}

enum CPU_I386_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_I386_ALL = 0x00000003;
}

enum CPU_X86_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_X86_64_ALL = 0x00000003;
}

enum CPU_INTEL_PENTIUM_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_PENT = 0x00000005;
  CPU_SUBTYPE_PENTPRO = 0x00000016;
  CPU_SUBTYPE_PENTII_M3 = 0x00000036;
  CPU_SUBTYPE_PENTII_M5 = 0x00000056;
  CPU_SUBTYPE_PENTIUM_3 = 0x00000008;
  CPU_SUBTYPE_PENTIUM_3_M = 0x00000018;
  CPU_SUBTYPE_PENTIUM_3_XEON = 0x00000028;
  CPU_SUBTYPE_PENTIUM_M = 0x00000009;
  CPU_SUBTYPE_PENTIUM_4 = 0x0000000a;
  CPU_SUBTYPE_PENTIUM_4_M = 0x0000001a;
}

enum CPU_ARM_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_ARM_ALL = 0x00000000;
  CPU_SUBTYPE_ARM_V4T = 0x00000005;
  CPU_SUBTYPE_ARM_V6 = 0x00000006;
  CPU_SUBTYPE_ARM_V5 = 0x00000007;
  CPU_SUBTYPE_ARM_XSCALE = 0x00000008;
  CPU_SUBTYPE_ARM_V7 = 0x00000009;
  CPU_SUBTYPE_ARM_V7F = 0x0000000a;
  CPU_SUBTYPE_ARM_V7S = 0x0000000b;
  CPU_SUBTYPE_ARM_V7K = 0x0000000c;
  CPU_SUBTYPE_ARM_V6M = 0x0000000e;
  CPU_SUBTYPE_ARM_V7M = 0x0000000f;
  CPU_SUBTYPE_ARM_V7EM = 0x00000010;
}

enum CPU_ARM_64_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_ARM_V5TEJ = 0x00000007;
  CPU_SUBTYPE_ARM64_ALL = 0x00000000;
}

enum CPU_SPARC_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_SPARC_ALL = 0x00000000;
}

enum CPU_POWERPC_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_POWERPC_ALL = 0x00000000;
  CPU_SUBTYPE_POWERPC_601 = 0x00000001;
  CPU_SUBTYPE_POWERPC_602 = 0x00000002;
  CPU_SUBTYPE_POWERPC_603 = 0x00000003;
  CPU_SUBTYPE_POWERPC_603e = 0x00000004;
  CPU_SUBTYPE_POWERPC_603ev = 0x00000005;
  CPU_SUBTYPE_POWERPC_604 = 0x00000006;
  CPU_SUBTYPE_POWERPC_604e = 0x00000007;
  CPU_SUBTYPE_POWERPC_620 = 0x00000008;
  CPU_SUBTYPE_POWERPC_750 = 0x00000009;
  CPU_SUBTYPE_POWERPC_7400 = 0x0000000a;
  CPU_SUBTYPE_POWERPC_7450 = 0x0000000b;
  CPU_SUBTYPE_POWERPC_970 = 0x00000064;
}

enum CPU_MC_SUBTYPE {
  option (yara.enum_options).inline = true;
  CPU_SUBTYPE_MC980000_ALL = 0x00000000;
  CPU_SUBTYPE_MC98601 = 0x00000001;
}

enum FILE_TYPE {
  option (yara.enum_options).inline = true;
  MH_OBJECT = 0x00000001;
  MH_EXECUTE = 0x00000002;
  MH_FVMLIB = 0x00000003;
  MH_CORE = 0x00000004;
  MH_PRELOAD = 0x00000005;
  MH_DYLIB = 0x00000006;
  MH_DYLINKER = 0x00000007;
  MH_BUNDLE = 0x00000008;
  MH_DYLIB_STUB = 0x00000009;
  MH_DSYM = 0x0000000a;
  MH_KEXT_BUNDLE = 0x0000000b;
}

enum FILE_FLAG {
  option (yara.enum_options).inline = true;
  MH_NOUNDEFS = 0x00000001;
  MH_INCRLINK = 0x00000002;
  MH_DYLDLINK = 0x00000004;
  MH_BINDATLOAD = 0x00000008;
  MH_PREBOUND = 0x00000010;
  MH_SPLIT_SEGS = 0x00000020;
  MH_LAZY_INIT = 0x00000040;
  MH_TWOLEVEL = 0x00000080;
  MH_FORCE_FLAT = 0x00000100;
  MH_NOMULTIDEFS = 0x00000200;
  MH_NOFIXPREBINDING = 0x00000400;
  MH_PREBINDABLE = 0x00000800;
  MH_ALLMODSBOUND = 0x00001000;
  MH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000;
  MH_CANONICAL = 0x00004000;
  MH_WEAK_DEFINES = 0x00008000;
  MH_BINDS_TO_WEAK = 0x00010000;
  MH_ALLOW_STACK_EXECUTION = 0x00020000;
  MH_ROOT_SAFE = 0x00040000;
  MH_SETUID_SAFE = 0x00080000;
  MH_NO_REEXPORTED_DYLIBS = 0x00100000;
  MH_PIE = 0x00200000;
  MH_DEAD_STRIPPABLE_DYLIB = 0x00400000;
  MH_HAS_TLV_DESCRIPTORS = 0x00800000;
  MH_NO_HEAP_EXECUTION = 0x01000000;
  MH_APP_EXTENSION_SAFE = 0x02000000;
}

enum SEGMENT_FLAG {
  option (yara.enum_options).inline = true;
  SG_HIGHVM = 0x00000001;
  SG_FVMLIB = 0x00000002;
  SG_NORELOC = 0x00000004;
  SG_PROTECTED_VERSION_1 = 0x00000008;
}

enum SECTION_FLAG_MASK {
  option (yara.enum_options).inline = true;
  SECTION_TYPE = 0x000000ff;
  SECTION_ATTRIBUTES = 0 [(yara.enum_value).i64 = 0xffffff00];
}

enum SECTION_TYPE {
  option (yara.enum_options).inline = true;
  S_REGULAR = 0x00000000;
  S_ZEROFILL = 0x00000001;
  S_CSTRING_LITERALS = 0x00000002;
  S_4BYTE_LITERALS = 0x00000003;
  S_8BYTE_LITERALS = 0x00000004;
  S_LITERAL_POINTERS = 0x00000005;
  S_NON_LAZY_SYMBOL_POINTERS = 0x00000006;
  S_LAZY_SYMBOL_POINTERS = 0x00000007;
  S_SYMBOL_STUBS = 0x00000008;
  S_MOD_INIT_FUNC_POINTERS = 0x00000009;
  S_MOD_TERM_FUNC_POINTERS = 0x0000000a;
  S_COALESCED = 0x0000000b;
  S_GB_ZEROFILL = 0x0000000c;
  S_INTERPOSING = 0x0000000d;
  S_16BYTE_LITERALS = 0x0000000e;
  S_DTRACE_DOF = 0x0000000f;
  S_LAZY_DYLIB_SYMBOL_POINTERS = 0x00000010;
  S_THREAD_LOCAL_REGULAR = 0x00000011;
  S_THREAD_LOCAL_ZEROFILL = 0x00000012;
  S_THREAD_LOCAL_VARIABLES = 0x00000013;
  S_THREAD_LOCAL_VARIABLE_POINTERS = 0x00000014;
  S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x00000015;
}

enum SECTION_ATTRIBUTES {
  option (yara.enum_options).inline = true;
  S_ATTR_PURE_INSTRUCTIONS = 0 [(yara.enum_value).i64 = 0x80000000];
  S_ATTR_NO_TOC = 0x40000000;
  S_ATTR_STRIP_STATIC_SYMS = 0x20000000;
  S_ATTR_NO_DEAD_STRIP = 0x10000000;
  S_ATTR_LIVE_SUPPORT = 0x08000000;
  S_ATTR_SELF_MODIFYING_CODE = 0x04000000;
  S_ATTR_DEBUG = 0x02000000;
  S_ATTR_SOME_INSTRUCTIONS = 0x00000400;
  S_ATTR_EXT_RELOC = 0x00000200;
  S_ATTR_LOC_RELOC = 0x00000100;
}

enum DEVICE_TYPE {
  option (yara.enum_options).inline = true;
  MACOSX = 0x00000024;
  IPHONEOS = 0x00000025;
  TVOS = 0x0000002f;
  WATCHOS = 0x00000030;
}