Skip to content

Commit a724832

Browse files
committed
[MachO] Apply types to more load commands
1 parent cbdd4df commit a724832

File tree

2 files changed

+247
-7
lines changed

2 files changed

+247
-7
lines changed

macho/types.cpp

Lines changed: 206 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ void CreateHeaderTypes(Ref<BinaryView> view)
275275
{"SG_HIGHVM", SG_HIGHVM},
276276
{"SG_FVMLIB", SG_FVMLIB},
277277
{"SG_NORELOC", SG_NORELOC},
278-
{"SG_PROTECTED_VERSION_1", SG_PROTECTED_VERSION_1}
278+
{"SG_PROTECTED_VERSION_1", SG_PROTECTED_VERSION_1},
279+
{"SG_READ_ONLY_DATA", SG_READ_ONLY_DATA},
279280
// clang-format on
280281
});
281282

@@ -313,6 +314,54 @@ void CreateHeaderTypes(Ref<BinaryView> view)
313314
// clang-format on
314315
});
315316

317+
// TODO: These three enums are technically a single field 32-bit field in the struct. The upper 24 bits are bit
318+
// flags while the lower 8 bits are mutually exclusive. This prevents Binary Ninja from rendering them in an ORd
319+
// form. The upper 24 bits are split into two enums because a 24 bit enum field isn't handle correctly either.
320+
auto sectionTypeEnum = BuildEnum(view, "section_type_t", 1,
321+
{
322+
{"S_REGULAR", S_REGULAR},
323+
{"S_ZEROFILL", S_ZEROFILL},
324+
{"S_CSTRING_LITERALS", S_CSTRING_LITERALS},
325+
{"S_4BYTE_LITERALS", S_4BYTE_LITERALS},
326+
{"S_8BYTE_LITERALS", S_8BYTE_LITERALS},
327+
{"S_LITERAL_POINTERS", S_LITERAL_POINTERS},
328+
{"S_NON_LAZY_SYMBOL_POINTERS", S_NON_LAZY_SYMBOL_POINTERS},
329+
{"S_LAZY_SYMBOL_POINTERS", S_LAZY_SYMBOL_POINTERS},
330+
{"S_SYMBOL_STUBS", S_SYMBOL_STUBS},
331+
{"S_MOD_INIT_FUNC_POINTERS", S_MOD_INIT_FUNC_POINTERS},
332+
{"S_MOD_TERM_FUNC_POINTERS", S_MOD_TERM_FUNC_POINTERS},
333+
{"S_COALESCED", S_COALESCED},
334+
{"S_GB_ZEROFILL", S_GB_ZEROFILL},
335+
{"S_INTERPOSING", S_INTERPOSING},
336+
{"S_16BYTE_LITERALS", S_16BYTE_LITERALS},
337+
{"S_DTRACE_DOF", S_DTRACE_DOF},
338+
{"S_LAZY_DYLIB_SYMBOL_POINTERS", S_LAZY_DYLIB_SYMBOL_POINTERS},
339+
{"S_THREAD_LOCAL_REGULAR", S_THREAD_LOCAL_REGULAR},
340+
{"S_THREAD_LOCAL_ZEROFILL", S_THREAD_LOCAL_ZEROFILL},
341+
{"S_THREAD_LOCAL_VARIABLES", S_THREAD_LOCAL_VARIABLES},
342+
{"S_THREAD_LOCAL_VARIABLE_POINTERS", S_THREAD_LOCAL_VARIABLE_POINTERS},
343+
{"S_THREAD_LOCAL_INIT_FUNCTION_POINTERS", S_THREAD_LOCAL_INIT_FUNCTION_POINTERS},
344+
{"S_INIT_FUNC_OFFSETS", S_INIT_FUNC_OFFSETS},
345+
});
346+
347+
auto sectionAttributesSysEnum = BuildEnum(view, "section_attr_sys_t", 1,
348+
{
349+
{"S_ATTR_DEBUG", (S_ATTR_DEBUG >> 24) & 0xff},
350+
{"S_ATTR_SELF_MODIFYING_CODE", (S_ATTR_SELF_MODIFYING_CODE >> 24) & 0xff},
351+
{"S_ATTR_LIVE_SUPPORT", (S_ATTR_LIVE_SUPPORT >> 24) & 0xff},
352+
{"S_ATTR_NO_DEAD_STRIP", (S_ATTR_NO_DEAD_STRIP >> 24) & 0xff},
353+
{"S_ATTR_STRIP_STATIC_SYMS", (S_ATTR_STRIP_STATIC_SYMS >> 24) & 0xff},
354+
{"S_ATTR_NO_TOC", (S_ATTR_NO_TOC >> 24) & 0xff},
355+
{"S_ATTR_PURE_INSTRUCTIONS", (S_ATTR_PURE_INSTRUCTIONS >> 24) & 0xff},
356+
});
357+
358+
auto sectionAttributesUserEnum = BuildEnum(view, "section_attr_user_t", 2,
359+
{
360+
{"S_ATTR_LOC_RELOC", (S_ATTR_LOC_RELOC >> 8) & 0xffff},
361+
{"S_ATTR_EXT_RELOC", (S_ATTR_EXT_RELOC >> 8) & 0xffff},
362+
{"S_ATTR_SOME_INSTRUCTIONS", (S_ATTR_SOME_INSTRUCTIONS >> 8) & 0xffff},
363+
});
364+
316365
auto sectionType = BuildStruct(view, "section", true,
317366
{
318367
// clang-format off
@@ -324,7 +373,9 @@ void CreateHeaderTypes(Ref<BinaryView> view)
324373
{"align", Type::IntegerType(4, false)},
325374
{"reloff", Type::IntegerType(4, false)},
326375
{"nreloc", Type::IntegerType(4, false)},
327-
{"flags", Type::IntegerType(4, false)},
376+
{"type", sectionTypeEnum},
377+
{"attrs_user", sectionAttributesUserEnum},
378+
{"attrs_sys", sectionAttributesSysEnum},
328379
{"reserved1", Type::IntegerType(4, false)},
329380
{"reserved2", Type::IntegerType(4, false)}
330381
// clang-format on
@@ -341,7 +392,9 @@ void CreateHeaderTypes(Ref<BinaryView> view)
341392
{"align", Type::IntegerType(4, false)},
342393
{"reloff", Type::IntegerType(4, false)},
343394
{"nreloc", Type::IntegerType(4, false)},
344-
{"flags", Type::IntegerType(4, false)},
395+
{"type", sectionTypeEnum},
396+
{"attrs_user", sectionAttributesUserEnum},
397+
{"attrs_sys", sectionAttributesSysEnum},
345398
{"reserved1", Type::IntegerType(4, false)},
346399
{"reserved2", Type::IntegerType(4, false)},
347400
{"reserved3", Type::IntegerType(4, false)}
@@ -499,14 +552,22 @@ void CreateHeaderTypes(Ref<BinaryView> view)
499552
// clang-format on
500553
});
501554

