Files
ipsw/pkg/dyld/prebuilt.go

579 lines
22 KiB
Go

package dyld
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"strings"
"unsafe"
"github.com/blacktop/go-macho/pkg/trie"
"github.com/blacktop/go-macho/types"
)
func (f *File) SupportsProgramTrie() bool {
if f.Headers[f.UUID].MappingOffset < uint32(unsafe.Offsetof(f.Headers[f.UUID].ProgramTrieSize)) {
return false
}
if f.Headers[f.UUID].ProgramTrieAddr == 0 {
return false
}
return true
}
func (f *File) ForEachLaunchLoaderSet(handler func(execPath string, pset *PrebuiltLoaderSet)) error {
if !f.SupportsProgramTrie() {
return ErrProgramTrieNotSupported
}
uuid, off, err := f.GetOffset(f.Headers[f.UUID].ProgramTrieAddr)
if err != nil {
return err
}
dat, err := f.ReadBytesForUUID(uuid, int64(off), uint64(f.Headers[f.UUID].ProgramTrieSize))
if err != nil {
return err
}
r := bytes.NewReader(dat)
nodes, err := trie.ParseTrie(r)
if err != nil {
return err
}
for _, node := range nodes {
r.Seek(int64(node.Offset), io.SeekStart)
pblsOff, err := trie.ReadUleb128(r)
if err != nil {
return err
}
uuid, psetOffset, err := f.GetOffset(f.Headers[f.UUID].ProgramsPblSetPoolAddr + uint64(pblsOff))
if err != nil {
return err
}
pset, err := f.parsePrebuiltLoaderSet(io.NewSectionReader(f.r[uuid], int64(psetOffset), 1<<63-1))
if err != nil {
return err
}
handler(string(node.Data), pset)
}
return nil
}
func (f *File) ForEachLaunchLoaderSetPath(handler func(execPath string)) error {
if !f.SupportsProgramTrie() {
return ErrProgramTrieNotSupported
}
uuid, off, err := f.GetOffset(f.Headers[f.UUID].ProgramTrieAddr)
if err != nil {
return err
}
dat, err := f.ReadBytesForUUID(uuid, int64(off), uint64(f.Headers[f.UUID].ProgramTrieSize))
if err != nil {
return err
}
r := bytes.NewReader(dat)
nodes, err := trie.ParseTrie(r)
if err != nil {
return err
}
for _, node := range nodes {
handler(string(node.Data))
}
return nil
}
// GetLaunchLoaderSet returns the PrebuiltLoaderSet for the given executable app path.
func (f *File) GetLaunchLoaderSet(executablePath string) (*PrebuiltLoaderSet, error) {
if !f.SupportsProgramTrie() {
return nil, ErrProgramTrieNotSupported
}
if !f.SupportsDylibPrebuiltLoader() {
return nil, ErrPrebuiltLoaderSetNotSupported
}
var psetOffset uint64
uuid, off, err := f.GetOffset(f.Headers[f.UUID].ProgramTrieAddr)
if err != nil {
return nil, err
}
dat, err := f.ReadBytesForUUID(uuid, int64(off), uint64(f.Headers[f.UUID].ProgramTrieSize))
if err != nil {
return nil, err
}
r := bytes.NewReader(dat)
if _, err = trie.WalkTrie(r, executablePath); err != nil {
return nil, fmt.Errorf("could not find executable %s in the ProgramTrie: %w", executablePath, err)
}
poolOffset, err := trie.ReadUleb128(r)
if err != nil {
return nil, err
}
uuid, psetOffset, err = f.GetOffset(f.Headers[f.UUID].ProgramsPblSetPoolAddr + uint64(poolOffset))
if err != nil {
return nil, err
}
return f.parsePrebuiltLoaderSet(io.NewSectionReader(f.r[uuid], int64(psetOffset), 1<<63-1))
}
func (f *File) SupportsDylibPrebuiltLoader() bool {
if f.Headers[f.UUID].MappingOffset < uint32(unsafe.Offsetof(f.Headers[f.UUID].ProgramTrieSize)) {
return false
}
if f.Headers[f.UUID].MappingOffset < uint32(unsafe.Offsetof(f.Headers[f.UUID].DylibsPblSetAddr)) {
return false
}
// FIXME: REMOVE once I have added iOS 18.x support
// if f.Headers[f.UUID].MappingOffset > uint32(unsafe.Offsetof(f.Headers[f.UUID].TPROMappingOffset)) {
// return false
// }
if f.Headers[f.UUID].DylibsPblSetAddr == 0 {
return false
}
return true
}
// GetLaunchLoader returns the PrebuiltLoader for the given executable in-cache dylib path.
func (f *File) GetDylibPrebuiltLoader(executablePath string) (*PrebuiltLoader, error) {
if !f.SupportsDylibPrebuiltLoader() {
return nil, ErrPrebuiltLoaderSetNotSupported
}
uuid, off, err := f.GetOffset(f.Headers[f.UUID].DylibsPblSetAddr)
if err != nil {
return nil, err
}
// if sc := f.GetSubCacheInfo(uuid); sc != nil {
// log.Debug(sc.Extention)
// }
sr := io.NewSectionReader(f.r[uuid], int64(off), 1<<63-1)
var pset PrebuiltLoaderSet
if err := binary.Read(sr, binary.LittleEndian, &pset.prebuiltLoaderSetHeader); err != nil {
return nil, err
}
if pset.Magic != PrebuiltLoaderSetMagic {
return nil, fmt.Errorf("invalid magic for PrebuiltLoaderSet: expected %x got %x", PrebuiltLoaderSetMagic, pset.Magic)
}
sr.Seek(int64(pset.LoadersArrayOffset), io.SeekStart)
loaderOffsets := make([]uint32, pset.LoadersArrayCount)
if err := binary.Read(sr, binary.LittleEndian, &loaderOffsets); err != nil {
return nil, err
}
imgIdx, err := f.HasImagePath(executablePath)
if err != nil {
return nil, err
} else if imgIdx < 0 {
return nil, fmt.Errorf("image not found")
}
sr.Seek(int64(loaderOffsets[imgIdx]), io.SeekStart)
// fmt.Println(executablePath)
return f.parsePrebuiltLoader(io.NewSectionReader(f.r[uuid], int64(off)+int64(loaderOffsets[imgIdx]), 1<<63-1))
}
func (f *File) parsePrebuiltLoaderSet(sr *io.SectionReader) (*PrebuiltLoaderSet, error) {
var pset PrebuiltLoaderSet
if err := binary.Read(sr, binary.LittleEndian, &pset.prebuiltLoaderSetHeader); err != nil {
return nil, err
}
if pset.Magic != PrebuiltLoaderSetMagic {
return nil, fmt.Errorf("invalid magic for PrebuiltLoaderSet: expected %x got %x", PrebuiltLoaderSetMagic, pset.Magic)
}
sr.Seek(int64(pset.LoadersArrayOffset), io.SeekStart)
loaderOffsets := make([]uint32, pset.LoadersArrayCount)
if err := binary.Read(sr, binary.LittleEndian, &loaderOffsets); err != nil {
return nil, err
}
for _, loaderOffset := range loaderOffsets {
pbl, err := f.parsePrebuiltLoader(io.NewSectionReader(sr, int64(loaderOffset), 1<<63-1))
if err != nil {
return nil, err
}
pset.Loaders = append(pset.Loaders, *pbl)
}
if pset.CachePatchCount > 0 { // FIXME: this is in "/usr/bin/abmlite" but the values don't make sense (dyld_closure_util gets the same values)
sr.Seek(int64(pset.CachePatchOffset), io.SeekStart)
pset.Patches = make([]CachePatch, pset.CachePatchCount)
if err := binary.Read(sr, binary.LittleEndian, &pset.Patches); err != nil {
return nil, err
}
}
if pset.DyldCacheUuidOffset > 0 {
sr.Seek(int64(pset.DyldCacheUuidOffset), io.SeekStart)
var dcUUID types.UUID
if err := binary.Read(sr, binary.LittleEndian, &dcUUID); err != nil {
return nil, err
}
}
if pset.MustBeMissingPathsCount > 0 {
sr.Seek(int64(pset.MustBeMissingPathsOffset), io.SeekStart)
br := bufio.NewReader(sr)
for range int(pset.MustBeMissingPathsCount) {
s, err := br.ReadString('\x00')
if err != nil {
return nil, err
}
pset.MustBeMissingPaths = append(pset.MustBeMissingPaths, strings.TrimSuffix(s, "\x00"))
}
}
// FIXME: when dyld src is out for iOS 18.0/macOS 15.0
if pset.ObjcSelectorHashTableOffset > 0 && !pset.Loaders[0].Loader.HasUUIDLoadCommand() {
sr.Seek(int64(pset.ObjcSelectorHashTableOffset), io.SeekStart)
var o ObjCSelectorOpt
if err := binary.Read(sr, f.ByteOrder, &o.objCStringTable); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc selector optimization string table: %v", err)
}
tabAddr, _ := sr.Seek(0, io.SeekCurrent)
o.Tab = make([]byte, o.objCStringTable.Mask+1)
if err := binary.Read(sr, f.ByteOrder, &o.Tab); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc selector optimization tabs: %v", err)
}
o.Checkbytes = make([]byte, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Checkbytes); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc selector optimization checkbytes: %v", err)
}
sr.Seek(int64(tabAddr)+int64(o.RoundedTabSize+o.RoundedCheckBytesSize), io.SeekStart)
o.Offsets = make([]BindTargetRef, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Offsets); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc selector optimization offsets: %v", err)
}
pset.SelectorTable = &o
}
// FIXME: when dyld src is out for iOS 18.0/macOS 15.0
if pset.ObjcClassHashTableOffset > 0 && !pset.Loaders[0].Loader.HasUUIDLoadCommand() {
sr.Seek(int64(pset.ObjcClassHashTableOffset), io.SeekStart)
var o ObjCClassOpt
if err := binary.Read(sr, f.ByteOrder, &o.objCStringTable); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization string table: %v", err)
}
tabAddr, _ := sr.Seek(0, io.SeekCurrent)
o.Tab = make([]byte, o.objCStringTable.Mask+1)
if err := binary.Read(sr, f.ByteOrder, &o.Tab); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization tabs: %v", err)
}
o.Checkbytes = make([]byte, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Checkbytes); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization checkbytes: %v", err)
}
sr.Seek(int64(tabAddr)+int64(o.RoundedTabSize+o.RoundedCheckBytesSize), io.SeekStart)
o.Offsets = make([]BindTargetRef, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Offsets); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization class name offsets: %v", err)
}
o.Classes = make([]BindTargetRef, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Classes); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization class impl offsets: %v", err)
}
var dupCount uint64
if err := binary.Read(sr, f.ByteOrder, &dupCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization duplicate count: %v", err)
}
o.Duplicates = make([]BindTargetRef, dupCount)
if err := binary.Read(sr, f.ByteOrder, &o.Duplicates); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc class optimization duplicate offsets: %v", err)
}
pset.ClassTable = &o
}
// FIXME: when dyld src is out for iOS 18.0/macOS 15.0
if pset.ObjcProtocolHashTableOffset > 0 && !pset.Loaders[0].Loader.HasUUIDLoadCommand() {
sr.Seek(int64(pset.ObjcProtocolHashTableOffset), io.SeekStart)
var o ObjCClassOpt
if err := binary.Read(sr, f.ByteOrder, &o.objCStringTable); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization string table: %v", err)
}
tabAddr, _ := sr.Seek(0, io.SeekCurrent)
o.Tab = make([]byte, o.objCStringTable.Mask+1)
if err := binary.Read(sr, f.ByteOrder, &o.Tab); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization tabs: %v", err)
}
o.Checkbytes = make([]byte, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Checkbytes); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization checkbytes: %v", err)
}
sr.Seek(int64(tabAddr)+int64(o.RoundedTabSize+o.RoundedCheckBytesSize), io.SeekStart)
o.Offsets = make([]BindTargetRef, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Offsets); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization protocol name offsets: %v", err)
}
o.Classes = make([]BindTargetRef, o.objCStringTable.Capacity)
if err := binary.Read(sr, f.ByteOrder, &o.Classes); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization protocol impl offsets: %v", err)
}
var dupCount uint64
if err := binary.Read(sr, f.ByteOrder, &dupCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization duplicate count: %v", err)
}
o.Duplicates = make([]BindTargetRef, dupCount)
if err := binary.Read(sr, f.ByteOrder, &o.Duplicates); err != nil {
return nil, fmt.Errorf("failed to read prebuilt objc protocol optimization duplicate offsets: %v", err)
}
pset.ProtocolTable = &o
}
if !pset.HasOptimizedObjC() && pset.ObjcProtocolClassCacheOffset > 0 { // FIXME: this is a hack (would have panic'ed while parsing macOS 12.6.1 DSC prebuilt for /bin/ls) possibly uninitialized data
return &pset, nil
}
if pset.HasOptimizedSwift() {
if pset.SwiftTypeConformanceTableOffset > 0 {
sr.Seek(int64(pset.SwiftTypeConformanceTableOffset), io.SeekStart)
var mmap SwiftConformanceMultiMap
if err := binary.Read(sr, f.ByteOrder, &mmap); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift type conformance map: %v", err)
}
var hashBufferCount uint64
if err := binary.Read(sr, f.ByteOrder, &hashBufferCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift type conformance hashBufferCount: %v", err)
}
hashBuffer := make([]uint64, hashBufferCount)
if err := binary.Read(sr, f.ByteOrder, &hashBuffer); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift type conformance hashBuffer: %v", err)
}
var nodeBufferCount uint64
if err := binary.Read(sr, f.ByteOrder, &nodeBufferCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift type conformance nodeBufferCount: %v", err)
}
pset.SwiftTypeProtocolTable = make([]SwiftTypeProtocolNodeEntryT, nodeBufferCount)
if err := binary.Read(sr, f.ByteOrder, &pset.SwiftTypeProtocolTable); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift type conformance nodeBuffer: %v", err)
}
}
if pset.SwiftMetadataConformanceTableOffset > 0 {
sr.Seek(int64(pset.SwiftMetadataConformanceTableOffset), io.SeekStart)
var mmap SwiftConformanceMultiMap
if err := binary.Read(sr, f.ByteOrder, &mmap); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift metadata conformance map: %v", err)
}
var hashBufferCount uint64
if err := binary.Read(sr, f.ByteOrder, &hashBufferCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift metadata conformance hashBufferCount: %v", err)
}
hashBuffer := make([]uint64, hashBufferCount)
if err := binary.Read(sr, f.ByteOrder, &hashBuffer); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift metadata conformance hashBuffer: %v", err)
}
var nodeBufferCount uint64
if err := binary.Read(sr, f.ByteOrder, &nodeBufferCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift metadata conformance nodeBufferCount: %v", err)
}
pset.SwiftMetadataProtocolTable = make([]SwiftMetadataConformanceNodeEntryT, nodeBufferCount)
if err := binary.Read(sr, f.ByteOrder, &pset.SwiftMetadataProtocolTable); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift metadata conformance nodeBuffer: %v", err)
}
}
if pset.SwiftForeignTypeConformanceTableOffset > 0 {
sr.Seek(int64(pset.SwiftForeignTypeConformanceTableOffset), io.SeekStart)
var mmap SwiftConformanceMultiMap
if err := binary.Read(sr, f.ByteOrder, &mmap); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift foreign type conformance map: %v", err)
}
var hashBufferCount uint64
if err := binary.Read(sr, f.ByteOrder, &hashBufferCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift foreign type conformance hashBufferCount: %v", err)
}
hashBuffer := make([]uint64, hashBufferCount)
if err := binary.Read(sr, f.ByteOrder, &hashBuffer); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift foreign type conformance hashBuffer: %v", err)
}
var nodeBufferCount uint64
if err := binary.Read(sr, f.ByteOrder, &nodeBufferCount); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift foreign type conformance nodeBufferCount: %v", err)
}
pset.SwiftForeignTypeProtocolTable = make([]SwiftForeignTypeConformanceNodeEntryT, nodeBufferCount)
if err := binary.Read(sr, f.ByteOrder, &pset.SwiftForeignTypeProtocolTable); err != nil {
return nil, fmt.Errorf("failed to read prebuilt swift foreign type conformance nodeBuffer: %v", err)
}
}
}
return &pset, nil
}
// parsePrebuiltLoader parses a prebuilt loader from a section reader.
func (f *File) parsePrebuiltLoader(sr *io.SectionReader) (*PrebuiltLoader, error) {
var pbl PrebuiltLoader
if err := binary.Read(sr, binary.LittleEndian, &pbl.Loader); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader: %v", err)
}
if pbl.Loader.HasUUIDLoadCommand() {
if err := binary.Read(sr, binary.LittleEndian, &pbl.UUID); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader uuid: %v", err)
}
if err := binary.Read(sr, binary.LittleEndian, &pbl.CpuSubtype); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader cpu subtype: %v", err)
}
if err := binary.Read(sr, binary.LittleEndian, &pbl.Unused); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader unused: %v", err)
}
}
if err := binary.Read(sr, binary.LittleEndian, &pbl.Header); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader header: %v", err)
}
if pbl.Loader.Magic != LoaderMagic {
return nil, fmt.Errorf("invalid magic for prebuilt loader: expected %x got %x", LoaderMagic, pbl.Loader.Magic)
}
if pbl.Header.PathOffset > 0 {
sr.Seek(int64(pbl.Header.PathOffset), io.SeekStart)
path, err := bufio.NewReader(sr).ReadString('\x00')
if err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader path: %v", err)
}
pbl.Path = strings.TrimSuffix(path, "\x00")
}
// fmt.Println("Loader Info:")
// fmt.Println(pbl.Loader.String())
// // fmt.Println(utils.Bits(uint64(pbl.Loader.Info)))
// fmt.Println("Info:")
// fmt.Println(pbl.Header.GetInfo())
// if pbl.Loader.Unknown1() {
// log.Debugf("Unknown1: %t", pbl.Loader.Unknown1())
// }
// if pbl.Loader.Unknown2() {
// log.Debugf("Unknown2: %t", pbl.Loader.Unknown2())
// }
// if pbl.Loader.Unknown3() {
// log.Debugf("Unknown3: %t", pbl.Loader.Unknown3())
// }
if pbl.Header.AltPathOffset > 0 {
sr.Seek(int64(pbl.Header.AltPathOffset), io.SeekStart)
path, err := bufio.NewReader(sr).ReadString('\x00')
if err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader alt path: %v", err)
}
pbl.AltPath = strings.TrimSuffix(path, "\x00")
}
if pbl.Header.FileValidationOffset > 0 {
sr.Seek(int64(pbl.Header.FileValidationOffset), io.SeekStart)
var fv fileValidation
if err := binary.Read(sr, binary.LittleEndian, &fv); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader file validation: %v", err)
}
pbl.FileValidation = &fv
}
if pbl.Header.RegionsCount() > 0 {
sr.Seek(int64(pbl.Header.RegionsOffset), io.SeekStart)
pbl.Regions = make([]Region, pbl.Header.RegionsCount())
if err := binary.Read(sr, binary.LittleEndian, &pbl.Regions); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader regions: %v", err)
}
}
if pbl.Header.DependentLoaderRefsArrayOffset > 0 {
sr.Seek(int64(pbl.Header.DependentLoaderRefsArrayOffset), io.SeekStart)
depsArray := make([]LoaderRef, pbl.Header.DepCount)
if err := binary.Read(sr, binary.LittleEndian, &depsArray); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader dependent loader refs: %v", err)
}
kindsArray := make([]DependentKind, pbl.Header.DepCount)
if pbl.Header.DependentKindArrayOffset > 0 {
sr.Seek(int64(pbl.Header.DependentKindArrayOffset), io.SeekStart)
if err := binary.Read(sr, binary.LittleEndian, &kindsArray); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader dependent kinds: %v", err)
}
}
for idx, dep := range depsArray {
img := dep.String()
if dep.Index() < uint16(len(f.Images)) {
img = f.Images[dep.Index()].Name
}
pbl.Dependents = append(pbl.Dependents, dependent{
Name: img,
Kind: kindsArray[idx],
})
}
}
if pbl.Header.BindTargetRefsCount > 0 {
sr.Seek(int64(pbl.Header.BindTargetRefsOffset), io.SeekStart)
pbl.BindTargets = make([]BindTargetRef, pbl.Header.BindTargetRefsCount)
if err := binary.Read(sr, binary.LittleEndian, &pbl.BindTargets); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader bind target refs: %v", err)
}
}
if pbl.Header.OverrideBindTargetRefsCount > 0 {
sr.Seek(int64(pbl.Header.OverrideBindTargetRefsOffset), io.SeekStart)
pbl.OverrideBindTargets = make([]BindTargetRef, pbl.Header.OverrideBindTargetRefsCount)
if err := binary.Read(sr, binary.LittleEndian, &pbl.OverrideBindTargets); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader override bind target refs: %v", err)
}
}
if pbl.Header.ObjcBinaryInfoOffset > 0 {
sr.Seek(int64(pbl.Header.ObjcBinaryInfoOffset), io.SeekStart)
var ofi ObjCBinaryInfo
if err := binary.Read(sr, binary.LittleEndian, &ofi); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader objc binary info: %v", err)
}
pbl.ObjcFixupInfo = &ofi
sr.Seek(int64(pbl.Header.ObjcBinaryInfoOffset)+int64(pbl.ObjcFixupInfo.ProtocolFixupsOffset), io.SeekStart)
pbl.ObjcCanonicalProtocolFixups = make([]bool, pbl.ObjcFixupInfo.ProtocolListCount)
if err := binary.Read(sr, binary.LittleEndian, &pbl.ObjcCanonicalProtocolFixups); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader objc canonical protocol fixups: %v", err)
}
sr.Seek(int64(pbl.Header.ObjcBinaryInfoOffset)+int64(pbl.ObjcFixupInfo.SelectorReferencesFixupsOffset), io.SeekStart)
pbl.ObjcSelectorFixups = make([]BindTargetRef, pbl.ObjcFixupInfo.SelectorReferencesFixupsCount)
if err := binary.Read(sr, binary.LittleEndian, &pbl.ObjcSelectorFixups); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader objc selector fixups: %v", err)
}
}
if pbl.Header.IndexOfTwin != NoUnzipperedTwin {
pbl.Twin = f.Images[pbl.Header.IndexOfTwin].Name
}
if pbl.Header.PatchTableOffset > 0 {
sr.Seek(int64(pbl.Header.PatchTableOffset), io.SeekStart)
for {
var patch DylibPatch
if err := binary.Read(sr, binary.LittleEndian, &patch); err != nil {
return nil, fmt.Errorf("failed to read prebuilt loader dylib patch: %v", err)
}
pbl.DylibPatches = append(pbl.DylibPatches, patch)
if patch.Kind == endOfPatchTable {
break
}
}
}
return &pbl, nil
}
// 110594112 [6978840h] SIZE = 0x222CA0; PADDING = 0x6B310;