mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
579 lines
22 KiB
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;
|