555+
QualifiedName filesetEntryIdName("fileset_entry_id");
556+
std::string filesetEntryIdId = Type::GenerateAutoTypeId("macho", filesetEntryIdName);
557+
auto filesetEntryIdType = Type::NamedType(view,
558+
view->DefineType(filesetEntryIdId, filesetEntryIdName,
559+
TypeBuilder::PointerType(4, Type::IntegerType(1, true))
560+
.SetPointerBase(RelativeToVariableAddressPointerBaseType, -24)
561+
.Finalize()));
562+
502563
auto filesetEntryCommandType = BuildStruct(view, "fileset_entry_command", false,
503564
{
504565
// clang-format off
505566
{"cmd", cmdTypeEnum},
506567
{"cmdsize", Type::IntegerType(4, false)},
507568
{"vmaddr", Type::IntegerType(8, false)},
508569
{"fileoff", Type::IntegerType(8, false)},
509-
{"entry_id", Type::IntegerType(4, false)},
570+
{"entry_id", filesetEntryIdType},
510571
{"reserved", Type::IntegerType(4, false)}
511572
// clang-format on
512573
});
@@ -521,6 +582,103 @@ void CreateHeaderTypes(Ref<BinaryView> view)
521582
// The 'state' field is intentionally ignored.
522583
// clang-format off
523584
});
585+
586+
auto platformTypeEnum = BuildEnum(view, "macho_platform_t", 4,
587+
{
588+
// clang-format off
589+
{"MACHO_PLATFORM_MACOS", MACHO_PLATFORM_MACOS},
590+
{"MACHO_PLATFORM_IOS", MACHO_PLATFORM_IOS},
591+
{"MACHO_PLATFORM_TVOS", MACHO_PLATFORM_TVOS},
592+
{"MACHO_PLATFORM_WATCHOS", MACHO_PLATFORM_WATCHOS},
593+
{"MACHO_PLATFORM_BRIDGEOS", MACHO_PLATFORM_BRIDGEOS},
594+
{"MACHO_PLATFORM_MACCATALYST", MACHO_PLATFORM_MACCATALYST},
595+
{"MACHO_PLATFORM_IOSSIMULATOR", MACHO_PLATFORM_IOSSIMULATOR},
596+
{"MACHO_PLATFORM_TVOSSIMULATOR", MACHO_PLATFORM_TVOSSIMULATOR},
597+
{"MACHO_PLATFORM_WATCHOSSIMULATOR", MACHO_PLATFORM_WATCHOSSIMULATOR},
598+
{"MACHO_PLATFORM_DRIVERKIT", MACHO_PLATFORM_DRIVERKIT},
599+
{"MACHO_PLATFORM_VISIONOS", MACHO_PLATFORM_VISIONOS},
600+
{"MACHO_PLATFORM_VISIONOSSIMULATOR", MACHO_PLATFORM_VISIONOSSIMULATOR},
601+
{"MACHO_PLATFORM_FIRMWARE", MACHO_PLATFORM_FIRMWARE},
602+
{"MACHO_PLATFORM_SEPOS", MACHO_PLATFORM_SEPOS},
603+
{"MACHO_PLATFORM_MACOS_EXCLAVECORE", MACHO_PLATFORM_MACOS_EXCLAVECORE},
604+
{"MACHO_PLATFORM_MACOS_EXCLAVEKIT", MACHO_PLATFORM_MACOS_EXCLAVEKIT},
605+
{"MACHO_PLATFORM_IOS_EXCLAVECORE", MACHO_PLATFORM_IOS_EXCLAVECORE},
606+
{"MACHO_PLATFORM_IOS_EXCLAVEKIT", MACHO_PLATFORM_IOS_EXCLAVEKIT},
607+
{"MACHO_PLATFORM_TVOS_EXCLAVECORE", MACHO_PLATFORM_TVOS_EXCLAVECORE},
608+
{"MACHO_PLATFORM_TVOS_EXCLAVEKIT", MACHO_PLATFORM_TVOS_EXCLAVEKIT},
609+
{"MACHO_PLATFORM_WATCHOS_EXCLAVECORE", MACHO_PLATFORM_WATCHOS_EXCLAVECORE},
610+
{"MACHO_PLATFORM_WATCHOS_EXCLAVEKIT", MACHO_PLATFORM_WATCHOS_EXCLAVEKIT},
611+
{"MACHO_PLATFORM_VISIONOS_EXCLAVECORE", MACHO_PLATFORM_VISIONOS_EXCLAVECORE},
612+
{"MACHO_PLATFORM_VISIONOS_EXCLAVEKIT", MACHO_PLATFORM_VISIONOS_EXCLAVEKIT}
613+
// clang-format on
614+
});
615+
616+
auto buildToolEnum = BuildEnum(view, "macho_build_tool_t", 4,
617+
{
618+
// clang-format off
619+
{"MACHO_TOOL_CLANG", MACHO_TOOL_CLANG},
620+
{"MACHO_TOOL_SWIFT", MACHO_TOOL_SWIFT},
621+
{"MACHO_TOOL_LD", MACHO_TOOL_LD},
622+
{"MACHO_TOOL_LLD", MACHO_TOOL_LLD},
623+
{"MACHO_TOOL_METAL", MACHO_TOOL_METAL},
624+
{"MACHO_TOOL_AIRLLD", MACHO_TOOL_AIRLLD},
625+
{"MACHO_TOOL_AIRNT", MACHO_TOOL_AIRNT},
626+
{"MACHO_TOOL_AIRNT_PLUGIN", MACHO_TOOL_AIRNT_PLUGIN},
627+
{"MACHO_TOOL_AIRPACK", MACHO_TOOL_AIRPACK},
628+
{"MACHO_TOOL_GPUARCHIVER", MACHO_TOOL_GPUARCHIVER},
629+
{"MACHO_TOOL_METAL_FRAMEWORK", MACHO_TOOL_METAL_FRAMEWORK},
630+
// clang-format on
631+
});
632+
633+
auto buildToolVersionType = BuildStruct(view, "build_tool_version", false,
634+
{
635+
// clang-format off
636+
{"tool", buildToolEnum},
637+
{"version", Type::IntegerType(4, false)}
638+
// clang-format on
639+
});
640+
641+
auto buildVersionCommandType = BuildStruct(view, "build_version_command", false,
642+
{
643+
// clang-format off
644+
{"cmd", cmdTypeEnum},
645+
{"cmdsize", Type::IntegerType(4, false)},
646+
{"platform", platformTypeEnum},
647+
{"minos", Type::IntegerType(4, false)},
648+
{"sdk", Type::IntegerType(4, false)},
649+
{"ntools", Type::IntegerType(4, false)},
650+
{"tools", Type::ArrayType(buildToolVersionType, 0)}
651+
// clang-format on
652+
});
653+
654+
auto sourceVersionCommandType = BuildStruct(view, "source_version_command", false,
655+
{
656+
// clang-format off
657+
{"cmd", cmdTypeEnum},
658+
{"cmdsize", Type::IntegerType(4, false)},
659+
{"version", Type::IntegerType(8, false)}
660+
// clang-format on
661+
});
662+
663+
auto entryPointCommandType = BuildStruct(view, "entry_point_command", false,
664+
{
665+
// clang-format off
666+
{"cmd", cmdTypeEnum},
667+
{"cmdsize", Type::IntegerType(4, false)},
668+
{"entryoff", Type::IntegerType(8, false)},
669+
{"stacksize", Type::IntegerType(8, false)}
670+
// clang-format on
671+
});
672+
673+
// Used for the various LC_LOAD_* commands that have only a single string field.
674+
auto stringCommandType = BuildStruct(view, "string_command", false,
675+
{
676+
// clang-format off
677+
{"cmd", cmdTypeEnum},
678+
{"cmdsize", Type::IntegerType(4, false)},
679+
{"value", lcStringType}
680+
// clang-format on
681+
});
524682
}
525683

