Skip to content

Commit ef9fe27

Browse files
committed
[MachO] Apply types to more load commands
1 parent f72688f commit ef9fe27

File tree

2 files changed

+238
-7
lines changed

2 files changed

+238
-7
lines changed

macho/types.cpp

+197-5
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,45 @@ 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_CSTRING_LITERALS", S_CSTRING_LITERALS},
324+
{"S_4BYTE_LITERALS", S_4BYTE_LITERALS},
325+
{"S_8BYTE_LITERALS", S_8BYTE_LITERALS},
326+
{"S_LITERAL_POINTERS", S_LITERAL_POINTERS},
327+
{"S_NON_LAZY_SYMBOL_POINTERS", S_NON_LAZY_SYMBOL_POINTERS},
328+
{"S_LAZY_SYMBOL_POINTERS", S_LAZY_SYMBOL_POINTERS},
329+
{"S_SYMBOL_STUBS", S_SYMBOL_STUBS},
330+
{"S_MOD_INIT_FUNC_POINTERS", S_MOD_INIT_FUNC_POINTERS},
331+
{"S_MOD_TERM_FUNC_POINTERS", S_MOD_TERM_FUNC_POINTERS},
332+
{"S_COALESCED", S_COALESCED},
333+
{"S_GB_ZEROFILL", S_GB_ZEROFILL},
334+
{"S_INTERPOSING", S_INTERPOSING},
335+
{"S_16BYTE_LITERALS", S_16BYTE_LITERALS},
336+
});
337+
338+
auto sectionAttributesSysEnum = BuildEnum(view, "section_attr_sys_t", 1,
339+
{
340+
{"S_ATTR_DEBUG", (S_ATTR_DEBUG >> 24) & 0xff},
341+
{"S_ATTR_SELF_MODIFYING_CODE", (S_ATTR_SELF_MODIFYING_CODE >> 24) & 0xff},
342+
{"S_ATTR_LIVE_SUPPORT", (S_ATTR_LIVE_SUPPORT >> 24) & 0xff},
343+
{"S_ATTR_NO_DEAD_STRIP", (S_ATTR_NO_DEAD_STRIP >> 24) & 0xff},
344+
{"S_ATTR_STRIP_STATIC_SYMS", (S_ATTR_STRIP_STATIC_SYMS >> 24) & 0xff},
345+
{"S_ATTR_NO_TOC", (S_ATTR_NO_TOC >> 24) & 0xff},
346+
{"S_ATTR_PURE_INSTRUCTIONS", (S_ATTR_PURE_INSTRUCTIONS >> 24) & 0xff},
347+
});
348+
349+
auto sectionAttributesUserEnum = BuildEnum(view, "section_attr_user_t", 2,
350+
{
351+
{"S_ATTR_LOC_RELOC", (S_ATTR_LOC_RELOC >> 8) & 0xffff},
352+
{"S_ATTR_EXT_RELOC", (S_ATTR_EXT_RELOC >> 8) & 0xffff},
353+
{"S_ATTR_SOME_INSTRUCTIONS", (S_ATTR_SOME_INSTRUCTIONS >> 8) & 0xffff},
354+
});
355+
316356
auto sectionType = BuildStruct(view, "section", true,
317357
{
318358
// clang-format off
@@ -324,7 +364,9 @@ void CreateHeaderTypes(Ref<BinaryView> view)
324364
{"align", Type::IntegerType(4, false)},
325365
{"reloff", Type::IntegerType(4, false)},
326366
{"nreloc", Type::IntegerType(4, false)},
327-
{"flags", Type::IntegerType(4, false)},
367+
{"type", sectionTypeEnum},
368+
{"attrs_user", sectionAttributesUserEnum},
369+
{"attrs_sys", sectionAttributesSysEnum},
328370
{"reserved1", Type::IntegerType(4, false)},
329371
{"reserved2", Type::IntegerType(4, false)}
330372
// clang-format on
@@ -341,7 +383,9 @@ void CreateHeaderTypes(Ref<BinaryView> view)
341383
{"align", Type::IntegerType(4, false)},
342384
{"reloff", Type::IntegerType(4, false)},
343385
{"nreloc", Type::IntegerType(4, false)},
344-
{"flags", Type::IntegerType(4, false)},
386+
{"type", sectionTypeEnum},
387+
{"attrs_user", sectionAttributesUserEnum},
388+
{"attrs_sys", sectionAttributesSysEnum},
345389
{"reserved1", Type::IntegerType(4, false)},
346390
{"reserved2", Type::IntegerType(4, false)},
347391
{"reserved3", Type::IntegerType(4, false)}
@@ -499,14 +543,22 @@ void CreateHeaderTypes(Ref<BinaryView> view)
499543
// clang-format on
500544
});
501545

