From d2793fee5d57795df4fa5d05bb4e2e031a51daea Mon Sep 17 00:00:00 2001 From: blacktop Date: Fri, 19 Apr 2024 11:19:17 -0600 Subject: [PATCH] fix: category class name bind lookup --- file.go | 13 +++++++------ objc.go | 36 +++++++++++++++++++++++++++--------- types/flags.go | 28 ++++++++++++++++------------ 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/file.go b/file.go index aef54f7..02b75e5 100644 --- a/file.go +++ b/file.go @@ -1558,7 +1558,7 @@ func (f *File) GetBindName(pointer uint64) (string, error) { return "", fmt.Errorf("failed to parse LC_DYLD_INFO_ONLY bind info: %v", err) } for _, bind := range binds { - if bind.Value == pointer { + if (bind.Start + bind.SegOffset) == pointer { return bind.Name, nil } } @@ -2511,6 +2511,7 @@ func (f *File) parseBinds(r *bytes.Reader, kind types.BindKind) ([]types.Bind, e } bind.Start = f.Segments()[imm].Addr bind.Segment = f.Segments()[imm].Name + bind.SegStart = f.Segments()[imm].Offset case types.BIND_OPCODE_ADD_ADDR_ULEB: out, err := trie.ReadUleb128(r) if err != nil { @@ -2524,7 +2525,7 @@ func (f *File) parseBinds(r *bytes.Reader, kind types.BindKind) ([]types.Bind, e if sec := f.FindSectionForVMAddr(f.Segment(bind.Segment).Addr + segOffset); sec != nil { bind.Section = sec.Name } - bind.Offset = segOffset + bind.SegOffset = segOffset binds = append(binds, bind) segOffset += f.pointerSize() } @@ -2532,7 +2533,7 @@ func (f *File) parseBinds(r *bytes.Reader, kind types.BindKind) ([]types.Bind, e if sec := f.FindSectionForVMAddr(f.Segment(bind.Segment).Addr + segOffset); sec != nil { bind.Section = sec.Name } - bind.Offset = segOffset + bind.SegOffset = segOffset binds = append(binds, bind) off, err := trie.ReadUleb128(r) if err != nil { @@ -2543,7 +2544,7 @@ func (f *File) parseBinds(r *bytes.Reader, kind types.BindKind) ([]types.Bind, e if sec := f.FindSectionForVMAddr(f.Segment(bind.Segment).Addr + segOffset); sec != nil { bind.Section = sec.Name } - bind.Offset = segOffset + bind.SegOffset = segOffset binds = append(binds, bind) segOffset += uint64(imm)*f.pointerSize() + f.pointerSize() case types.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: @@ -2559,7 +2560,7 @@ func (f *File) parseBinds(r *bytes.Reader, kind types.BindKind) ([]types.Bind, e if sec := f.FindSectionForVMAddr(f.Segment(bind.Segment).Addr + segOffset); sec != nil { bind.Section = sec.Name } - bind.Offset = segOffset + bind.SegOffset = segOffset binds = append(binds, bind) segOffset += skip + f.pointerSize() } @@ -2607,7 +2608,7 @@ func (f *File) parseBinds(r *bytes.Reader, kind types.BindKind) ([]types.Bind, e return nil, fmt.Errorf("bind ordinal is out of range") } ordinalTable[ord].Value = ptr - ordinalTable[ord].Offset = segOffset + ordinalTable[ord].SegOffset = segOffset binds = append(binds, ordinalTable[ord]) } // The delta is bits [51..61] diff --git a/objc.go b/objc.go index de02345..7611f9d 100644 --- a/objc.go +++ b/objc.go @@ -717,21 +717,39 @@ func (f *File) GetObjCCategories() ([]objc.Category, error) { if err != nil { return nil, fmt.Errorf("failed to read cstring: %v", err) } - categoryPtr.ClsVMAddr = f.vma.Convert(categoryPtr.ClsVMAddr) - if c, ok := f.objc[categoryPtr.ClsVMAddr]; ok { - category.Class = c.(*objc.Class) + if categoryPtr.ClsVMAddr > 0 { + categoryPtr.ClsVMAddr = f.vma.Convert(categoryPtr.ClsVMAddr) + if c, ok := f.objc[categoryPtr.ClsVMAddr]; ok { + category.Class = c.(*objc.Class) + } else { + category.Class, err = f.GetObjCClass(categoryPtr.ClsVMAddr) + if err != nil { + if f.HasFixups() { + bindName, err := f.GetBindName(categoryPtr.ClsVMAddr) + if err == nil { + category.Class = &objc.Class{Name: strings.TrimPrefix(bindName, "_OBJC_CLASS_$_")} + } else { + return nil, fmt.Errorf("failed to read super class objc_class_t at vmaddr: %#x; %v", categoryPtr.ClsVMAddr, err) + } + } else { + category.Class = &objc.Class{} + } + } + f.PutObjC(categoryPtr.ClsVMAddr, category.Class) + } } else { - category.Class, err = f.GetObjCClass(categoryPtr.ClsVMAddr) - if err != nil { - bindName, err := f.GetBindName(categoryPtr.ClsVMAddr) + if c, ok := f.objc[categoryPtr.ClsVMAddr]; ok { + category.Class = c.(*objc.Class) + } else { + category.Class = &objc.Class{} + bindName, err := f.GetBindName(ptr + uint64(unsafe.Offsetof(categoryPtr.ClsVMAddr))) if err == nil { category.Class = &objc.Class{Name: strings.TrimPrefix(bindName, "_OBJC_CLASS_$_")} } else { - category.Class = &objc.Class{} - // return nil, fmt.Errorf("failed to read super class objc_class_t at vmaddr: %#x; %v", categoryPtr.ClsVMAddr, err) + return nil, fmt.Errorf("failed to read super class objc_class_t at vmaddr: %#x; %v", ptr+uint64(unsafe.Offsetof(categoryPtr.ClsVMAddr)), err) } + f.PutObjC(ptr+uint64(unsafe.Offsetof(categoryPtr.ClsVMAddr)), category.Class) } - f.PutObjC(categoryPtr.ClsVMAddr, category.Class) } if categoryPtr.InstanceMethodsVMAddr > 0 { categoryPtr.InstanceMethodsVMAddr = f.vma.Convert(categoryPtr.InstanceMethodsVMAddr) diff --git a/types/flags.go b/types/flags.go index ee8e915..3dce289 100644 --- a/types/flags.go +++ b/types/flags.go @@ -108,25 +108,29 @@ func (bs Binds) Search(name string) (*Bind, error) { } type Bind struct { - Name string - Type uint8 - Kind BindKind - Flags uint8 - Addend int64 - Segment string - Section string - Start uint64 - Offset uint64 - Dylib string - Value uint64 + Name string + Type uint8 + Kind BindKind + Flags uint8 + Addend int64 + Segment string + SegStart uint64 + SegOffset uint64 + Section string + Start uint64 + Dylib string + Value uint64 } +func (b Bind) Offset() uint64 { + return b.SegStart + b.SegOffset +} func (b Bind) String() string { return fmt.Sprintf( "%-7s %-16s %#x %-4s %-10s %5d %-25s\t%s%s", b.Segment, b.Section, - b.Start+b.Offset, + b.Start+b.SegOffset, b.Kind, getBindType(b.Type), b.Addend,