526684
void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryReader& incomingReader,
@@ -609,6 +767,9 @@ void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryRead
609767
case LC_DYLIB_CODE_SIGN_DRS:
610768
case LC_DYLD_EXPORTS_TRIE:
611769
case LC_DYLD_CHAINED_FIXUPS:
770+
case LC_ATOM_INFO:
771+
case LC_FUNCTION_VARIANTS:
772+
case LC_FUNCTION_VARIANT_FIXUPS:
612773
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("linkedit_data_command")));
613774
break;
614775
case LC_ENCRYPTION_INFO:
@@ -623,8 +784,14 @@ void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryRead
623784
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("dyld_info_command")));
624785
break;
625786
case LC_FILESET_ENTRY:
626-
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("fileset_entry_command")));
787+
{
788+
auto type = Type::NamedType(view, QualifiedName("fileset_entry_command"));
789+
view->DefineDataVariable(cmdAddr, type);
790+
if (load.cmdsize - type->GetWidth() <= 150)
791+
view->DefineDataVariable(cmdAddr + type->GetWidth(),
792+
Type::ArrayType(Type::IntegerType(1, true), load.cmdsize - type->GetWidth()));
627793
break;
794+
}
628795
case LC_UNIXTHREAD:
629796
{
630797
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("unix_thread_command")));
@@ -633,6 +800,40 @@ void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryRead
633800
view->DefineDataVariable(reader.GetOffset(), Type::ArrayType(Type::IntegerType(8, true), count));
634801
break;
635802
}
803+
case LC_BUILD_VERSION:
804+
{
805+
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("build_version_command")));
806+
reader.SeekRelative(12);
807+
uint32_t count = reader.Read32();
808+
view->DefineDataVariable(
809+
reader.GetOffset(), Type::ArrayType(Type::NamedType(view, QualifiedName("build_tool_version")), count));
810+
break;
811+
}
812+
case LC_SOURCE_VERSION:
813+
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("source_version_command")));
814+
break;
815+
case LC_MAIN:
816+
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("entry_point_command")));
817+
break;
818+
case LC_DYLD_ENVIRONMENT:
819+
case LC_ID_DYLINKER:
820+
case LC_LOAD_DYLINKER:
821+
case LC_RPATH:
822+
case LC_SUB_CLIENT:
823+
case LC_SUB_FRAMEWORK:
824+
case LC_SUB_LIBRARY:
825+
case LC_SUB_UMBRELLA:
826+
case LC_TARGET_TRIPLE:
827+
{
828+
Ref<Type> type = Type::NamedType(view, QualifiedName("string_command"));
829+
view->DefineDataVariable(cmdAddr, type);
830+
831+
if (load.cmdsize - type->GetWidth() <= 150)
832+
view->DefineDataVariable(cmdAddr + type->GetWidth(),
833+
Type::ArrayType(Type::IntegerType(1, true), load.cmdsize - type->GetWidth()));
834+
835+
break;
836+
}
636837
default:
637838
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("load_command")));
638839
break;