546+
QualifiedName filesetEntryIdName("fileset_entry_id");
547+
std::string filesetEntryIdId = Type::GenerateAutoTypeId("macho", filesetEntryIdName);
548+
auto filesetEntryIdType = Type::NamedType(view,
549+
view->DefineType(filesetEntryIdId, filesetEntryIdName,
550+
TypeBuilder::PointerType(4, Type::IntegerType(1, true))
551+
.SetPointerBase(RelativeToVariableAddressPointerBaseType, -24)
552+
.Finalize()));
553+
502554
auto filesetEntryCommandType = BuildStruct(view, "fileset_entry_command", false,
503555
{
504556
// clang-format off
505557
{"cmd", cmdTypeEnum},
506558
{"cmdsize", Type::IntegerType(4, false)},
507559
{"vmaddr", Type::IntegerType(8, false)},
508560
{"fileoff", Type::IntegerType(8, false)},
509-
{"entry_id", Type::IntegerType(4, false)},
561+
{"entry_id", filesetEntryIdType},
510562
{"reserved", Type::IntegerType(4, false)}
511563
// clang-format on
512564
});
@@ -521,6 +573,103 @@ void CreateHeaderTypes(Ref<BinaryView> view)
521573
// The 'state' field is intentionally ignored.
522574
// clang-format off
523575
});
576+
577+
auto platformTypeEnum = BuildEnum(view, "macho_platform_t", 4,
578+
{
579+
// clang-format off
580+
{"MACHO_PLATFORM_MACOS", MACHO_PLATFORM_MACOS},
581+
{"MACHO_PLATFORM_IOS", MACHO_PLATFORM_IOS},
582+
{"MACHO_PLATFORM_TVOS", MACHO_PLATFORM_TVOS},
583+
{"MACHO_PLATFORM_WATCHOS", MACHO_PLATFORM_WATCHOS},
584+
{"MACHO_PLATFORM_BRIDGEOS", MACHO_PLATFORM_BRIDGEOS},
585+
{"MACHO_PLATFORM_MACCATALYST", MACHO_PLATFORM_MACCATALYST},
586+
{"MACHO_PLATFORM_IOSSIMULATOR", MACHO_PLATFORM_IOSSIMULATOR},
587+
{"MACHO_PLATFORM_TVOSSIMULATOR", MACHO_PLATFORM_TVOSSIMULATOR},
588+
{"MACHO_PLATFORM_WATCHOSSIMULATOR", MACHO_PLATFORM_WATCHOSSIMULATOR},
589+
{"MACHO_PLATFORM_DRIVERKIT", MACHO_PLATFORM_DRIVERKIT},
590+
{"MACHO_PLATFORM_VISIONOS", MACHO_PLATFORM_VISIONOS},
591+
{"MACHO_PLATFORM_VISIONOSSIMULATOR", MACHO_PLATFORM_VISIONOSSIMULATOR},
592+
{"MACHO_PLATFORM_FIRMWARE", MACHO_PLATFORM_FIRMWARE},
593+
{"MACHO_PLATFORM_SEPOS", MACHO_PLATFORM_SEPOS},
594+
{"MACHO_PLATFORM_MACOS_EXCLAVECORE", MACHO_PLATFORM_MACOS_EXCLAVECORE},
595+
{"MACHO_PLATFORM_MACOS_EXCLAVEKIT", MACHO_PLATFORM_MACOS_EXCLAVEKIT},
596+
{"MACHO_PLATFORM_IOS_EXCLAVECORE", MACHO_PLATFORM_IOS_EXCLAVECORE},
597+
{"MACHO_PLATFORM_IOS_EXCLAVEKIT", MACHO_PLATFORM_IOS_EXCLAVEKIT},
598+
{"MACHO_PLATFORM_TVOS_EXCLAVECORE", MACHO_PLATFORM_TVOS_EXCLAVECORE},
599+
{"MACHO_PLATFORM_TVOS_EXCLAVEKIT", MACHO_PLATFORM_TVOS_EXCLAVEKIT},
600+
{"MACHO_PLATFORM_WATCHOS_EXCLAVECORE", MACHO_PLATFORM_WATCHOS_EXCLAVECORE},
601+
{"MACHO_PLATFORM_WATCHOS_EXCLAVEKIT", MACHO_PLATFORM_WATCHOS_EXCLAVEKIT},
602+
{"MACHO_PLATFORM_VISIONOS_EXCLAVECORE", MACHO_PLATFORM_VISIONOS_EXCLAVECORE},
603+
{"MACHO_PLATFORM_VISIONOS_EXCLAVEKIT", MACHO_PLATFORM_VISIONOS_EXCLAVEKIT}
604+
// clang-format on
605+
});
606+
607+
auto buildToolEnum = BuildEnum(view, "macho_build_tool_t", 4,
608+
{
609+
// clang-format off
610+
{"MACHO_TOOL_CLANG", MACHO_TOOL_CLANG},
611+
{"MACHO_TOOL_SWIFT", MACHO_TOOL_SWIFT},
612+
{"MACHO_TOOL_LD", MACHO_TOOL_LD},
613+
{"MACHO_TOOL_LLD", MACHO_TOOL_LLD},
614+
{"MACHO_TOOL_METAL", MACHO_TOOL_METAL},
615+
{"MACHO_TOOL_AIRLLD", MACHO_TOOL_AIRLLD},
616+
{"MACHO_TOOL_AIRNT", MACHO_TOOL_AIRNT},
617+
{"MACHO_TOOL_AIRNT_PLUGIN", MACHO_TOOL_AIRNT_PLUGIN},
618+
{"MACHO_TOOL_AIRPACK", MACHO_TOOL_AIRPACK},
619+
{"MACHO_TOOL_GPUARCHIVER", MACHO_TOOL_GPUARCHIVER},
620+
{"MACHO_TOOL_METAL_FRAMEWORK", MACHO_TOOL_METAL_FRAMEWORK},
621+
// clang-format on
622+
});
623+
624+
auto buildToolVersionType = BuildStruct(view, "build_tool_version", false,
625+
{
626+
// clang-format off
627+
{"tool", buildToolEnum},
628+
{"version", Type::IntegerType(4, false)}
629+
// clang-format on
630+
});
631+
632+
auto buildVersionCommandType = BuildStruct(view, "build_version_command", false,
633+
{
634+
// clang-format off
635+
{"cmd", cmdTypeEnum},
636+
{"cmdsize", Type::IntegerType(4, false)},
637+
{"platform", platformTypeEnum},
638+
{"minos", Type::IntegerType(4, false)},
639+
{"sdk", Type::IntegerType(4, false)},
640+
{"ntools", Type::IntegerType(4, false)},
641+
{"tools", Type::ArrayType(buildToolVersionType, 0)}
642+
// clang-format on
643+
});
644+
645+
auto sourceVersionCommandType = BuildStruct(view, "source_version_command", false,
646+
{
647+
// clang-format off
648+
{"cmd", cmdTypeEnum},
649+
{"cmdsize", Type::IntegerType(4, false)},
650+
{"version", Type::IntegerType(8, false)}
651+
// clang-format on
652+
});
653+
654+
auto entryPointCommandType = BuildStruct(view, "entry_point_command", false,
655+
{
656+
// clang-format off
657+
{"cmd", cmdTypeEnum},
658+
{"cmdsize", Type::IntegerType(4, false)},
659+
{"entryoff", Type::IntegerType(8, false)},
660+
{"stacksize", Type::IntegerType(8, false)}
661+
// clang-format on
662+
});
663+
664+
// Used for the various LC_LOAD_* commands that have only a single string field.
665+
auto stringCommandType = BuildStruct(view, "string_command", false,
666+
{
667+
// clang-format off
668+
{"cmd", cmdTypeEnum},
669+
{"cmdsize", Type::IntegerType(4, false)},
670+
{"value", lcStringType}
671+
// clang-format on
672+
});
524673
}
525674

