From 9d4af2d6fe24840dcc54c93cda9ff6ef6ed845c3 Mon Sep 17 00:00:00 2001 From: blacktop Date: Tue, 19 Dec 2023 11:28:10 -0700 Subject: [PATCH] fix: DYLD_CHAINED_PTR_64_OFFSET edge case #29 #30 --- file.go | 1 + file_test.go | 32 +++++++---- pkg/fixupchains/fixupchains.go | 15 +++-- pkg/fixupchains/types.go | 102 +++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 16 deletions(-) diff --git a/file.go b/file.go index 4a5a056..a737411 100644 --- a/file.go +++ b/file.go @@ -1487,6 +1487,7 @@ func (f *File) convertToVMAddr(value uint64) uint64 { } return uint64(int64(symAddr) + addend) } + return value } } // TODO: fix this dumb hack for SUPPORT_OLD_ARM64E_FORMAT diff --git a/file_test.go b/file_test.go index 6013bd4..ff0d97a 100644 --- a/file_test.go +++ b/file_test.go @@ -844,7 +844,9 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x: %#v\n", cfstr.Address, cfstr.Name) } } else { - t.Errorf(err.Error()) + if !errors.Is(err, ErrObjcSectionNotFound) { + t.Fatalf(err.Error()) + } } if meths, err := got.GetObjCMethodLists(); err == nil { @@ -854,7 +856,9 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x: (%s) %s [%d]\n", m.ImpVMAddr, m.ReturnType(), m.Name, m.NumberOfArguments()) } } else { - t.Errorf(err.Error()) + if !errors.Is(err, ErrObjcSectionNotFound) { + t.Fatalf(err.Error()) + } } if protos, err := got.GetObjCProtocols(); err == nil { @@ -862,7 +866,9 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Println(proto.String()) } } else { - t.Errorf(err.Error()) + if !errors.Is(err, ErrObjcSectionNotFound) { + t.Fatalf(err.Error()) + } } if classes, err := got.GetObjCClasses(); err == nil { @@ -870,7 +876,9 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Println(class.Verbose()) } } else { - t.Errorf(err.Error()) + if !errors.Is(err, ErrObjcSectionNotFound) { + t.Fatalf(err.Error()) + } } if nlclasses, err := got.GetObjCNonLazyClasses(); err == nil { @@ -878,7 +886,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Println(class.String()) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if cats, err := got.GetObjCCategories(); err == nil { @@ -886,7 +894,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Println(cat.String()) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if nlcats, err := got.GetObjCNonLazyCategories(); err == nil { @@ -894,7 +902,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Println(cat.String()) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if selRefs, err := got.GetObjCProtoReferences(); err == nil { @@ -903,7 +911,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x -> %#x: %s\n", off, prot.Ptr, prot.Name) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if selRefs, err := got.GetObjCClassReferences(); err == nil { fmt.Println("@class refs") @@ -911,7 +919,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x -> %#x: %s\n", off, sel.ClassPtr, sel.Name) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if selRefs, err := got.GetObjCSuperReferences(); err == nil { fmt.Println("@super refs") @@ -919,7 +927,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x -> %#x: %s\n", off, sel.ClassPtr, sel.SuperClass) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if selRefs, err := got.GetObjCSelectorReferences(); err == nil { fmt.Println("@selectors refs") @@ -927,7 +935,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x -> %#x: %s\n", off, sel.VMAddr, sel.Name) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } if methods, err := got.GetObjCMethodNames(); err == nil { fmt.Printf("\n@methods\n") @@ -935,7 +943,7 @@ func TestNewFileWithObjC(t *testing.T) { fmt.Printf("%#x: %s\n", vmaddr, method) } } else { - t.Errorf(err.Error()) + t.Fatalf(err.Error()) } } } diff --git a/pkg/fixupchains/fixupchains.go b/pkg/fixupchains/fixupchains.go index 8f895a8..7d6dfb1 100644 --- a/pkg/fixupchains/fixupchains.go +++ b/pkg/fixupchains/fixupchains.go @@ -194,10 +194,17 @@ func (dcf *DyldChainedFixups) walkDcFixupChain(segIdx int, pageIndex uint16, off if err := binary.Read(dcf.sr, dcf.bo, &dcPtr64); err != nil { return err } - dcf.Starts[segIdx].Fixups = append(dcf.Starts[segIdx].Fixups, DyldChainedPtr64RebaseOffset{ - Pointer: dcPtr64, - Fixup: fixupLocation, - }) + // NOTE: the fixup-chains.h seems to indicate that DYLD_CHAINED_PTR_64_OFFSET is a rebase, but can also be a bind + if Generic64IsBind(dcPtr64) { + bind := DyldChainedPtr64Bind{Pointer: dcPtr64, Fixup: fixupLocation} + bind.Import = dcf.Imports[bind.Ordinal()].Name + dcf.Starts[segIdx].Fixups = append(dcf.Starts[segIdx].Fixups, bind) + } else { + dcf.Starts[segIdx].Fixups = append(dcf.Starts[segIdx].Fixups, DyldChainedPtr64RebaseOffset{ + Pointer: dcPtr64, + Fixup: fixupLocation, + }) + } if Generic64Next(dcPtr64) == 0 { chainEnd = true } diff --git a/pkg/fixupchains/types.go b/pkg/fixupchains/types.go index e080f86..e0f1e87 100644 --- a/pkg/fixupchains/types.go +++ b/pkg/fixupchains/types.go @@ -20,6 +20,9 @@ type DyldChainedFixups struct { type Fixup interface { Offset() uint64 + IsRebase() bool + IsBind() bool + Raw() uint64 String(baseAddr ...uint64) string } @@ -210,6 +213,12 @@ type DyldChainedPtrArm64eRebase struct { Pointer uint64 } +func (d DyldChainedPtrArm64eRebase) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eRebase) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eRebase) Offset() uint64 { return d.Fixup } @@ -258,6 +267,12 @@ type DyldChainedPtrArm64eBind struct { Import string } +func (d DyldChainedPtrArm64eBind) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eBind) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eBind) Offset() uint64 { return d.Fixup } @@ -315,6 +330,12 @@ type DyldChainedPtrArm64eAuthRebase struct { Pointer uint64 } +func (d DyldChainedPtrArm64eAuthRebase) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eAuthRebase) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eAuthRebase) Offset() uint64 { return d.Fixup } @@ -368,6 +389,12 @@ type DyldChainedPtrArm64eAuthBind struct { Import string } +func (d DyldChainedPtrArm64eAuthBind) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eAuthBind) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eAuthBind) Offset() uint64 { return d.Fixup } @@ -429,6 +456,12 @@ type DyldChainedPtr64Rebase struct { Pointer uint64 } +func (d DyldChainedPtr64Rebase) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtr64Rebase) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtr64Rebase) Offset() uint64 { return d.Fixup } @@ -476,6 +509,12 @@ type DyldChainedPtr64RebaseOffset struct { Pointer uint64 } +func (d DyldChainedPtr64RebaseOffset) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtr64RebaseOffset) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtr64RebaseOffset) Offset() uint64 { return d.Fixup } @@ -523,6 +562,12 @@ type DyldChainedPtrArm64eRebase24 struct { Pointer uint64 } +func (d DyldChainedPtrArm64eRebase24) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eRebase24) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eRebase24) Offset() uint64 { return d.Fixup } @@ -571,6 +616,12 @@ type DyldChainedPtrArm64eAuthRebase24 struct { Pointer uint64 } +func (d DyldChainedPtrArm64eAuthRebase24) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eAuthRebase24) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eAuthRebase24) Offset() uint64 { return d.Fixup } @@ -625,6 +676,12 @@ type DyldChainedPtrArm64eBind24 struct { Import string } +func (d DyldChainedPtrArm64eBind24) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eBind24) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eBind24) Offset() uint64 { return d.Fixup } @@ -676,6 +733,12 @@ type DyldChainedPtrArm64eAuthBind24 struct { Import string } +func (d DyldChainedPtrArm64eAuthBind24) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtrArm64eAuthBind24) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtrArm64eAuthBind24) Offset() uint64 { return d.Fixup } @@ -738,6 +801,12 @@ type DyldChainedPtr64Bind struct { Import string } +func (d DyldChainedPtr64Bind) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtr64Bind) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtr64Bind) Offset() uint64 { return d.Fixup } @@ -785,6 +854,12 @@ type DyldChainedPtr64KernelCacheRebase struct { Pointer uint64 } +func (d DyldChainedPtr64KernelCacheRebase) IsRebase() bool { + return true +} +func (d DyldChainedPtr64KernelCacheRebase) IsBind() bool { + return false +} func (d DyldChainedPtr64KernelCacheRebase) Offset() uint64 { return d.Fixup } @@ -852,6 +927,12 @@ type DyldChainedPtr32Rebase struct { Pointer uint32 } +func (d DyldChainedPtr32Rebase) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtr32Rebase) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtr32Rebase) Offset() uint64 { return d.Fixup } @@ -867,6 +948,9 @@ func (d DyldChainedPtr32Rebase) Bind() uint32 { func (d DyldChainedPtr32Rebase) Kind() string { return "ptr32-rebase" } +func (d DyldChainedPtr32Rebase) Raw() uint64 { + return uint64(d.Pointer) +} func (d DyldChainedPtr32Rebase) String(baseAddr ...uint64) string { if len(baseAddr) > 0 { d.Fixup += baseAddr[0] @@ -881,6 +965,12 @@ type DyldChainedPtr32Bind struct { Import string } +func (d DyldChainedPtr32Bind) IsRebase() bool { + return d.Bind() == 0 +} +func (d DyldChainedPtr32Bind) IsBind() bool { + return d.Bind() != 0 +} func (d DyldChainedPtr32Bind) Offset() uint64 { return d.Fixup } @@ -918,6 +1008,12 @@ type DyldChainedPtr32CacheRebase struct { Pointer uint32 } +func (d DyldChainedPtr32CacheRebase) IsRebase() bool { + return true +} +func (d DyldChainedPtr32CacheRebase) IsBind() bool { + return false +} func (d DyldChainedPtr32CacheRebase) Offset() uint64 { return d.Fixup } @@ -946,6 +1042,12 @@ type DyldChainedPtr32FirmwareRebase struct { Pointer uint32 } +func (d DyldChainedPtr32FirmwareRebase) IsRebase() bool { + return true +} +func (d DyldChainedPtr32FirmwareRebase) IsBind() bool { + return false +} func (d DyldChainedPtr32FirmwareRebase) Offset() uint64 { return d.Fixup }