macho/types.h

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ typedef int vm_prot_t;
107107
#define SG_FVMLIB 0x2
108108
#define SG_NORELOC 0x4
109109
#define SG_PROTECTED_VERSION_1 0x8
110+
#define SG_READ_ONLY_DATA 0x10
110111

111112
// Section flags
112113
#define S_ATTR_SOME_INSTRUCTIONS 0x00000400
@@ -117,6 +118,10 @@ typedef int vm_prot_t;
117118
#define S_ATTR_NO_DEAD_STRIP 0x10000000 // no dead stripping
118119
#define S_ATTR_LIVE_SUPPORT 0x08000000 // blocks are live if they reference live blocks
119120
#define S_ATTR_SELF_MODIFYING_CODE 0x04000000 // Used with i386 code stubs written on by dyld
121+
#define S_ATTR_DEBUG 0x02000000 // a debug section */
122+
#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 // section contains some machine instructions
123+
#define S_ATTR_EXT_RELOC 0x00000200 // section has external relocation entries
124+
#define S_ATTR_LOC_RELOC 0x00000100 // section has local relocation entries
120125

121126
#define S_REGULAR 0x0
122127
#define S_ZEROFILL 0x1
@@ -201,6 +206,10 @@ typedef int vm_prot_t;
201206
#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD)
202207
#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD)
203208
#define LC_FILESET_ENTRY (0x35 | LC_REQ_DYLD)
209+
#define LC_ATOM_INFO 0x36
210+
#define LC_FUNCTION_VARIANTS 0x37
211+
#define LC_FUNCTION_VARIANT_FIXUPS 0x38
212+
#define LC_TARGET_TRIPLE 0x39
204213

