1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
|
#include "SharedCacheView.h"
#include <regex>
#include "SharedCacheController.h"
#include "FileAccessorCache.h"
#include "MappedFileAccessor.h"
using namespace BinaryNinja;
using namespace BinaryNinja::DSC;
SharedCacheViewType::SharedCacheViewType() : BinaryViewType(VIEW_NAME, VIEW_NAME) {}
// We register all our one-shot stuff here, such as the object destructor.
void SharedCacheViewType::Register()
{
auto fdLimit = AdjustFileDescriptorLimit();
LogDebug("Shared Cache processing initialized with a max file descriptor limit of %lld", fdLimit);
// Adjust the global accessor cache to the fdlimit.
FileAccessorCache::Global().SetCacheSize(fdLimit);
// TODO: Register object destructor to clear accessor cache
RegisterSharedCacheControllerDestructor();
static SharedCacheViewType type;
BinaryViewType::Register(&type);
}
Ref<BinaryView> SharedCacheViewType::Create(BinaryView* data)
{
return new SharedCacheView(VIEW_NAME, data, false);
}
Ref<Settings> SharedCacheViewType::GetLoadSettingsForData(BinaryView* data)
{
Ref<BinaryView> viewRef = Parse(data);
if (!viewRef || !viewRef->Init())
{
LogWarn("Failed to initialize view of type '%s'. Generating default load settings.", GetName().c_str());
viewRef = data;
}
Ref<Settings> settings = GetDefaultLoadSettingsForData(viewRef);
// specify default load settings that can be overridden
std::vector<std::string> overrides = {"loader.imageBase", "loader.platform"};
settings->UpdateProperty("loader.imageBase", "message", "Note: File indicates image is not relocatable.");
for (const auto& override : overrides)
{
if (settings->Contains(override))
settings->UpdateProperty(override, "readOnly", false);
}
Ref<Settings> programSettings = Settings::Instance();
programSettings->Set("analysis.workflows.functionWorkflow", "core.function.sharedCache", viewRef);
settings->RegisterSetting("loader.dsc.processCFStrings",
R"({
"title" : "Process CFString Metadata",
"type" : "boolean",
"default" : true,
"description" : "Processes CoreFoundation strings, applying string values from encoded metadata"
})");
settings->RegisterSetting("loader.dsc.autoLoadPattern",
R"({
"title" : "Image Auto-Load Regex Pattern",
"type" : "string",
"default" : ".*libsystem_c.dylib",
"description" : "A regex pattern to auto load matching images at the end of view init, defaults to the system_c image only."
})");
settings->RegisterSetting("loader.dsc.processObjC",
R"({
"title" : "Process Objective-C Metadata",
"type" : "boolean",
"default" : true,
"description" : "Processes Objective-C metadata, applying class and method names from encoded metadata"
})");
settings->RegisterSetting("loader.dsc.regionFilter",
R"({
"title" : "Region Regex Filter",
"type" : "string",
"default" : ".*LINKEDIT.*",
"description" : "Regex filter for region names to skip loading, by default this filters out the link edit region which is not necessary to be applied to the view."
})");
settings->RegisterSetting("loader.dsc.autoLoadObjCStubRequirements",
R"({
"title" : "Auto-Load Objective-C Stub Requirements",
"type" : "boolean",
"default" : true,
"description" : "Automatically loads segments required for inlining Objective-C stubs. Recommended you keep this on."
})");
settings->RegisterSetting("loader.dsc.autoLoadStubsAndDyldData",
R"({
"title" : "Auto-Load Stub Islands",
"type" : "boolean",
"default" : true,
"description" : "Automatically loads stub and dylddata regions that contain just branches and pointers. These are required for resolving stub names, and performance impact is minimal. Recommended you keep this on."
})");
settings->RegisterSetting("loader.dsc.processFunctionStarts",
R"({
"title" : "Process Mach-O Function Starts Tables",
"type" : "boolean",
"default" : true,
"description" : "Add function starts sourced from the Function Starts tables to the core for analysis."
})");
// Merge existing load settings if they exist. This allows for the selection of a specific object file from a Mach-O
// Universal file. The 'Universal' BinaryViewType generates a schema with 'loader.universal.architectures'. This
// schema contains an appropriate 'Mach-O' load schema for selecting a specific object file. The embedded schema
// contains 'loader.macho.universalImageOffset'.
Ref<Settings> loadSettings = viewRef->GetLoadSettings(GetName());
if (loadSettings && !loadSettings->IsEmpty())
settings->DeserializeSchema(loadSettings->SerializeSchema());
return settings;
}
Ref<BinaryView> SharedCacheViewType::Parse(BinaryView* data)
{
return new SharedCacheView(VIEW_NAME, data, true);
}
bool SharedCacheViewType::IsTypeValidForData(BinaryView* data)
{
if (!data)
return false;
DataBuffer sig = data->ReadBuffer(data->GetStart(), 4);
if (sig.GetLength() != 4)
return false;
const char* magic = (char*)sig.GetData();
if (strncmp(magic, "dyld", 4) == 0)
return true;
return false;
}
SharedCacheView::SharedCacheView(const std::string& typeName, BinaryView* data, bool parseOnly) :
BinaryView(typeName, data->GetFile(), data), m_parseOnly(parseOnly)
{
CreateLogger("SharedCache");
CreateLogger("SharedCache.ObjC");
}
enum DSCPlatform
{
DSCPlatformMacOS = 1,
DSCPlatformiOS = 2,
DSCPlatformTVOS = 3,
DSCPlatformWatchOS = 4,
DSCPlatformBridgeOS = 5, // T1/T2 APL1023/T8012, this is your touchbar/touchid in intel macs. Similar to watchOS.
// DSCPlatformMacCatalyst = 6,
DSCPlatformiOSSimulator = 7,
DSCPlatformTVOSSimulator = 8,
DSCPlatformWatchOSSimulator = 9,
DSCPlatformVisionOS = 11, // Apple Vision Pro
DSCPlatformVisionOSSimulator = 12 // Apple Vision Pro Simulator
};
bool SharedCacheView::Init()
{
std::string os;
std::string arch;
auto logger = new Logger("SharedCache.View", GetFile()->GetSessionId());
uint32_t platform;
GetParentView()->Read(&platform, 0xd8, 4);
char magic[17];
GetParentView()->Read(&magic, 0, 16);
magic[16] = 0;
// TODO: Do we want to add any warnings about platform support here?
// TODO: Do we still consider macos experimental?
switch (platform)
{
case DSCPlatformMacOS:
case DSCPlatformTVOS:
case DSCPlatformTVOSSimulator:
os = "mac";
break;
case DSCPlatformiOS:
case DSCPlatformiOSSimulator:
case DSCPlatformVisionOS:
case DSCPlatformVisionOSSimulator:
os = "ios";
break;
// armv7 or slide info v1 (unsupported)
case DSCPlatformWatchOS:
case DSCPlatformWatchOSSimulator:
case DSCPlatformBridgeOS:
default:
logger->LogError("Unknown platform: %d", platform);
return false;
}
if (std::string(magic) == "dyld_v1 arm64" || std::string(magic) == "dyld_v1 arm64e"
|| std::string(magic) == "dyld_v1arm64_32")
{
arch = "aarch64";
}
else if (std::string(magic) == "dyld_v1 x86_64" || std::string(magic) == "dyld_v1 x86_64h")
{
arch = "x86_64";
}
else
{
logger->LogError("Unknown magic: %s", magic);
return false;
}
SetDefaultPlatform(Platform::GetByName(os + "-" + arch));
SetDefaultArchitecture(Architecture::GetByName(arch));
Ref<Settings> settings = GetLoadSettings(GetTypeName());
if (!settings)
{
Ref<Settings> programSettings = Settings::Instance();
programSettings->Set("analysis.workflows.functionWorkflow", "core.function.sharedCache", this);
}
if (m_parseOnly)
return true;
QualifiedNameAndType headerType;
std::string err;
ParseTypeString(
"\n"
"\tstruct dyld_cache_header\n"
"\t{\n"
"\t\tchar magic[16];\t\t\t\t\t // e.g. \"dyld_v0 i386\"\n"
"\t\tuint32_t mappingOffset;\t\t\t // file offset to first dyld_cache_mapping_info\n"
"\t\tuint32_t mappingCount;\t\t\t // number of dyld_cache_mapping_info entries\n"
"\t\tuint32_t imagesOffsetOld;\t\t // UNUSED: moved to imagesOffset to prevent older dsc_extarctors from "
"crashing\n"
"\t\tuint32_t imagesCountOld;\t\t // UNUSED: moved to imagesCount to prevent older dsc_extarctors from "
"crashing\n"
"\t\tuint64_t dyldBaseAddress;\t\t // base address of dyld when cache was built\n"
"\t\tuint64_t codeSignatureOffset;\t // file offset of code signature blob\n"
"\t\tuint64_t codeSignatureSize;\t\t // size of code signature blob (zero means to end of file)\n"
"\t\tuint64_t slideInfoOffsetUnused;\t // unused. Used to be file offset of kernel slid info\n"
"\t\tuint64_t slideInfoSizeUnused;\t // unused. Used to be size of kernel slid info\n"
"\t\tuint64_t localSymbolsOffset;\t // file offset of where local symbols are stored\n"
"\t\tuint64_t localSymbolsSize;\t\t // size of local symbols information\n"
"\t\tuint8_t uuid[16];\t\t\t\t // unique value for each shared cache file\n"
"\t\tuint64_t cacheType;\t\t\t\t // 0 for development, 1 for production // Kat: , 2 for iOS 16?\n"
"\t\tuint32_t branchPoolsOffset;\t\t // file offset to table of uint64_t pool addresses\n"
"\t\tuint32_t branchPoolsCount;\t\t // number of uint64_t entries\n"
"\t\tuint64_t accelerateInfoAddr;\t // (unslid) address of optimization info\n"
"\t\tuint64_t accelerateInfoSize;\t // size of optimization info\n"
"\t\tuint64_t imagesTextOffset;\t\t // file offset to first dyld_cache_image_text_info\n"
"\t\tuint64_t imagesTextCount;\t\t // number of dyld_cache_image_text_info entries\n"
"\t\tuint64_t patchInfoAddr;\t\t\t // (unslid) address of dyld_cache_patch_info\n"
"\t\tuint64_t patchInfoSize;\t // Size of all of the patch information pointed to via the "
"dyld_cache_patch_info\n"
"\t\tuint64_t otherImageGroupAddrUnused;\t // unused\n"
"\t\tuint64_t otherImageGroupSizeUnused;\t // unused\n"
"\t\tuint64_t progClosuresAddr;\t\t\t // (unslid) address of list of program launch closures\n"
"\t\tuint64_t progClosuresSize;\t\t\t // size of list of program launch closures\n"
"\t\tuint64_t progClosuresTrieAddr;\t\t // (unslid) address of trie of indexes into program launch closures\n"
"\t\tuint64_t progClosuresTrieSize;\t\t // size of trie of indexes into program launch closures\n"
"\t\tuint32_t platform;\t\t\t\t\t // platform number (macOS=1, etc)\n"
"\t\tuint32_t formatVersion : 8,\t\t\t // dyld3::closure::kFormatVersion\n"
"\t\t\tdylibsExpectedOnDisk : 1, // dyld should expect the dylib exists on disk and to compare inode/mtime to "
"see if cache is valid\n"
"\t\t\tsimulator : 1,\t\t\t // for simulator of specified platform\n"
"\t\t\tlocallyBuiltCache : 1,\t // 0 for B&I built cache, 1 for locally built cache\n"
"\t\t\tbuiltFromChainedFixups : 1,\t // some dylib in cache was built using chained fixups, so patch tables "
"must be used for overrides\n"
"\t\t\tpadding : 20;\t\t\t\t // TBD\n"
"\t\tuint64_t sharedRegionStart;\t\t // base load address of cache if not slid\n"
"\t\tuint64_t sharedRegionSize;\t\t // overall size required to map the cache and all subCaches, if any\n"
"\t\tuint64_t maxSlide;\t\t\t\t // runtime slide of cache can be between zero and this value\n"
"\t\tuint64_t dylibsImageArrayAddr;\t // (unslid) address of ImageArray for dylibs in this cache\n"
"\t\tuint64_t dylibsImageArraySize;\t // size of ImageArray for dylibs in this cache\n"
"\t\tuint64_t dylibsTrieAddr;\t\t // (unslid) address of trie of indexes of all cached dylibs\n"
"\t\tuint64_t dylibsTrieSize;\t\t // size of trie of cached dylib paths\n"
"\t\tuint64_t otherImageArrayAddr;\t // (unslid) address of ImageArray for dylibs and bundles with dlopen "
"closures\n"
"\t\tuint64_t otherImageArraySize;\t // size of ImageArray for dylibs and bundles with dlopen closures\n"
"\t\tuint64_t otherTrieAddr;\t // (unslid) address of trie of indexes of all dylibs and bundles with dlopen "
"closures\n"
"\t\tuint64_t otherTrieSize;\t // size of trie of dylibs and bundles with dlopen closures\n"
"\t\tuint32_t mappingWithSlideOffset;\t\t // file offset to first dyld_cache_mapping_and_slide_info\n"
"\t\tuint32_t mappingWithSlideCount;\t\t\t // number of dyld_cache_mapping_and_slide_info entries\n"
"\t\tuint64_t dylibsPBLStateArrayAddrUnused;\t // unused\n"
"\t\tuint64_t dylibsPBLSetAddr;\t\t\t\t // (unslid) address of PrebuiltLoaderSet of all cached dylibs\n"
"\t\tuint64_t programsPBLSetPoolAddr;\t\t // (unslid) address of pool of PrebuiltLoaderSet for each program\n"
"\t\tuint64_t programsPBLSetPoolSize;\t\t // size of pool of PrebuiltLoaderSet for each program\n"
"\t\tuint64_t programTrieAddr;\t\t\t\t // (unslid) address of trie mapping program path to PrebuiltLoaderSet\n"
"\t\tuint32_t programTrieSize;\n"
"\t\tuint32_t osVersion;\t\t\t\t// OS Version of dylibs in this cache for the main platform\n"
"\t\tuint32_t altPlatform;\t\t\t// e.g. iOSMac on macOS\n"
"\t\tuint32_t altOsVersion;\t\t\t// e.g. 14.0 for iOSMac\n"
"\t\tuint64_t swiftOptsOffset;\t\t// file offset to Swift optimizations header\n"
"\t\tuint64_t swiftOptsSize;\t\t\t// size of Swift optimizations header\n"
"\t\tuint32_t subCacheArrayOffset;\t// file offset to first dyld_subcache_entry\n"
"\t\tuint32_t subCacheArrayCount;\t// number of subCache entries\n"
"\t\tuint8_t symbolFileUUID[16];\t\t// unique value for the shared cache file containing unmapped local "
"symbols\n"
"\t\tuint64_t rosettaReadOnlyAddr;\t// (unslid) address of the start of where Rosetta can add "
"read-only/executable data\n"
"\t\tuint64_t rosettaReadOnlySize;\t// maximum size of the Rosetta read-only/executable region\n"
"\t\tuint64_t rosettaReadWriteAddr;\t// (unslid) address of the start of where Rosetta can add read-write "
"data\n"
"\t\tuint64_t rosettaReadWriteSize;\t// maximum size of the Rosetta read-write region\n"
"\t\tuint32_t imagesOffset;\t\t\t// file offset to first dyld_cache_image_info\n"
"\t\tuint32_t imagesCount;\t\t\t// number of dyld_cache_image_info entries\n"
"\t\tuint32_t cacheSubType; // 0 for development, 1 for production, when cacheType is "
"multi-cache(2)\n"
"\t\tuint64_t objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header\n"
"\t\tuint64_t objcOptsSize; // size of ObjC optimizations header\n"
"\t\tuint64_t cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process "
"introspection\n"
"\t\tuint64_t cacheAtlasSize; // size of embedded cache atlas\n"
"\t\tuint64_t dynamicDataOffset; // VM offset from cache_header* to the location of "
"dyld_cache_dynamic_data_header\n"
"\t\tuint64_t dynamicDataMaxSize; // maximum size of space reserved from dynamic data\n"
"\t\tuint32_t tproMappingsOffset; // file offset to first dyld_cache_tpro_mapping_info\n"
"\t\tuint32_t tproMappingsCount; // number of dyld_cache_tpro_mapping_info entries\n"
"\t};",
headerType, err);
if (!err.empty() || !headerType.type)
{
logger->LogError("Failed to parse header type: %s", err.c_str());
return false;
}
// Add Mach-O file header type info
EnumerationBuilder cpuTypeBuilder;
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ANY", MACHO_CPU_TYPE_ANY);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_VAX", MACHO_CPU_TYPE_VAX);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC680x0", MACHO_CPU_TYPE_MC680x0);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_X86", MACHO_CPU_TYPE_X86);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_X86_64", MACHO_CPU_TYPE_X86_64);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MIPS", MACHO_CPU_TYPE_MIPS);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC98000", MACHO_CPU_TYPE_MC98000);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_HPPA", MACHO_CPU_TYPE_HPPA);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM", MACHO_CPU_TYPE_ARM);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM64", MACHO_CPU_TYPE_ARM64);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM64_32", MACHO_CPU_TYPE_ARM64_32);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC88000", MACHO_CPU_TYPE_MC88000);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_SPARC", MACHO_CPU_TYPE_SPARC);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_I860", MACHO_CPU_TYPE_I860);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ALPHA", MACHO_CPU_TYPE_ALPHA);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_POWERPC", MACHO_CPU_TYPE_POWERPC);
cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_POWERPC64", MACHO_CPU_TYPE_POWERPC64);
Ref<Enumeration> cpuTypeEnum = cpuTypeBuilder.Finalize();
Ref<Type> cpuTypeEnumType = Type::EnumerationType(nullptr, cpuTypeEnum, 4, false);
std::string cpuTypeEnumName = "cpu_type_t";
std::string cpuTypeEnumId = Type::GenerateAutoTypeId("macho", cpuTypeEnumName);
DefineType(cpuTypeEnumId, cpuTypeEnumName, cpuTypeEnumType);
EnumerationBuilder fileTypeBuilder;
fileTypeBuilder.AddMemberWithValue("MH_OBJECT", MH_OBJECT);
fileTypeBuilder.AddMemberWithValue("MH_EXECUTE", MH_EXECUTE);
fileTypeBuilder.AddMemberWithValue("MH_FVMLIB", MH_FVMLIB);
fileTypeBuilder.AddMemberWithValue("MH_CORE", MH_CORE);
fileTypeBuilder.AddMemberWithValue("MH_PRELOAD", MH_PRELOAD);
fileTypeBuilder.AddMemberWithValue("MH_DYLIB", MH_DYLIB);
fileTypeBuilder.AddMemberWithValue("MH_DYLINKER", MH_DYLINKER);
fileTypeBuilder.AddMemberWithValue("MH_BUNDLE", MH_BUNDLE);
fileTypeBuilder.AddMemberWithValue("MH_DYLIB_STUB", MH_DYLIB_STUB);
fileTypeBuilder.AddMemberWithValue("MH_DSYM", MH_DSYM);
fileTypeBuilder.AddMemberWithValue("MH_KEXT_BUNDLE", MH_KEXT_BUNDLE);
fileTypeBuilder.AddMemberWithValue("MH_FILESET", MH_FILESET);
Ref<Enumeration> fileTypeEnum = fileTypeBuilder.Finalize();
Ref<Type> fileTypeEnumType = Type::EnumerationType(nullptr, fileTypeEnum, 4, false);
std::string fileTypeEnumName = "file_type_t";
std::string fileTypeEnumId = Type::GenerateAutoTypeId("macho", fileTypeEnumName);
DefineType(fileTypeEnumId, fileTypeEnumName, fileTypeEnumType);
EnumerationBuilder flagsTypeBuilder;
flagsTypeBuilder.AddMemberWithValue("MH_NOUNDEFS", MH_NOUNDEFS);
flagsTypeBuilder.AddMemberWithValue("MH_INCRLINK", MH_INCRLINK);
flagsTypeBuilder.AddMemberWithValue("MH_DYLDLINK", MH_DYLDLINK);
flagsTypeBuilder.AddMemberWithValue("MH_BINDATLOAD", MH_BINDATLOAD);
flagsTypeBuilder.AddMemberWithValue("MH_PREBOUND", MH_PREBOUND);
flagsTypeBuilder.AddMemberWithValue("MH_SPLIT_SEGS", MH_SPLIT_SEGS);
flagsTypeBuilder.AddMemberWithValue("MH_LAZY_INIT", MH_LAZY_INIT);
flagsTypeBuilder.AddMemberWithValue("MH_TWOLEVEL", MH_TWOLEVEL);
flagsTypeBuilder.AddMemberWithValue("MH_FORCE_FLAT", MH_FORCE_FLAT);
flagsTypeBuilder.AddMemberWithValue("MH_NOMULTIDEFS", MH_NOMULTIDEFS);
flagsTypeBuilder.AddMemberWithValue("MH_NOFIXPREBINDING", MH_NOFIXPREBINDING);
flagsTypeBuilder.AddMemberWithValue("MH_PREBINDABLE", MH_PREBINDABLE);
flagsTypeBuilder.AddMemberWithValue("MH_ALLMODSBOUND", MH_ALLMODSBOUND);
flagsTypeBuilder.AddMemberWithValue("MH_SUBSECTIONS_VIA_SYMBOLS", MH_SUBSECTIONS_VIA_SYMBOLS);
flagsTypeBuilder.AddMemberWithValue("MH_CANONICAL", MH_CANONICAL);
flagsTypeBuilder.AddMemberWithValue("MH_WEAK_DEFINES", MH_WEAK_DEFINES);
flagsTypeBuilder.AddMemberWithValue("MH_BINDS_TO_WEAK", MH_BINDS_TO_WEAK);
flagsTypeBuilder.AddMemberWithValue("MH_ALLOW_STACK_EXECUTION", MH_ALLOW_STACK_EXECUTION);
flagsTypeBuilder.AddMemberWithValue("MH_ROOT_SAFE", MH_ROOT_SAFE);
flagsTypeBuilder.AddMemberWithValue("MH_SETUID_SAFE", MH_SETUID_SAFE);
flagsTypeBuilder.AddMemberWithValue("MH_NO_REEXPORTED_DYLIBS", MH_NO_REEXPORTED_DYLIBS);
flagsTypeBuilder.AddMemberWithValue("MH_PIE", MH_PIE);
flagsTypeBuilder.AddMemberWithValue("MH_DEAD_STRIPPABLE_DYLIB", MH_DEAD_STRIPPABLE_DYLIB);
flagsTypeBuilder.AddMemberWithValue("MH_HAS_TLV_DESCRIPTORS", MH_HAS_TLV_DESCRIPTORS);
flagsTypeBuilder.AddMemberWithValue("MH_NO_HEAP_EXECUTION", MH_NO_HEAP_EXECUTION);
flagsTypeBuilder.AddMemberWithValue("MH_APP_EXTENSION_SAFE", _MH_APP_EXTENSION_SAFE);
flagsTypeBuilder.AddMemberWithValue("MH_NLIST_OUTOFSYNC_WITH_DYLDINFO", _MH_NLIST_OUTOFSYNC_WITH_DYLDINFO);
flagsTypeBuilder.AddMemberWithValue("MH_SIM_SUPPORT", _MH_SIM_SUPPORT);
flagsTypeBuilder.AddMemberWithValue("MH_DYLIB_IN_CACHE", _MH_DYLIB_IN_CACHE);
Ref<Enumeration> flagsTypeEnum = flagsTypeBuilder.Finalize();
Ref<Type> flagsTypeEnumType = Type::EnumerationType(nullptr, flagsTypeEnum, 4, false);
std::string flagsTypeEnumName = "flags_type_t";
std::string flagsTypeEnumId = Type::GenerateAutoTypeId("macho", flagsTypeEnumName);
DefineType(flagsTypeEnumId, flagsTypeEnumName, flagsTypeEnumType);
StructureBuilder machoHeaderBuilder;
machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "magic");
machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("cpu_type_t")), "cputype");
machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "cpusubtype");
machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("file_type_t")), "filetype");
machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "ncmds");
machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeofcmds");
machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("flags_type_t")), "flags");
if (GetAddressSize() == 8)
machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "reserved");
Ref<Structure> machoHeaderStruct = machoHeaderBuilder.Finalize();
QualifiedName headerName = (GetAddressSize() == 8) ? std::string("mach_header_64") : std::string("mach_header");
std::string headerTypeId = Type::GenerateAutoTypeId("macho", headerName);
Ref<Type> machoHeaderType = Type::StructureType(machoHeaderStruct);
DefineType(headerTypeId, headerName, machoHeaderType);
EnumerationBuilder cmdTypeBuilder;
cmdTypeBuilder.AddMemberWithValue("LC_REQ_DYLD", LC_REQ_DYLD);
cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT", LC_SEGMENT);
cmdTypeBuilder.AddMemberWithValue("LC_SYMTAB", LC_SYMTAB);
cmdTypeBuilder.AddMemberWithValue("LC_SYMSEG", LC_SYMSEG);
cmdTypeBuilder.AddMemberWithValue("LC_THREAD", LC_THREAD);
cmdTypeBuilder.AddMemberWithValue("LC_UNIXTHREAD", LC_UNIXTHREAD);
cmdTypeBuilder.AddMemberWithValue("LC_LOADFVMLIB", LC_LOADFVMLIB);
cmdTypeBuilder.AddMemberWithValue("LC_IDFVMLIB", LC_IDFVMLIB);
cmdTypeBuilder.AddMemberWithValue("LC_IDENT", LC_IDENT);
cmdTypeBuilder.AddMemberWithValue("LC_FVMFILE", LC_FVMFILE);
cmdTypeBuilder.AddMemberWithValue("LC_PREPAGE", LC_PREPAGE);
cmdTypeBuilder.AddMemberWithValue("LC_DYSYMTAB", LC_DYSYMTAB);
cmdTypeBuilder.AddMemberWithValue("LC_LOAD_DYLIB", LC_LOAD_DYLIB);
cmdTypeBuilder.AddMemberWithValue("LC_ID_DYLIB", LC_ID_DYLIB);
cmdTypeBuilder.AddMemberWithValue("LC_LOAD_DYLINKER", LC_LOAD_DYLINKER);
cmdTypeBuilder.AddMemberWithValue("LC_ID_DYLINKER", LC_ID_DYLINKER);
cmdTypeBuilder.AddMemberWithValue("LC_PREBOUND_DYLIB", LC_PREBOUND_DYLIB);
cmdTypeBuilder.AddMemberWithValue("LC_ROUTINES", LC_ROUTINES);
cmdTypeBuilder.AddMemberWithValue("LC_SUB_FRAMEWORK", LC_SUB_FRAMEWORK);
cmdTypeBuilder.AddMemberWithValue("LC_SUB_UMBRELLA", LC_SUB_UMBRELLA);
cmdTypeBuilder.AddMemberWithValue("LC_SUB_CLIENT", LC_SUB_CLIENT);
cmdTypeBuilder.AddMemberWithValue("LC_SUB_LIBRARY", LC_SUB_LIBRARY);
cmdTypeBuilder.AddMemberWithValue("LC_TWOLEVEL_HINTS", LC_TWOLEVEL_HINTS);
cmdTypeBuilder.AddMemberWithValue("LC_PREBIND_CKSUM", LC_PREBIND_CKSUM);
cmdTypeBuilder.AddMemberWithValue("LC_LOAD_WEAK_DYLIB", LC_LOAD_WEAK_DYLIB); // (0x18 | LC_REQ_DYLD)
cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT_64", LC_SEGMENT_64);
cmdTypeBuilder.AddMemberWithValue("LC_ROUTINES_64", LC_ROUTINES_64);
cmdTypeBuilder.AddMemberWithValue("LC_UUID", LC_UUID);
cmdTypeBuilder.AddMemberWithValue("LC_RPATH", LC_RPATH); // (0x1c | LC_REQ_DYLD)
cmdTypeBuilder.AddMemberWithValue("LC_CODE_SIGNATURE", LC_CODE_SIGNATURE);
cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT_SPLIT_INFO", LC_SEGMENT_SPLIT_INFO);
cmdTypeBuilder.AddMemberWithValue("LC_REEXPORT_DYLIB", LC_REEXPORT_DYLIB); // (0x1f | LC_REQ_DYLD)
cmdTypeBuilder.AddMemberWithValue("LC_LAZY_LOAD_DYLIB", LC_LAZY_LOAD_DYLIB);
cmdTypeBuilder.AddMemberWithValue("LC_ENCRYPTION_INFO", LC_ENCRYPTION_INFO);
cmdTypeBuilder.AddMemberWithValue("LC_DYLD_INFO", LC_DYLD_INFO);
cmdTypeBuilder.AddMemberWithValue("LC_DYLD_INFO_ONLY", LC_DYLD_INFO_ONLY); // (0x22 | LC_REQ_DYLD)
cmdTypeBuilder.AddMemberWithValue("LC_LOAD_UPWARD_DYLIB", LC_LOAD_UPWARD_DYLIB); // (0x23 | LC_REQ_DYLD)
cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_MACOSX", LC_VERSION_MIN_MACOSX);
cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_IPHONEOS", LC_VERSION_MIN_IPHONEOS);
cmdTypeBuilder.AddMemberWithValue("LC_FUNCTION_STARTS", LC_FUNCTION_STARTS);
cmdTypeBuilder.AddMemberWithValue("LC_DYLD_ENVIRONMENT", LC_DYLD_ENVIRONMENT);
cmdTypeBuilder.AddMemberWithValue("LC_MAIN", LC_MAIN); // (0x28 | LC_REQ_DYLD)
cmdTypeBuilder.AddMemberWithValue("LC_DATA_IN_CODE", LC_DATA_IN_CODE);
cmdTypeBuilder.AddMemberWithValue("LC_SOURCE_VERSION", LC_SOURCE_VERSION);
cmdTypeBuilder.AddMemberWithValue("LC_DYLIB_CODE_SIGN_DRS", LC_DYLIB_CODE_SIGN_DRS);
cmdTypeBuilder.AddMemberWithValue("LC_ENCRYPTION_INFO_64", _LC_ENCRYPTION_INFO_64);
cmdTypeBuilder.AddMemberWithValue("LC_LINKER_OPTION", _LC_LINKER_OPTION);
cmdTypeBuilder.AddMemberWithValue("LC_LINKER_OPTIMIZATION_HINT", _LC_LINKER_OPTIMIZATION_HINT);
cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_TVOS", _LC_VERSION_MIN_TVOS);
cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_WATCHOS", LC_VERSION_MIN_WATCHOS);
cmdTypeBuilder.AddMemberWithValue("LC_NOTE", LC_NOTE);
cmdTypeBuilder.AddMemberWithValue("LC_BUILD_VERSION", LC_BUILD_VERSION);
cmdTypeBuilder.AddMemberWithValue("LC_DYLD_EXPORTS_TRIE", LC_DYLD_EXPORTS_TRIE);
cmdTypeBuilder.AddMemberWithValue("LC_DYLD_CHAINED_FIXUPS", LC_DYLD_CHAINED_FIXUPS);
cmdTypeBuilder.AddMemberWithValue("LC_FILESET_ENTRY", LC_FILESET_ENTRY);
Ref<Enumeration> cmdTypeEnum = cmdTypeBuilder.Finalize();
Ref<Type> cmdTypeEnumType = Type::EnumerationType(nullptr, cmdTypeEnum, 4, false);
std::string cmdTypeEnumName = "load_command_type_t";
std::string cmdTypeEnumId = Type::GenerateAutoTypeId("macho", cmdTypeEnumName);
DefineType(cmdTypeEnumId, cmdTypeEnumName, cmdTypeEnumType);
StructureBuilder loadCommandBuilder;
loadCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
loadCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
Ref<Structure> loadCommandStruct = loadCommandBuilder.Finalize();
QualifiedName loadCommandName = std::string("load_command");
std::string loadCommandTypeId = Type::GenerateAutoTypeId("macho", loadCommandName);
Ref<Type> loadCommandType = Type::StructureType(loadCommandStruct);
DefineType(loadCommandTypeId, loadCommandName, loadCommandType);
EnumerationBuilder protTypeBuilder;
protTypeBuilder.AddMemberWithValue("VM_PROT_NONE", MACHO_VM_PROT_NONE);
protTypeBuilder.AddMemberWithValue("VM_PROT_READ", MACHO_VM_PROT_READ);
protTypeBuilder.AddMemberWithValue("VM_PROT_WRITE", MACHO_VM_PROT_WRITE);
protTypeBuilder.AddMemberWithValue("VM_PROT_EXECUTE", MACHO_VM_PROT_EXECUTE);
// protTypeBuilder.AddMemberWithValue("VM_PROT_DEFAULT", MACHO_VM_PROT_DEFAULT);
// protTypeBuilder.AddMemberWithValue("VM_PROT_ALL", MACHO_VM_PROT_ALL);
protTypeBuilder.AddMemberWithValue("VM_PROT_NO_CHANGE", MACHO_VM_PROT_NO_CHANGE);
protTypeBuilder.AddMemberWithValue("VM_PROT_COPY_OR_WANTS_COPY", MACHO_VM_PROT_COPY);
// protTypeBuilder.AddMemberWithValue("VM_PROT_WANTS_COPY", MACHO_VM_PROT_WANTS_COPY);
Ref<Enumeration> protTypeEnum = protTypeBuilder.Finalize();
Ref<Type> protTypeEnumType = Type::EnumerationType(nullptr, protTypeEnum, 4, false);
std::string protTypeEnumName = "vm_prot_t";
std::string protTypeEnumId = Type::GenerateAutoTypeId("macho", protTypeEnumName);
DefineType(protTypeEnumId, protTypeEnumName, protTypeEnumType);
EnumerationBuilder segFlagsTypeBuilder;
segFlagsTypeBuilder.AddMemberWithValue("SG_HIGHVM", SG_HIGHVM);
segFlagsTypeBuilder.AddMemberWithValue("SG_FVMLIB", SG_FVMLIB);
segFlagsTypeBuilder.AddMemberWithValue("SG_NORELOC", SG_NORELOC);
segFlagsTypeBuilder.AddMemberWithValue("SG_PROTECTED_VERSION_1", SG_PROTECTED_VERSION_1);
Ref<Enumeration> segFlagsTypeEnum = segFlagsTypeBuilder.Finalize();
Ref<Type> segFlagsTypeEnumType = Type::EnumerationType(nullptr, segFlagsTypeEnum, 4, false);
std::string segFlagsTypeEnumName = "sg_flags_t";
std::string segFlagsTypeEnumId = Type::GenerateAutoTypeId("macho", segFlagsTypeEnumName);
DefineType(segFlagsTypeEnumId, segFlagsTypeEnumName, segFlagsTypeEnumType);
StructureBuilder loadSegmentCommandBuilder;
loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
loadSegmentCommandBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "vmaddr");
loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "vmsize");
loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "fileoff");
loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "filesize");
loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "maxprot");
loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "initprot");
loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "nsects");
loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("sg_flags_t")), "flags");
Ref<Structure> loadSegmentCommandStruct = loadSegmentCommandBuilder.Finalize();
QualifiedName loadSegmentCommandName = std::string("segment_command");
std::string loadSegmentCommandTypeId = Type::GenerateAutoTypeId("macho", loadSegmentCommandName);
Ref<Type> loadSegmentCommandType = Type::StructureType(loadSegmentCommandStruct);
DefineType(loadSegmentCommandTypeId, loadSegmentCommandName, loadSegmentCommandType);
StructureBuilder loadSegmentCommand64Builder;
loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
loadSegmentCommand64Builder.AddMember(Type::IntegerType(4, false), "cmdsize");
loadSegmentCommand64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "vmaddr");
loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "vmsize");
loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "fileoff");
loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "filesize");
loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "maxprot");
loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "initprot");
loadSegmentCommand64Builder.AddMember(Type::IntegerType(4, false), "nsects");
loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("sg_flags_t")), "flags");
Ref<Structure> loadSegmentCommand64Struct = loadSegmentCommand64Builder.Finalize();
QualifiedName loadSegment64CommandName = std::string("segment_command_64");
std::string loadSegment64CommandTypeId = Type::GenerateAutoTypeId("macho", loadSegment64CommandName);
Ref<Type> loadSegment64CommandType = Type::StructureType(loadSegmentCommand64Struct);
DefineType(loadSegment64CommandTypeId, loadSegment64CommandName, loadSegment64CommandType);
StructureBuilder sectionBuilder;
sectionBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "sectname");
sectionBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
sectionBuilder.AddMember(Type::IntegerType(4, false), "addr");
sectionBuilder.AddMember(Type::IntegerType(4, false), "size");
sectionBuilder.AddMember(Type::IntegerType(4, false), "offset");
sectionBuilder.AddMember(Type::IntegerType(4, false), "align");
sectionBuilder.AddMember(Type::IntegerType(4, false), "reloff");
sectionBuilder.AddMember(Type::IntegerType(4, false), "nreloc");
sectionBuilder.AddMember(Type::IntegerType(4, false), "flags");
sectionBuilder.AddMember(Type::IntegerType(4, false), "reserved1");
sectionBuilder.AddMember(Type::IntegerType(4, false), "reserved2");
Ref<Structure> sectionStruct = sectionBuilder.Finalize();
QualifiedName sectionName = std::string("section");
std::string sectionTypeId = Type::GenerateAutoTypeId("macho", sectionName);
Ref<Type> sectionType = Type::StructureType(sectionStruct);
DefineType(sectionTypeId, sectionName, sectionType);
StructureBuilder section64Builder;
section64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "sectname");
section64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
section64Builder.AddMember(Type::IntegerType(8, false), "addr");
section64Builder.AddMember(Type::IntegerType(8, false), "size");
section64Builder.AddMember(Type::IntegerType(4, false), "offset");
section64Builder.AddMember(Type::IntegerType(4, false), "align");
section64Builder.AddMember(Type::IntegerType(4, false), "reloff");
section64Builder.AddMember(Type::IntegerType(4, false), "nreloc");
section64Builder.AddMember(Type::IntegerType(4, false), "flags");
section64Builder.AddMember(Type::IntegerType(4, false), "reserved1");
section64Builder.AddMember(Type::IntegerType(4, false), "reserved2");
section64Builder.AddMember(Type::IntegerType(4, false), "reserved3");
Ref<Structure> section64Struct = section64Builder.Finalize();
QualifiedName section64Name = std::string("section_64");
std::string section64TypeId = Type::GenerateAutoTypeId("macho", section64Name);
Ref<Type> section64Type = Type::StructureType(section64Struct);
DefineType(section64TypeId, section64Name, section64Type);
StructureBuilder symtabBuilder;
symtabBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
symtabBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
symtabBuilder.AddMember(Type::IntegerType(4, false), "symoff");
symtabBuilder.AddMember(Type::IntegerType(4, false), "nsyms");
symtabBuilder.AddMember(Type::IntegerType(4, false), "stroff");
symtabBuilder.AddMember(Type::IntegerType(4, false), "strsize");
Ref<Structure> symtabStruct = symtabBuilder.Finalize();
QualifiedName symtabName = std::string("symtab");
std::string symtabTypeId = Type::GenerateAutoTypeId("macho", symtabName);
Ref<Type> symtabType = Type::StructureType(symtabStruct);
DefineType(symtabTypeId, symtabName, symtabType);
StructureBuilder dynsymtabBuilder;
dynsymtabBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "ilocalsym");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nlocalsym");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "iextdefsym");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextdefsym");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "iundefsym");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nundefsym");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "tocoff");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "ntoc");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "modtaboff");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nmodtab");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "extrefsymoff");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextrefsyms");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "indirectsymoff");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nindirectsyms");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "extreloff");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextrel");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "locreloff");
dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nlocrel");
Ref<Structure> dynsymtabStruct = dynsymtabBuilder.Finalize();
QualifiedName dynsymtabName = std::string("dynsymtab");
std::string dynsymtabTypeId = Type::GenerateAutoTypeId("macho", dynsymtabName);
Ref<Type> dynsymtabType = Type::StructureType(dynsymtabStruct);
DefineType(dynsymtabTypeId, dynsymtabName, dynsymtabType);
StructureBuilder uuidBuilder;
uuidBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
uuidBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
uuidBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, false), 16), "uuid");
Ref<Structure> uuidStruct = uuidBuilder.Finalize();
QualifiedName uuidName = std::string("uuid");
std::string uuidTypeId = Type::GenerateAutoTypeId("macho", uuidName);
Ref<Type> uuidType = Type::StructureType(uuidStruct);
DefineType(uuidTypeId, uuidName, uuidType);
StructureBuilder linkeditDataBuilder;
linkeditDataBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "dataoff");
linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "datasize");
Ref<Structure> linkeditDataStruct = linkeditDataBuilder.Finalize();
QualifiedName linkeditDataName = std::string("linkedit_data");
std::string linkeditDataTypeId = Type::GenerateAutoTypeId("macho", linkeditDataName);
Ref<Type> linkeditDataType = Type::StructureType(linkeditDataStruct);
DefineType(linkeditDataTypeId, linkeditDataName, linkeditDataType);
StructureBuilder encryptionInfoBuilder;
encryptionInfoBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptoff");
encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptsize");
encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptid");
Ref<Structure> encryptionInfoStruct = encryptionInfoBuilder.Finalize();
QualifiedName encryptionInfoName = std::string("encryption_info");
std::string encryptionInfoTypeId = Type::GenerateAutoTypeId("macho", encryptionInfoName);
Ref<Type> encryptionInfoType = Type::StructureType(encryptionInfoStruct);
DefineType(encryptionInfoTypeId, encryptionInfoName, encryptionInfoType);
StructureBuilder versionMinBuilder;
versionMinBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
versionMinBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
versionMinBuilder.AddMember(Type::IntegerType(4, false), "version");
versionMinBuilder.AddMember(Type::IntegerType(4, false), "sdk");
Ref<Structure> versionMinStruct = versionMinBuilder.Finalize();
QualifiedName versionMinName = std::string("version_min");
std::string versionMinTypeId = Type::GenerateAutoTypeId("macho", versionMinName);
Ref<Type> versionMinType = Type::StructureType(versionMinStruct);
DefineType(versionMinTypeId, versionMinName, versionMinType);
StructureBuilder dyldInfoBuilder;
dyldInfoBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "rebase_off");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "rebase_size");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "bind_off");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "bind_size");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "weak_bind_off");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "weak_bind_size");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "lazy_bind_off");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "lazy_bind_size");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "export_off");
dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "export_size");
Ref<Structure> dyldInfoStruct = dyldInfoBuilder.Finalize();
QualifiedName dyldInfoName = std::string("dyld_info");
std::string dyldInfoTypeId = Type::GenerateAutoTypeId("macho", dyldInfoName);
Ref<Type> dyldInfoType = Type::StructureType(dyldInfoStruct);
DefineType(dyldInfoTypeId, dyldInfoName, dyldInfoType);
StructureBuilder dylibBuilder;
dylibBuilder.AddMember(Type::IntegerType(4, false), "name");
dylibBuilder.AddMember(Type::IntegerType(4, false), "timestamp");
dylibBuilder.AddMember(Type::IntegerType(4, false), "current_version");
dylibBuilder.AddMember(Type::IntegerType(4, false), "compatibility_version");
Ref<Structure> dylibStruct = dylibBuilder.Finalize();
QualifiedName dylibName = std::string("dylib");
std::string dylibTypeId = Type::GenerateAutoTypeId("macho", dylibName);
Ref<Type> dylibType = Type::StructureType(dylibStruct);
DefineType(dylibTypeId, dylibName, dylibType);
StructureBuilder dylibCommandBuilder;
dylibCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
dylibCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
dylibCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("dylib")), "dylib");
Ref<Structure> dylibCommandStruct = dylibCommandBuilder.Finalize();
QualifiedName dylibCommandName = std::string("dylib_command");
std::string dylibCommandTypeId = Type::GenerateAutoTypeId("macho", dylibCommandName);
Ref<Type> dylibCommandType = Type::StructureType(dylibCommandStruct);
DefineType(dylibCommandTypeId, dylibCommandName, dylibCommandType);
StructureBuilder filesetEntryCommandBuilder;
filesetEntryCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
filesetEntryCommandBuilder.AddMember(Type::IntegerType(8, false), "vmaddr");
filesetEntryCommandBuilder.AddMember(Type::IntegerType(8, false), "fileoff");
filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "entry_id");
filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "reserved");
Ref<Structure> filesetEntryCommandStruct = filesetEntryCommandBuilder.Finalize();
QualifiedName filesetEntryCommandName = std::string("fileset_entry_command");
std::string filesetEntryCommandTypeId = Type::GenerateAutoTypeId("macho", filesetEntryCommandName);
Ref<Type> filesetEntryCommandType = Type::StructureType(filesetEntryCommandStruct);
DefineType(filesetEntryCommandTypeId, filesetEntryCommandName, filesetEntryCommandType);
// uint32_t at 0x10 is offset to mapping table.
// first mapping struct in that table is base of primary
// first uint64_t in that struct is the base address of the primary
// double gpv here because DSCRaw explicitly stops at the start of this mapping table
uint64_t basePointer = 0;
GetParentView()->Read(&basePointer, 16, 4);
if (basePointer == 0)
{
logger->LogError("Failed to read base pointer");
return false;
}
uint64_t primaryBase = 0;
GetParentView()->Read(&primaryBase, basePointer, 8);
if (primaryBase == 0)
{
logger->LogError("Failed to read primary base at 0x%llx", basePointer);
return false;
}
uint64_t headerSize = std::min(basePointer, headerType.type->GetWidth());
// Truncate the `dyld_cache_header` structure to the structure present in the cache file.
auto newStructure = StructureBuilder(headerType.type->GetStructure()).SetWidth(headerSize).Finalize();
headerType.type = TypeBuilder::StructureType(newStructure).Finalize();
AddAutoSegment(primaryBase, headerSize, 0, headerSize, SegmentReadable);
AddAutoSection("__dsc_header", primaryBase, headerSize, ReadOnlyDataSectionSemantics);
DefineType("dyld_cache_header", headerType.name, headerType.type);
DefineAutoSymbolAndVariableOrFunction(
GetDefaultPlatform(), new Symbol(DataSymbol, "primary_cache_header", primaryBase), headerType.type);
auto sharedCache = SharedCache(GetAddressSize());
{
// Add up all the cache entries using the cache processor.
// After this we should have all the mappings available as well.
CacheProcessor cacheProcessor = CacheProcessor(this);
auto startTime = std::chrono::high_resolution_clock::now();
bool result = cacheProcessor.ProcessCache(sharedCache);
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
logger->LogInfo("Processing %zu entries took %.3f seconds", sharedCache.GetEntries().size(), elapsed.count());
if (!result)
{
// TODO: Prompt the user to select the primary cache file? We can still recover from here.
// Oh no, we failed to process the cache, this likely means the primary on-disk file was not able to be found.
logger->LogError("Failed to process cache, likely missing cache files.");
// NOTE: An interaction handler headlessly could select yes to this, however for the purposes of this we will just let them continue by defualt.
if (IsUIEnabled() && ShowMessageBox("Continue opening", "This shared cache file was unable to be processed, would you like to open without shared cache information?", YesNoButtonSet, QuestionIcon) != YesButton)
return false;
// Skip all the other shared cache stuff.
return true;
}
}
{
// Write all the slide info pointers to the virtual memory.
// This should be done before any other work begins, as the backing data will be altered by this process.
auto startTime = std::chrono::high_resolution_clock::now();
for (const auto& [_, entry] : sharedCache.GetEntries())
sharedCache.ProcessEntrySlideInfo(entry);
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
logger->LogInfo("Processing slide info took %.3f seconds", elapsed.count());
}
{
// Load up all images into the cache before adding extra regions.
// Currently, it is expected that a primary entry contain all relevant images, so we only check that one.
auto startTime = std::chrono::high_resolution_clock::now();
for (const auto& [_, entry] : sharedCache.GetEntries())
if (entry.GetType() == CacheEntryType::Primary)
sharedCache.ProcessEntryImages(entry);
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
auto images = sharedCache.GetImages();
logger->LogInfo("Processing %zu images took %.3f seconds", images.size(), elapsed.count());
// Warn if we found no images, and provide the likely explanation
if (images.empty())
logger->LogWarn("Failed to process any images, likely missing cache files.");
}
{
// TODO: Run this up on a separate thread maybe and have callback notifications?
// Load up all the regions into the cache.
auto startTime = std::chrono::high_resolution_clock::now();
for (const auto& [_, entry] : sharedCache.GetEntries())
sharedCache.ProcessEntryRegions(entry);
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
logger->LogInfo("Processing %zu regions took %.3f seconds", sharedCache.GetRegions().size(), elapsed.count());
}
auto cacheController = SharedCacheController::Initialize(*this, std::move(sharedCache));
// Users can adjust which images are loaded by default using the `loader.dsc.autoLoadPattern` setting.
std::string autoLoadPattern = ".*libsystem_c.dylib";
if (settings && settings->Contains("loader.dsc.autoLoadPattern"))
autoLoadPattern = settings->Get<std::string>("loader.dsc.autoLoadPattern", this);
logger->LogDebug("Loading images using pattern: %s", autoLoadPattern.c_str());
std::regex autoLoadRegex(autoLoadPattern);
for (const auto& [_, image] : cacheController->GetCache().GetImages())
if (std::regex_match(image.GetName(), autoLoadRegex))
cacheController->ApplyImage(*this, image);
return true;
}
|