-
Notifications
You must be signed in to change notification settings - Fork 280
Expand file tree
/
Copy pathSharedCacheView.cpp
More file actions
1094 lines (978 loc) · 56.7 KB
/
SharedCacheView.cpp
File metadata and controls
1094 lines (978 loc) · 56.7 KB
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
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "SharedCacheView.h"
#include <regex>
#include <filesystem>
#include "SharedCacheController.h"
#include "SharedCacheBuilder.h"
using namespace BinaryNinja;
using namespace BinaryNinja::DSC;
static const char* VIEW_METADATA_KEY = "shared_cache_view";
SharedCacheViewType::SharedCacheViewType() : BinaryViewType(VIEW_NAME, VIEW_NAME) {}
// We register all our one-shot stuff here, such as the object destructor.
void SharedCacheViewType::Register()
{
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())
{
LogWarnF("Failed to initialize view of type '{}'. 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);
}
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."
})");
// Place the synthetic sections well after the shared cache to ensure they do
// not collide with any images that are later loaded from the shared cache.
// We do not have easy access to the size of the shared cache's mapping here
// so we use a large fixed offset.
// TODO: This will have to be updated if we add support for 32-bit shared caches.
const uint64_t syntheticSectionsOffset = 12ull * 1024 * 1024 * 1024;
settings->UpdateProperty("loader.syntheticSectionBase", "default", viewRef->GetStart() + syntheticSectionsOffset);
// 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)
{
// By default, we will assume the primary file name from the original file path.
// This is subject to be overridden via `LoadMetadata`.
m_primaryFileName = BaseFileName(GetFile()->GetOriginalFilename());
// Load up the metadata from the parent view (because our metadata is hilariously not available during view init)
if (const auto metadata = GetParentView()->QueryMetadata(VIEW_METADATA_KEY))
LoadMetadata(*metadata);
}
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,
DSCPlatformDriverKit = 10,
DSCPlatformVisionOS = 11, // Apple Vision Pro
DSCPlatformVisionOSSimulator = 12 // Apple Vision Pro Simulator
};
bool SharedCacheView::Init()
{
std::string os;
std::string arch;
m_logger = new Logger("SharedCache.View", GetFile()->GetSessionId());
char magic[17];
GetParentView()->Read(&magic, 0, 16);
magic[16] = 0;
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
{
m_logger->LogErrorF("Unknown magic: {:?}", magic);
return false;
}
// Use the value of mappingOffset as an upper bound for the size of the
// header to avoid misinterpreting bytes outside of the header.
uint32_t mappingOffset;
GetParentView()->Read(&mappingOffset, 0x10, 4);
uint32_t platform;
if (mappingOffset >= 0xd8 + 4) {
GetParentView()->Read(&platform, 0xd8, 4);
} else {
m_logger->LogWarn("Old header without platform field: Defaulting to iOS");
platform = DSCPlatformiOS;
}
switch (platform)
{
case DSCPlatformMacOS:
case DSCPlatformTVOS:
case DSCPlatformTVOSSimulator:
os = "mac";
break;
case DSCPlatformiOS:
case DSCPlatformiOSSimulator:
case DSCPlatformVisionOS:
case DSCPlatformVisionOSSimulator:
os = "ios";
break;
case DSCPlatformDriverKit:
// TODO: The same platform value is used for both macOS and iOS DriverKit shared caches.
// Until we have a way to differentiate them, default to macOS.
os = "mac";
break;
// armv7 or slide info v1 (unsupported)
case DSCPlatformWatchOS:
case DSCPlatformWatchOSSimulator:
case DSCPlatformBridgeOS:
m_logger->LogErrorF("Unsupported platform: {}", platform);
return false;
default:
m_logger->LogWarnF("Unknown platform: {}", platform);
return false;
}
SetDefaultPlatform(Platform::GetByName(os + "-" + arch));
SetDefaultArchitecture(Architecture::GetByName(arch));
Ref<Settings> settings = GetLoadSettings(GetTypeName());
if (!settings)
{
Ref<Settings> programSettings = Settings::Instance();
auto previousWorkflow = programSettings->Get<std::string>("analysis.workflows.functionWorkflow", this);
// Earlier versions of the shared cache plug-in used a named workflow rather than
// modifying `core.function.metaAnalysis`. Update reference to those older workflow
// names to `core.function.metaAnalysis`.
if (previousWorkflow == "core.function.dsc" || previousWorkflow == "core.function.sharedCache")
programSettings->Set("analysis.workflows.functionWorkflow", "core.function.metaAnalysis", 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)
{
m_logger->LogErrorF("Failed to parse header type: {}", err);
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)
{
m_logger->LogError("Failed to read base pointer");
return false;
}
uint64_t primaryBase = 0;
GetParentView()->Read(&primaryBase, basePointer, 8);
if (primaryBase == 0)
{
m_logger->LogErrorF("Failed to read primary base at {:#x}", 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);
if (GetFile()->GetFilename().empty())
{
// We have initialized the view with no backing file.
// We are going to forgo initialization of shared cache controller, as there is no way to populate entries.
// This can occur when downloading shared cache files from a remote project. In the collaboration core it will
// call view init to push metadata about the remote IIRC.
LogInfo("No backing file, skipping shared cache controller initialization...");
return true;
}
return InitController();
}
bool SharedCacheView::InitController()
{
auto primaryFilePath = GetPrimaryFilePath();
if (!primaryFilePath.has_value())
{
m_logger->LogError("Failed to get primary file path!");
return false;
}
std::string primaryFileDir = std::filesystem::path(*primaryFilePath).parent_path().string();
// Get the primary project file from the current files project.
// This is required to allow selecting a primary file in a different directory. Otherwise, we search the current database directory.
Ref<ProjectFile> primaryProjectFile = nullptr;
auto currentProjectFile = GetFile()->GetProjectFile();
if (currentProjectFile)
primaryProjectFile = currentProjectFile->GetProject()->GetFileByPathOnDisk(*primaryFilePath);
if (!IsSameFolderForFile(primaryProjectFile, currentProjectFile))
{
// TODO: Remove this restriction using stored cache UUID's and a fast project file search.
m_logger->LogWarn("Because the primary file is in a different project folder you will need to select it on every open, consider moving the database file into the same folder.");
}
// OK, we have the primary shared cache file, now let's add the entries.
auto sharedCacheBuilder = SharedCacheBuilder(this);
sharedCacheBuilder.SetPrimaryFileName(m_primaryFileName);
// Add the primary file. If we fail log alert that the primary cache file is invalid.
// We process the primary cache entry first as it might be consulted in the processing of later entries.
if (!sharedCacheBuilder.AddFile(*primaryFilePath, m_primaryFileName, CacheEntryType::Primary))
{
m_logger->LogAlertF("Failed to add primary cache file: '{}'", m_primaryFileName);
return false;
}
{
// After this we should have all the mappings available as well.
auto startTime = std::chrono::high_resolution_clock::now();
if (primaryProjectFile)
sharedCacheBuilder.AddProjectFolder(primaryProjectFile->GetFolder());
else
sharedCacheBuilder.AddDirectory(primaryFileDir);
auto totalEntries = sharedCacheBuilder.GetCache().GetEntries().size();
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
m_logger->LogInfoF("Processing {} entries took {:.3f} seconds", totalEntries, elapsed.count());
// Verify that we are not missing any entries that were stored in the metadata.
// If we are that means we should alert the user that a previously associated cache entry is missing.
std::set<std::string> missingCacheEntries = m_secondaryFileNames;
std::optional<uint64_t> expectedFileCount;
for (const auto& entry : sharedCacheBuilder.GetCache().GetEntries())
{
missingCacheEntries.erase(entry.GetFileName());
LogSecondaryFileName(entry.GetFileName());
// Set the number of sub-caches so we can verify it later.
if (entry.GetType() == CacheEntryType::Primary)
{
const auto& entryHeader = entry.GetHeader();
if (expectedFileCount)
m_logger->LogWarnF("Multiple primary cache files found for '{}'.", m_primaryFileName);
// TODO: Some caches seem to have fewer sub caches than what we report having.
expectedFileCount = 1 + entryHeader.subCacheArrayCount;
}
}
for (const auto& missingFileName: missingCacheEntries)
m_logger->LogErrorF("Secondary cache file '{}' is missing!", missingFileName);
// Verify that we have the required amount of sub-caches, if not alert the user.
if (!expectedFileCount)
m_logger->LogWarnF("Did not find a primary cache file for '{}'! You are likely opening a secondary cache file instead of a primary one.", m_primaryFileName);
else if (totalEntries < expectedFileCount)
m_logger->LogWarnF("Insufficient cache files in dyld header ({}/{}), loading as partial shared cache...", totalEntries, *expectedFileCount);
}
auto sharedCache = sharedCacheBuilder.Finalize();
{
// 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;
m_logger->LogInfoF("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;
const auto& images = sharedCache.GetImages();
m_logger->LogInfoF("Processing {} images took {:.3f} seconds", images.size(), elapsed.count());
// Warn if we found no images, and provide the likely explanation
if (images.empty())
m_logger->LogWarn("Failed to process any images, likely missing cache files.");
}
{
// 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;
m_logger->LogInfoF("Processing {} regions took {:.3f} seconds", sharedCache.GetRegions().size(), elapsed.count());
}
// TODO: Here we should have all the regions and what not for the virtual memory populated, I think it might be a good idea
// TODO: To verify the regions are here and pointing at valid file accessor mappings, to make diagnosing issues quicker.
auto cacheController = SharedCacheController::Initialize(*this, std::move(sharedCache));
{
auto logger = m_logger;
// Load up all the symbols into the named symbols lookup map.
// NOTE: We do this on a separate thread as image & region loading does not consult this.
WorkerPriorityEnqueue([logger, cacheController]() {
auto& sharedCache = cacheController->GetCache();
auto startTime = std::chrono::high_resolution_clock::now();
sharedCache.ProcessSymbols();
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
logger->LogInfoF("Processing {} symbols took {:.3f} seconds (separate thread)", sharedCache.GetSymbols().size(), elapsed.count());
});
}
Ref<Settings> settings = GetLoadSettings(GetTypeName());
// 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);
m_logger->LogDebugF("Loading images using pattern: {:?}", autoLoadPattern);
{
// TODO: Refusing to add undo action "Added section libsystem_c.dylib::__macho_header", there is literally
// TODO: no way around this warning as undo actions are implicit with user sections, for more detail see:
// TODO: - https://github.com/Vector35/binaryninja-api/issues/6742
// TODO: - https://github.com/Vector35/binaryninja-api/issues/6289
// Load all images that match the `autoLoadPattern`.
auto startTime = std::chrono::high_resolution_clock::now();
size_t loadedImages = 0;
std::regex autoLoadRegex(autoLoadPattern);
for (const auto& [_, image] : cacheController->GetCache().GetImages())
if (std::regex_match(image.GetName(), autoLoadRegex))
if (cacheController->ApplyImage(*this, image))
++loadedImages;
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = endTime - startTime;
m_logger->LogInfoF("Automatically loading {} images took {:.3f} seconds", loadedImages, elapsed.count());
}
return true;
}
void SharedCacheView::OnAfterSnapshotDataApplied()
{
if (auto controller = SharedCacheController::FromView(*this))
controller->ProcessObjCForLoadedImages(*this);
}
void SharedCacheView::SetPrimaryFileName(std::string primaryFileName)
{
m_primaryFileName = std::move(primaryFileName);
GetParentView()->StoreMetadata(VIEW_METADATA_KEY, GetMetadata());
}
void SharedCacheView::LogSecondaryFileName(std::string secondaryFileName)
{
m_secondaryFileNames.insert(std::move(secondaryFileName));