205214
// Mach-O File types
206215
#define MH_OBJECT 0x1
@@ -1014,14 +1023,44 @@ namespace BinaryNinja {
10141023
MACHO_PLATFORM_IOS = 2,
10151024
MACHO_PLATFORM_TVOS = 3,
10161025
MACHO_PLATFORM_WATCHOS = 4,
1017-
MACHO_PLATFORM_BRIDGEOS = 5
1026+
MACHO_PLATFORM_BRIDGEOS = 5,
1027+
MACHO_PLATFORM_MACCATALYST = 6,
1028+
MACHO_PLATFORM_IOSSIMULATOR = 7,
1029+
MACHO_PLATFORM_TVOSSIMULATOR = 8,
1030+
MACHO_PLATFORM_WATCHOSSIMULATOR = 9,
1031+
MACHO_PLATFORM_DRIVERKIT = 10,
1032+
MACHO_PLATFORM_VISIONOS = 11,
1033+
MACHO_PLATFORM_VISIONOSSIMULATOR = 12,
1034+
1035+
MACHO_PLATFORM_FIRMWARE = 13,
1036+
MACHO_PLATFORM_SEPOS = 14,
1037+
1038+
MACHO_PLATFORM_MACOS_EXCLAVECORE = 15,
1039+
MACHO_PLATFORM_MACOS_EXCLAVEKIT = 16,
1040+
MACHO_PLATFORM_IOS_EXCLAVECORE = 17,
1041+
MACHO_PLATFORM_IOS_EXCLAVEKIT = 18,
1042+
MACHO_PLATFORM_TVOS_EXCLAVECORE = 19,
1043+
MACHO_PLATFORM_TVOS_EXCLAVEKIT = 20,
1044+
MACHO_PLATFORM_WATCHOS_EXCLAVECORE = 21,
1045+
MACHO_PLATFORM_WATCHOS_EXCLAVEKIT = 22,
1046+
MACHO_PLATFORM_VISIONOS_EXCLAVECORE = 23,
1047+
MACHO_PLATFORM_VISIONOS_EXCLAVEKIT = 24,
10181048
};
10191049

10201050
enum MachoBuildTool
10211051
{
10221052
MACHO_TOOL_CLANG = 1,
10231053
MACHO_TOOL_SWIFT = 2,
1024-
MACHO_TOOL_LD = 3
1054+
MACHO_TOOL_LD = 3,
1055+
MACHO_TOOL_LLD = 4,
1056+
1057+
MACHO_TOOL_METAL = 1024,
1058+
MACHO_TOOL_AIRLLD = 1025,
1059+
MACHO_TOOL_AIRNT = 1026,
1060+
MACHO_TOOL_AIRNT_PLUGIN = 1027,
1061+
MACHO_TOOL_AIRPACK = 1028,
1062+
MACHO_TOOL_GPUARCHIVER = 1031,
1063+
MACHO_TOOL_METAL_FRAMEWORK = 1032,
10251064
};
10261065

10271066
struct build_tool_version

0 commit comments

Comments
 (0)