//------------------------------------------------ //--- 010 Editor v10.0.1 Binary Template // // File: PBL.bt // Authors: blacktop // Version: 1.0 // Purpose: // Category: Executable // File Mask: // ID Bytes: 64 34 70 73 // History: //------------------------------------------------ typedef struct { char magic[4]; // "d4ps" uint32 versionHash; // PREBUILTLOADER_VERSION uint32 length; uint32 loadersArrayCount; uint32 loadersArrayOffset; uint32 cachePatchCount; uint32 cachePatchOffset; uint32 dyldCacheUUIDOffset; uint32 mustBeMissingPathsCount; uint32 mustBeMissingPathsOffset; // ObjC prebuilt data uint32 objcSelectorHashTableOffset; uint32 objcClassHashTableOffset; uint32 objcProtocolHashTableOffset; uint32 reserved; uint64 objcProtocolClassCacheOffset; // Swift prebuilt data uint32 swiftTypeConformanceTableOffset; uint32 swiftMetadataConformanceTableOffset; uint32 swiftForeignTypeConformanceTableOffset; } PBLSetHeader; typedef struct { uint16 index : 15; // index into PrebuiltLoaderSet uint16 app : 1; // app vs dyld cache PrebuiltLoaderSet } LoaderRef; typedef struct { char magic[4]; // "dy4l" uint16 isPrebuilt : 1; // PrebuiltLoader vs JustInTimeLoader uint16 dylibInDyldCache : 1; uint16 hasObjC : 1; uint16 mayHavePlusLoad : 1; uint16 hasReadOnlyData : 1; // __DATA_CONST. Don't use directly. Use hasConstantSegmentsToProtect() uint16 neverUnload : 1; // part of launch or has non-unloadable data (e.g. objc, tlv) uint16 leaveMapped : 1; // RTLD_NODELETE uint16 hasReadOnlyObjC : 1; // Has __DATA_CONST,__objc_selrefs section uint16 pre2022Binary : 1; uint16 isPremapped : 1; // mapped by exclave core uint16 hasUUIDLoadCommand : 1; uint16 hasWeakDefs : 1; uint16 hasTLVs : 1; uint16 belowLibSystem : 1; uint16 padding : 2; LoaderRef ref; } PBLLoader; typedef struct { uint32 fileOffset; uint32 size; } CodeSignatureInFile; typedef enum { // TEXT: _dyld_section_location_text_swift5_protos = 0x0, _dyld_section_location_text_swift5_proto, _dyld_section_location_text_swift5_types, _dyld_section_location_text_swift5_replace, _dyld_section_location_text_swift5_replace2, _dyld_section_location_text_swift5_ac_funcs, // DATA*: _dyld_section_location_objc_image_info, _dyld_section_location_data_sel_refs, _dyld_section_location_data_msg_refs, _dyld_section_location_data_class_refs, _dyld_section_location_data_super_refs, _dyld_section_location_data_protocol_refs, _dyld_section_location_data_class_list, _dyld_section_location_data_non_lazy_class_list, _dyld_section_location_data_stub_list, _dyld_section_location_data_category_list, _dyld_section_location_data_category_list2, _dyld_section_location_data_non_lazy_category_list, _dyld_section_location_data_protocol_list, _dyld_section_location_data_objc_fork_ok, _dyld_section_location_data_raw_isa, // Note, always add new entries before this _dyld_section_location_count, } _dyld_section_location_kind; typedef struct { uint32 version; // = 1; uint32 flags; // = 0; uint64 offsets[_dyld_section_location_count]; uint64 sizes[_dyld_section_location_count]; } SectionLocations; typedef struct { uint16 pathOffset; uint16 dependentLoaderRefsArrayOffset; // offset to array of LoaderRef uint16 dependentKindArrayOffset; // zero if all deps normal uint16 fixupsLoadCommandOffset; uint16 altPathOffset; // if install_name does not match real path uint16 fileValidationOffset; // zero or offset to FileValidationInfo uint16 hasInitializers : 1, isOverridable : 1, // if in dyld cache, can roots override it supportsCatalyst : 1, // if false, this cannot be used in catalyst process isCatalystOverride : 1, // catalyst side of unzippered twin regionsCount : 12; uint16 regionsOffset; // offset to Region array uint16 depCount; uint16 bindTargetRefsOffset; uint32 bindTargetRefsCount; // bind targets can be large, so it is last // After this point, all offsets in to the PrebuiltLoader need to be 32-bits as the bind targets can be large uint32 objcBinaryInfoOffset; // zero or offset to ObjCBinaryInfo uint16 indexOfTwin; // if in dyld cache and part of unzippered twin, then index of the other twin uint16 reserved1; uint64 exportsTrieLoaderOffset; uint32 exportsTrieLoaderSize; uint32 vmSpace; CodeSignatureInFile codeSignature; uint32 patchTableOffset; uint32 overrideBindTargetRefsOffset; uint32 overrideBindTargetRefsCount; uint32 NEW_FIELD_OR_PADDING; // 🆕 SectionLocations sectionLocations; } PBLHeader; typedef ubyte Uuid[16]; string readimagename(PBLHeader &hdr) { local uint32 off; off = startof(hdr) - sizeof(PBLLoader); // VERSION_1 // off = startof(hdr) - sizeof(PBLLoader) - sizeof(Uuid) - 8; // VERSION_2 return ReadString( off + hdr.pathOffset ); } string readUUID(Uuid uuid) { local string ret, tmp; local int i; for (i = 0; i < 4; i++) { SPrintf(tmp, "%.2X", uuid[i]); ret += tmp; } ret += "-"; for (i = 0; i < 2; i++) { SPrintf(tmp, "%.2X", uuid[i + 4]); ret += tmp; } ret += "-"; for (i = 0; i < 2; i++) { SPrintf(tmp, "%.2X", uuid[i + 6]); ret += tmp; } ret += "-"; for (i = 0; i < 2; i++) { SPrintf(tmp, "%.2X", uuid[i + 8]); ret += tmp; } ret += "-"; for (i = 0; i < 6; i++) { SPrintf(tmp, "%.2X", uuid[i + 10]); ret += tmp; } return ret; } typedef struct (uint32 offset) { FSeek(offset); PBLLoader loader; if (loader.isVersion2) { Uuid uuid; uint32 unknown[2]; } PBLHeader header; } PBL; LittleEndian(); PBLSetHeader hdr; FSeek(hdr.loadersArrayOffset); uint32 loaderOffsets[hdr.loadersArrayCount]; local int i; for (i = 0; i < hdr.loadersArrayCount; i++) { PBL pbls(loaderOffsets[i]); }