macho.go (125 lines of code) (raw):

// Copyright ©2022 Elastic N.V. All rights reserved. // Copyright ©2021 Dan Kortschak. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package toutoumomoma import ( "debug/gosym" "debug/macho" "io" "strings" ) type machoFile struct { r io.ReaderAt objFile *macho.File } func openMachO(r io.ReaderAt) (*machoFile, error) { objFile, err := macho.NewFile(r) if err != nil { return nil, err } return &machoFile{r: r, objFile: objFile}, nil } func (f *machoFile) Close() error { f.objFile = nil if c, ok := f.r.(io.Closer); ok { return c.Close() } return nil } func (f *machoFile) isGoExecutable() (ok bool, err error) { for _, section := range f.objFile.Sections { switch section.Name { case "__gosymtab", "__gopclntab", "__go_buildinfo": return true, nil } } return false, nil } func (f *machoFile) hasBuildID() (ok bool, err error) { sect := f.objFile.Section("__go_buildinfo") if sect == nil { return false, nil } _, err = sect.Data() return err == nil, err } func (f *machoFile) hasRealFiles() (ok bool, err error) { tab, err := f.pclnTable() if err != nil { return false, err } if len(f.objFile.Symtab.Syms) == 0 { return false, nil } foundMain := false for _, sym := range f.objFile.Symtab.Syms { if sym.Name != "main.main" { continue } foundMain = true file, _, fn := tab.PCToLine(sym.Value) if file == "??" || fn == nil { return false, nil } } return foundMain, nil } func (f *machoFile) importedSymbols() ([]string, error) { imports, err := f.objFile.ImportedSymbols() if err != nil { return nil, err } for i, imp := range imports { imports[i] = strings.ToLower(imp) } return imports, nil } func (f *machoFile) goSymbols(stdlib bool) ([]string, error) { tab, err := f.pclnTable() if err != nil { return nil, err } imports := make([]string, 0, len(f.objFile.Symtab.Syms)) for _, sym := range f.objFile.Symtab.Syms { if sym.Sect == 0 || int(sym.Sect) > len(f.objFile.Sections) { continue } sect := f.objFile.Sections[sym.Sect-1] if sect.Seg != "__TEXT" || sect.Name != "__text" { continue } if strings.HasPrefix(sym.Name, "type..") { continue } if !stdlib && isStdlib(sym.Name, sym.Value, tab) { continue } imports = append(imports, sym.Name) } if len(imports) == 0 { imports = nil } return imports, nil } func (f *machoFile) pclnTable() (*gosym.Table, error) { textStart, symtab, pclntab, err := f.pcln() if err != nil { return nil, nil } return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) } func (f *machoFile) sectionStats() ([]Section, error) { s := make([]Section, len(f.objFile.Sections)) for i, sect := range f.objFile.Sections { h, sigma, err := streamEntropy(sect.Open()) if err != nil { return nil, err } s[i] = Section{ Name: sect.Name, Size: sect.Size, FileSize: sect.Size, Entropy: h, VarEntropy: sigma, Flags: sect.Flags, } } return s, nil }