526675
void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryReader& incomingReader,
@@ -609,6 +758,9 @@ void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryRead
609758
case LC_DYLIB_CODE_SIGN_DRS:
610759
case LC_DYLD_EXPORTS_TRIE:
611760
case LC_DYLD_CHAINED_FIXUPS:
761+
case LC_ATOM_INFO:
762+
case LC_FUNCTION_VARIANTS:
763+
case LC_FUNCTION_VARIANT_FIXUPS:
612764
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("linkedit_data_command")));
613765
break;
614766
case LC_ENCRYPTION_INFO:
@@ -623,8 +775,14 @@ void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryRead
623775
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("dyld_info_command")));
624776
break;
625777
case LC_FILESET_ENTRY:
626-
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("fileset_entry_command")));
778+
{
779+
auto type = Type::NamedType(view, QualifiedName("fileset_entry_command"));
780+
view->DefineDataVariable(cmdAddr, type);
781+
if (load.cmdsize - type->GetWidth() <= 150)
782+
view->DefineDataVariable(cmdAddr + type->GetWidth(),
783+
Type::ArrayType(Type::IntegerType(1, true), load.cmdsize - type->GetWidth()));
627784
break;
785+
}
628786
case LC_UNIXTHREAD:
629787
{
630788
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("unix_thread_command")));
@@ -633,6 +791,40 @@ void ApplyHeaderTypes(Ref<BinaryView> view, Ref<Logger> logger, const BinaryRead
633791
view->DefineDataVariable(reader.GetOffset(), Type::ArrayType(Type::IntegerType(8, true), count));
634792
break;
635793
}
794+
case LC_BUILD_VERSION:
795+
{
796+
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("build_version_command")));
797+
reader.SeekRelative(12);
798+
uint32_t count = reader.Read32();
799+
view->DefineDataVariable(
800+
reader.GetOffset(), Type::ArrayType(Type::NamedType(view, QualifiedName("build_tool_version")), count));
801+
break;
802+
}
803+
case LC_SOURCE_VERSION:
804+
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("source_version_command")));
805+
break;
806+
case LC_MAIN:
807+
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("entry_point_command")));
808+
break;
809+
case LC_DYLD_ENVIRONMENT:
810+
case LC_ID_DYLINKER:
811+
case LC_LOAD_DYLINKER:
812+
case LC_RPATH:
813+
case LC_SUB_CLIENT:
814+
case LC_SUB_FRAMEWORK:
815+
case LC_SUB_LIBRARY:
816+
case LC_SUB_UMBRELLA:
817+
case LC_TARGET_TRIPLE:
818+
{
819+
Ref<Type> type = Type::NamedType(view, QualifiedName("string_command"));
820+
view->DefineDataVariable(cmdAddr, type);
821+
822+
if (load.cmdsize - type->GetWidth() <= 150)
823+
view->DefineDataVariable(cmdAddr + type->GetWidth(),
824+
Type::ArrayType(Type::IntegerType(1, true), load.cmdsize - type->GetWidth()));
825+
826+
break;
827+
}
636828
default:
637829
view->DefineDataVariable(cmdAddr, Type::NamedType(view, QualifiedName("load_command")));
638830
break;

macho/types.h

+41-2
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
@@ -200,6 +205,10 @@ typedef int vm_prot_t;
200205
#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD)
201206
#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD)
202207
#define LC_FILESET_ENTRY (0x35 | LC_REQ_DYLD)
208+
#define LC_ATOM_INFO 0x36
209+
#define LC_FUNCTION_VARIANTS 0x37
210+
#define LC_FUNCTION_VARIANT_FIXUPS 0x38
211+
#define LC_TARGET_TRIPLE 0x39
203212

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

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

10261065
struct build_tool_version

0 commit comments

Comments
 (0)