mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
201 lines
7.5 KiB
Go
201 lines
7.5 KiB
Go
package dyld
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/blacktop/go-macho/types"
|
|
)
|
|
|
|
func output(show bool, fmtStr string, args ...any) {
|
|
if show {
|
|
fmt.Printf(fmtStr, args...)
|
|
}
|
|
}
|
|
|
|
// Is64bit returns if dyld is 64bit or not
|
|
func (f *File) Is64bit() bool {
|
|
return strings.Contains(f.Headers[f.UUID].Magic.String(), "64")
|
|
}
|
|
|
|
// IsArm64 returns if dyld is arm64 or not (meaning I can disassemble it)
|
|
func (f *File) IsArm64() bool {
|
|
return strings.Contains(f.Headers[f.UUID].Magic.String(), "arm64")
|
|
}
|
|
|
|
// GetOffset returns the offset for a given virtual address and the cache's UUID that contains it
|
|
func (f *File) GetOffset(address uint64) (types.UUID, uint64, error) {
|
|
for uuid, cacheMaps := range f.Mappings {
|
|
for _, mapping := range cacheMaps {
|
|
if mapping.Address <= address && address < mapping.Address+mapping.Size {
|
|
return uuid, (address - mapping.Address) + mapping.FileOffset, nil
|
|
}
|
|
}
|
|
}
|
|
var badUUID types.UUID // will create a NULL uuid
|
|
return badUUID, 0, fmt.Errorf("address %#x not within any mappings address range", address)
|
|
}
|
|
|
|
// GetOffsetForUUID returns the offset for a given virtual address for a given cache UUID
|
|
func (f *File) GetOffsetForUUID(uuid types.UUID, address uint64) (uint64, error) {
|
|
for _, mapping := range f.Mappings[uuid] {
|
|
if mapping.Address <= address && address < mapping.Address+mapping.Size {
|
|
return (address - mapping.Address) + mapping.FileOffset, nil
|
|
}
|
|
}
|
|
return 0, fmt.Errorf("address %#x not within any mappings address range", address)
|
|
}
|
|
|
|
// IsAddressInCache returns if the virtual address is in the cache's mappings
|
|
func (f *File) IsAddressInCache(uuid types.UUID, address uint64) bool {
|
|
for _, mapping := range f.Mappings[uuid] {
|
|
if mapping.Address <= address && address < mapping.Address+mapping.Size {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetVMAddress returns a map of uuids to virtual address for a given offset
|
|
func (f *File) GetVMAddress(offset uint64) (map[types.UUID]uint64, error) {
|
|
uuid2addr := make(map[types.UUID]uint64)
|
|
for uuid, cacheMaps := range f.Mappings {
|
|
for _, mapping := range cacheMaps {
|
|
if mapping.FileOffset <= offset && offset < mapping.FileOffset+mapping.Size {
|
|
uuid2addr[uuid] = (offset - mapping.FileOffset) + mapping.Address
|
|
}
|
|
}
|
|
}
|
|
if len(uuid2addr) == 0 {
|
|
return nil, fmt.Errorf("offset %#x not within any mappings file offset range", offset)
|
|
}
|
|
return uuid2addr, nil
|
|
}
|
|
|
|
// GetVMAddressForUUID returns the virtual address for a given offset for a given cache UUID
|
|
func (f *File) GetVMAddressForUUID(uuid types.UUID, offset uint64) (uint64, error) {
|
|
for _, mapping := range f.MappingsWithSlideInfo[uuid] {
|
|
if mapping.FileOffset <= offset && offset < mapping.FileOffset+mapping.Size {
|
|
return (offset - mapping.FileOffset) + mapping.Address, nil
|
|
}
|
|
}
|
|
return 0, fmt.Errorf("offset %#x not within any mappings file offset range", offset)
|
|
}
|
|
|
|
func (f *File) GetCacheOffset(vmoffset uint64) (types.UUID, uint64, error) {
|
|
if vmoffset < f.SubCacheInfo[0].CacheVMOffset {
|
|
return f.UUID, vmoffset, nil // vm offset in primary subcache
|
|
}
|
|
for idx, scinfo := range f.SubCacheInfo { // check the sub subcaches
|
|
if idx < len(f.SubCacheInfo)-1 {
|
|
if scinfo.CacheVMOffset <= vmoffset && vmoffset < f.SubCacheInfo[idx+1].CacheVMOffset {
|
|
return scinfo.UUID, vmoffset - scinfo.CacheVMOffset, nil
|
|
}
|
|
} else {
|
|
if scinfo.CacheVMOffset <= vmoffset {
|
|
return scinfo.UUID, vmoffset - scinfo.CacheVMOffset, nil
|
|
}
|
|
}
|
|
}
|
|
// NOTE: via the dyld src comments; the .symbols subcache is unmmapped
|
|
return types.UUID{}, 0, fmt.Errorf("offset %#x not within any sub cache VM offset range", vmoffset)
|
|
}
|
|
|
|
func (f *File) GetCacheOffsetFromAddress(addr uint64) (types.UUID, uint64, error) {
|
|
vmstart := f.Headers[f.UUID].SharedRegionStart
|
|
for idx, scinfo := range f.SubCacheInfo { // check the sub subcaches
|
|
if idx < len(f.SubCacheInfo)-1 {
|
|
if vmstart+scinfo.CacheVMOffset <= addr && addr < vmstart+f.SubCacheInfo[idx+1].CacheVMOffset {
|
|
return scinfo.UUID, addr - (vmstart + scinfo.CacheVMOffset) + scinfo.CacheVMOffset, nil
|
|
}
|
|
} else {
|
|
if vmstart+scinfo.CacheVMOffset <= addr {
|
|
return scinfo.UUID, addr - (vmstart + scinfo.CacheVMOffset) + scinfo.CacheVMOffset, nil
|
|
}
|
|
}
|
|
}
|
|
// NOTE: via the dyld src comments; the .symbols subcache is unmmapped
|
|
return types.UUID{}, 0, fmt.Errorf("address %#x not within any sub cache VM offset range", addr)
|
|
}
|
|
|
|
func (f *File) GetCacheVMAddress(offset uint64) (types.UUID, uint64, error) {
|
|
if offset < f.SubCacheInfo[0].CacheVMOffset {
|
|
return f.UUID, f.MappingsWithSlideInfo[f.UUID][0].Address + offset, nil // vm addr in primary subcache
|
|
}
|
|
for idx, scinfo := range f.SubCacheInfo { // check the sub subcaches
|
|
if idx < len(f.SubCacheInfo)-1 {
|
|
if scinfo.CacheVMOffset <= offset && offset < f.SubCacheInfo[idx+1].CacheVMOffset {
|
|
return scinfo.UUID, f.MappingsWithSlideInfo[scinfo.UUID][0].Address + (offset - scinfo.CacheVMOffset), nil
|
|
}
|
|
} else {
|
|
if scinfo.CacheVMOffset <= offset {
|
|
return scinfo.UUID, f.MappingsWithSlideInfo[scinfo.UUID][0].Address + (offset - scinfo.CacheVMOffset), nil
|
|
}
|
|
}
|
|
}
|
|
// NOTE: via the dyld src comments; the .symbols subcache is unmmapped
|
|
return types.UUID{}, 0, fmt.Errorf("offset %#x not within any sub cache VM offset range", offset)
|
|
}
|
|
|
|
// GetMappingForOffsetForUUID returns the mapping containing a given file offset for a given cache UUID
|
|
func (f *File) GetMappingForOffsetForUUID(uuid types.UUID, offset uint64) (*CacheMapping, error) {
|
|
for _, mapping := range f.Mappings[uuid] {
|
|
if mapping.FileOffset <= offset && offset < mapping.FileOffset+mapping.Size {
|
|
return mapping, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("offset %#x not within any mappings file offset range", offset)
|
|
}
|
|
|
|
// GetMappingForVMAddress returns the mapping containing a given virtual address
|
|
func (f *File) GetMappingForVMAddress(address uint64) (types.UUID, *CacheMappingWithSlideInfo, error) {
|
|
for uuid := range f.MappingsWithSlideInfo {
|
|
for _, mapping := range f.MappingsWithSlideInfo[uuid] {
|
|
if mapping.Address <= address && address < mapping.Address+mapping.Size {
|
|
return uuid, mapping, nil
|
|
}
|
|
}
|
|
}
|
|
return types.UUID{}, nil, fmt.Errorf("address %#x not within any mapping's address range", address)
|
|
}
|
|
|
|
// ReadBytesForUUID returns bytes at a given offset for a given cache UUID
|
|
func (f *File) ReadBytesForUUID(uuid types.UUID, offset int64, size uint64) ([]byte, error) {
|
|
data := make([]byte, size)
|
|
if _, err := f.r[uuid].ReadAt(data, offset); err != nil {
|
|
return nil, fmt.Errorf("failed to read bytes at offset %#x: %v", offset, err)
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// ReadPointerForUUID returns pointer at a given offset for a given cache UUID
|
|
func (f *File) ReadPointerForUUID(uuid types.UUID, offset uint64) (uint64, error) {
|
|
u64 := make([]byte, 8)
|
|
if _, err := f.r[uuid].ReadAt(u64, int64(offset)); err != nil {
|
|
return 0, fmt.Errorf("failed to read pointer at offset %#x: %v", offset, err)
|
|
}
|
|
return binary.LittleEndian.Uint64(u64), nil
|
|
}
|
|
|
|
// ReadPointerAtAddress returns pointer at a given virtual address
|
|
func (f *File) ReadPointerAtAddress(address uint64) (uint64, error) {
|
|
uuid, offset, err := f.GetOffset(address)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to get offset for address %#x: %v", address, err)
|
|
}
|
|
return f.ReadPointerForUUID(uuid, offset)
|
|
}
|
|
|
|
func (f *File) GetSubCacheExtensionFromUUID(uuid types.UUID) (string, error) {
|
|
for idx, sc := range f.SubCacheInfo {
|
|
if sc.UUID == uuid {
|
|
if len(sc.Extention) == 0 {
|
|
return fmt.Sprintf(".%d", idx), nil
|
|
}
|
|
return sc.Extention, nil
|
|
}
|
|
}
|
|
return "", fmt.Errorf("failed to find subcache extension for uuid %s", uuid.String())
|
|
}
|