func newSectionReader(rf io.ReaderAt) (ret sectionReader, err error) { ret.macho, err = macho.NewFile(rf) if err != nil { ret.elf, err = elf.NewFile(rf) } return }
// zipExeReaderElf treats the file as a ELF binary // (linux/BSD/etc... executable) and attempts to find a zip archive. func zipExeReaderElf(rda io.ReaderAt, size int64) (*zip.Reader, error) { file, err := elf.NewFile(rda) if err != nil { return nil, err } var max int64 for _, sect := range file.Sections { if sect.Type == elf.SHT_NOBITS { continue } // Check if this section has a zip file if zfile, err := zip.NewReader(sect, int64(sect.Size)); err == nil { return zfile, nil } // Otherwise move end of file pointer end := int64(sect.Offset + sect.Size) if end > max { max = end } } // No zip file within binary, try appended to end section := io.NewSectionReader(rda, max, size-max) return zip.NewReader(section, section.Size()) }
func elfexec(b []byte) (uintptr, []KexecSegment, error) { f, err := elf.NewFile(bytes.NewReader(b)) if err != nil { return 0, nil, err } scount := 0 for _, v := range f.Progs { if v.Type.String() == "PT_LOAD" { scount++ } } if scount > KEXEC_SEGMENT_MAX { log.Fatalf("Too many segments: got %v, max is %v", scount, KEXEC_SEGMENT_MAX) } segs := make([]KexecSegment, scount) for i, v := range f.Progs { if v.Type.String() == "PT_LOAD" { f := v.Open() b := pages(uintptr(v.Memsz)) if _, err := f.Read(b[:v.Filesz]); err != nil { log.Fatalf("Reading %d bytes of program header %d: %v", v.Filesz, i, err) } segs[i] = makeseg(b, uintptr(v.Paddr)) } } log.Printf("Using ELF image loader") return uintptr(f.Entry), segs, nil //return uintptr(0x40000), segs, nil }
func TestRun(t *testing.T) { file := "samples/simple/O0/strings" f := ioReader(file) _elf, err := elf.NewFile(f) check(wrap(err)) maps := loader.GetSegments(_elf) symbols := loader.GetSymbols(_elf) fmt.Println("done loading") emulator := MakeBlanketEmulator(maps) fmt.Println("done making blanket emulator") for rng, symb := range symbols { if symb.Type == ds.FUNC && strings.Contains(symb.Name, "str") { bbs := extract_bbs(maps, rng) if len(bbs) == 0 { continue } fmt.Printf("found function %v\n", symb.Name) fmt.Printf("running for %v \n", bbs) err := emulator.FullBlanket(bbs) if err != nil { log.WithFields(log.Fields{"error": err}).Fatal("Error running Blanket") } ev := emulator.Config.EventHandler.(*be.EventsToMinHash) fmt.Println("hash %v", ev.GetHash(60)) // fmt.Println("events %v", ev.Inspect()) } } }
func Fuzz(data []byte) int { f, err := elf.NewFile(bytes.NewReader(data)) if err != nil { if f != nil { panic("file is not nil on error") } return 0 } defer f.Close() f.DynamicSymbols() f.ImportedLibraries() f.ImportedSymbols() f.Section(".data") f.SectionByType(elf.SHT_GNU_VERSYM) f.Symbols() dw, err := f.DWARF() if err != nil { if dw != nil { panic("dwarf is not nil on error") } return 1 } dr := dw.Reader() for { e, _ := dr.Next() if e == nil { break } } return 2 }
func process(file *os.File, name string) error { if f, err := elf.NewFile(file); err != nil { return err } else { if fl, err := f.ImportedLibraries(); err != nil { return err } else { if s := f.Section(".interp"); s == nil { return errors.New("No interpreter") } else { if interp, err := s.Data(); err != nil { return err } else { // We could just append the interp but people // expect to see that first. fl = append([]string{string(interp)}, fl...) for _, i := range fl { list[i] = true } } } } } return nil }
// NewReader returns a reader for the export data section of an object // (.o) or archive (.a) file read from r. func NewReader(r io.Reader) (io.Reader, error) { data, err := ioutil.ReadAll(r) if err != nil { return nil, err } // If the file is an archive, extract the first section. const archiveMagic = "!<arch>\n" if bytes.HasPrefix(data, []byte(archiveMagic)) { section, err := firstSection(data[len(archiveMagic):]) if err != nil { return nil, err } data = section } // Data contains an ELF file with a .go_export section. // ELF magic number is "\x7fELF". ef, err := elf.NewFile(bytes.NewReader(data)) if err != nil { return nil, err } sec := ef.Section(".go_export") if sec == nil { return nil, fmt.Errorf("no .go_export section") } return sec.Open(), nil }
func Soname(data []byte) (so string, ok bool) { e, err := elf.NewFile(bytes.NewReader(data)) if err != nil { return so, false } section := e.Section(".dynamic") if section == nil { // not a dynamic binary. return so, false } // e.stringtable(section.Link) dynstr, _ := e.Sections[section.Link].Data() switch e.Class { case elf.ELFCLASS64: n := section.Size / 16 // 2*sizeof(uintptr) values := make([]elf.Dyn64, n) binary.Read(section.Open(), binary.LittleEndian, values) for _, v := range values { if elf.DynTag(v.Tag) == elf.DT_SONAME { return getstring(dynstr, int(v.Val)), true } } case elf.ELFCLASS32: n := section.Size / 8 values := make([]elf.Dyn32, n) binary.Read(section.Open(), binary.LittleEndian, values) for _, v := range values { if elf.DynTag(v.Tag) == elf.DT_SONAME { return getstring(dynstr, int(v.Val)), true } } } return "", false }
func openElf(r *os.File) (rawFile, error) { f, err := elf.NewFile(r) if err != nil { return nil, err } return &elfFile{f}, nil }
func openBinary(name string) (Binary, error) { f, err := os.Open(name) if err != nil { return nil, err } magic := make([]byte, 4) if _, err := f.ReadAt(magic[:], 0); err != nil { return nil, err } if bytes.HasPrefix(magic, []byte{0x7f, 'E', 'L', 'F'}) { e, err := elf.NewFile(f) if err != nil { return nil, err } return &elfBinary{File: e}, nil } else if bytes.HasPrefix(magic, []byte{'M', 'Z'}) { p, err := pe.Open(name) if err != nil { return nil, err } return &peBinary{File: p}, nil } else if bytes.HasPrefix(magic, []byte{0xcf, 0xfa, 0xed, 0xfe}) { m, err := macho.Open(name) if err != nil { return nil, err } return &machoBinary{File: m}, nil } return nil, fmt.Errorf("unsupported binary format") }
func openDebugFile(r io.ReaderAt) (debugFile, error) { f, err := elf.NewFile(r) if err != nil { return nil, err } return &file{f}, nil }
func NewElfLoader(r io.ReaderAt, arch string) (models.Loader, error) { file, err := elf.NewFile(r) if err != nil { return nil, err } var bits int switch file.Class { case elf.ELFCLASS32: bits = 32 case elf.ELFCLASS64: bits = 64 default: return nil, errors.New("Unknown ELF class.") } machineName, ok := machineMap[file.Machine] if !ok { return nil, fmt.Errorf("Unsupported machine: %s", file.Machine) } return &ElfLoader{ LoaderHeader: LoaderHeader{ arch: machineName, bits: bits, os: "linux", entry: file.Entry, byteOrder: file.ByteOrder, }, file: file, }, nil }
func Run(file string) { f := ioReader(file) _elf, err := elf.NewFile(f) check(err) maps := GetSegments(_elf) _ = GetSymbols(_elf) fmt.Printf("%v\n", maps) }
// Opens the export data file at the given path. If this is an ELF file, // searches for and opens the .go_export section. If this is an archive, // reads the export data from the first member, which is assumed to be an ELF file. // This is intended to replicate the logic in gofrontend. func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) { f, err := os.Open(fpath) if err != nil { return } closer = f defer func() { if err != nil && closer != nil { f.Close() } }() var magic [4]byte _, err = f.ReadAt(magic[:], 0) if err != nil { return } var elfreader io.ReaderAt switch string(magic[:]) { case gccgov1Magic, goimporterMagic: // Raw export data. reader = f return case archiveMagic: // TODO(pcc): Read the archive directly instead of using "ar". f.Close() closer = nil cmd := exec.Command("ar", "p", fpath) var out []byte out, err = cmd.Output() if err != nil { return } elfreader = bytes.NewReader(out) default: elfreader = f } ef, err := elf.NewFile(elfreader) if err != nil { return } sec := ef.Section(".go_export") if sec == nil { err = fmt.Errorf("%s: .go_export section not found", fpath) return } reader = sec.Open() return }
func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) { if obj, err := elf.NewFile(f); err == nil { if sect := obj.Section(".text"); sect != nil { textStart = sect.Addr } if sect := obj.Section(".gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, err } } if sect := obj.Section(".gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, err } } return textStart, symtab, pclntab, nil } if obj, err := macho.NewFile(f); err == nil { if sect := obj.Section("__text"); sect != nil { textStart = sect.Addr } if sect := obj.Section("__gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, err } } if sect := obj.Section("__gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, err } } return textStart, symtab, pclntab, nil } if obj, err := pe.NewFile(f); err == nil { if sect := obj.Section(".text"); sect != nil { textStart = uint64(sect.VirtualAddress) } if sect := obj.Section(".gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, err } } if sect := obj.Section(".gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, err } } return textStart, symtab, pclntab, nil } return 0, nil, nil, fmt.Errorf("unrecognized binary format") }
func elfSymbols(f *os.File) (syms []Sym, goarch string) { p, err := elf.NewFile(f) if err != nil { errorf("parsing %s: %v", f.Name(), err) return } elfSyms, err := p.Symbols() if err != nil { errorf("parsing %s: %v", f.Name(), err) return } switch p.Machine { case elf.EM_X86_64: goarch = "amd64" case elf.EM_386: goarch = "386" case elf.EM_ARM: goarch = "arm" } for _, s := range elfSyms { sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} switch s.Section { case elf.SHN_UNDEF: sym.Code = 'U' case elf.SHN_COMMON: sym.Code = 'B' default: i := int(s.Section) if i < 0 || i >= len(p.Sections) { break } sect := p.Sections[i] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' case elf.SHF_ALLOC: sym.Code = 'R' case elf.SHF_ALLOC | elf.SHF_WRITE: sym.Code = 'D' } } if elf.ST_BIND(s.Info) == elf.STB_LOCAL { sym.Code += 'a' - 'A' } syms = append(syms, sym) } return }
func main() { fd, err := os.Open("/bin/bash") argh(err) bash, err := elf.NewFile(fd) argh(err) section := bash.Section(".note.gnu.build-id") if section == nil { panic("No note") } bytes, err := section.Data() argh(err) fmt.Printf("%x\n", bytes[len(bytes)-buildIdLen:]) }
func isStatic(r io.ReaderAt) (bool, error) { f, err := elf.NewFile(r) if err != nil { return false, err } libs, err := f.ImportedLibraries() if err != nil { return false, err } if len(libs) > 0 { return false, nil } return true, nil }
func NewFile(r io.ReaderAt) (binaryx.File, error) { elfBinary, err := elf.NewFile(r) if err == nil { return newFile(&elfx.File{elfBinary}) } machoBinary, err := macho.NewFile(r) if err == nil { return newFile(&machox.File{machoBinary}) } peBinary, err := pe.NewFile(r) if err == nil { return newFile(&pex.File{peBinary}) } return nil, err }
// GetBuildID returns the GNU build-ID for an ELF binary. // // If no build-ID was found but the binary was read without error, it returns // (nil, nil). func GetBuildID(binary io.ReaderAt) ([]byte, error) { f, err := elf.NewFile(binary) if err != nil { return nil, err } findBuildID := func(notes []elfNote) ([]byte, error) { var buildID []byte for _, note := range notes { if note.Name == "GNU" && note.Type == noteTypeGNUBuildID { if buildID == nil { buildID = note.Desc } else { return nil, fmt.Errorf("multiple build ids found, don't know which to use!") } } } return buildID, nil } for _, p := range f.Progs { if p.Type != elf.PT_NOTE { continue } notes, err := parseNotes(p.Open(), int(p.Align), f.ByteOrder) if err != nil { return nil, err } if b, err := findBuildID(notes); b != nil || err != nil { return b, err } } for _, s := range f.Sections { if s.Type != elf.SHT_NOTE { continue } notes, err := parseNotes(s.Open(), int(s.Addralign), f.ByteOrder) if err != nil { return nil, err } if b, err := findBuildID(notes); b != nil || err != nil { return b, err } } return nil, nil }
func grabDebugLineSection(p string, t *testing.T) []byte { f, err := os.Open(p) if err != nil { t.Fatal(err) } defer f.Close() ef, err := elf.NewFile(f) if err == nil { data, _ := ef.Section(".debug_line").Data() return data } mf, _ := macho.NewFile(f) data, _ := mf.Section("__debug_line").Data() return data }
func elfSymbols(f *os.File) []Sym { p, err := elf.NewFile(f) if err != nil { errorf("parsing %s: %v", f.Name(), err) return nil } elfSyms, err := p.Symbols() if err != nil { errorf("parsing %s: %v", f.Name(), err) return nil } var syms []Sym for _, s := range elfSyms { sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} switch s.Section { case elf.SHN_UNDEF: sym.Code = 'U' case elf.SHN_COMMON: sym.Code = 'B' default: i := int(s.Section) if i <= 0 || i > len(p.Sections) { break } sect := p.Sections[i-1] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' case elf.SHF_ALLOC: sym.Code = 'R' case elf.SHF_ALLOC | elf.SHF_WRITE: sym.Code = 'D' } } if elf.ST_BIND(s.Info) == elf.STB_LOCAL { sym.Code += 'a' - 'A' } syms = append(syms, sym) } return syms }
func (dbp *Process) findExecutable(path string) (*elf.File, error) { if path == "" { path = fmt.Sprintf("/proc/%d/exe", dbp.Pid) } f, err := os.OpenFile(path, 0, os.ModePerm) if err != nil { return nil, err } elfFile, err := elf.NewFile(f) if err != nil { return nil, err } data, err := elfFile.DWARF() if err != nil { return nil, err } dbp.dwarf = data return elfFile, nil }
// readELFGoBuildID the Go build ID string from an ELF binary. // The Go build ID is stored in a note described by an ELF PT_NOTE prog header. // The caller has already opened filename, to get f, and read the first 4 kB out, in data. func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) { // Assume the note content is in the first 4 kB, already read. // Rewrite the ELF header to set shnum to 0, so that we can pass // the data to elf.NewFile and it will decode the Prog list but not // try to read the section headers and the string table from disk. // That's a waste of I/O when all we care about is the Prog list // and the one ELF note. switch elf.Class(data[elf.EI_CLASS]) { case elf.ELFCLASS32: data[48] = 0 data[49] = 0 case elf.ELFCLASS64: data[60] = 0 data[61] = 0 } const elfGoBuildIDTag = 4 ef, err := elf.NewFile(bytes.NewReader(data)) if err != nil { return "", &os.PathError{Path: filename, Op: "parse", Err: err} } for _, p := range ef.Progs { if p.Type != elf.PT_NOTE || p.Off >= uint64(len(data)) || p.Off+p.Filesz >= uint64(len(data)) || p.Filesz < 16 { continue } note := data[p.Off : p.Off+p.Filesz] nameSize := ef.ByteOrder.Uint32(note) valSize := ef.ByteOrder.Uint32(note[4:]) tag := ef.ByteOrder.Uint32(note[8:]) name := note[12:16] if nameSize != 4 || 16+valSize > uint32(len(note)) || tag != elfGoBuildIDTag || !bytes.Equal(name, elfGoNote) { continue } return string(note[16 : 16+valSize]), nil } // No note. Treat as successful but build ID empty. return "", nil }
func main() { file := os.Args[1] log.SetLevel(log.ErrorLevel) fmt.Printf("%v\n", os.Args) if len(os.Args) >= 3 && os.Args[2] == "d" { log.SetLevel(log.DebugLevel) } f := ioReader(file) _elf, err := elf.NewFile(f) check(wrap(err)) maps := loader.GetSegments(_elf) symbols := loader.GetSymbols(_elf) fmt.Println("done loading") fmt.Printf("maps %v\n", maps) for rng, symb := range symbols { if !are_we_interessted_in_this(symb) { continue } bbs := extract_bbs(maps, rng) if len(bbs) == 0 { continue } fmt.Printf("%v : ", pad_func_name(symb.Name)) emulator := MakeBlanketEmulator(maps) err := emulator.FullBlanket(bbs) if err != nil { log.WithFields(log.Fields{"error": err}).Error("Error running Blanket") continue } ev := emulator.Events fmt.Printf("hash %v\n", hex.EncodeToString(ev.GetHash(32))) log.WithFields(log.Fields{"events": ev.Inspect()}).Debug("Done running Blanket") emulator.Close() emulator = nil } }
func FixFile(filename string) error { fd, err := os.OpenFile(filename, os.O_RDWR, 0) if err != nil { return err } defer fd.Close() elf, err := ELF.NewFile(fd) if err != nil { log.Print("Failed to parse ELF. This can happen if the binary is already packed.") return err } defer elf.Close() log.Printf("%+v", elf.FileHeader) err = fixelf(elf, fd) if err != nil { log.Fatal("Failure to read ELF header") return err } return nil }
func main() { // cat <bin> | ./a.out if len(os.Args) == 1 { var buf bytes.Buffer if _, err := io.Copy(&buf, os.Stdin); err != nil { fmt.Println(err) os.Exit(1) } data := buf.Bytes() if len(data) > 0 { file, e := elf.NewFile(bytes.NewReader(data)) if e != nil { fmt.Println(INVALID) os.Exit(1) } checksec(file) } // FILE [FILE]* } else { for _, arg := range os.Args[1:] { file, e := elf.Open(arg) if e != nil { fmt.Printf("%s,%s\n", arg, INVALID) } else { fmt.Print(arg, SEP) checksec(file) file.Close() } } } }
// This function is an exact copy of gccgoimporter.openExportFile. func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) { f, err := os.Open(fpath) if err != nil { return } defer func() { if err != nil { f.Close() } }() closer = f var magic [4]byte _, err = f.ReadAt(magic[:], 0) if err != nil { return } if string(magic[:]) == "v1;\n" { // Raw export data. reader = f return } ef, err := elf.NewFile(f) if err != nil { return } sec := ef.Section(".go_export") if sec == nil { err = fmt.Errorf("%s: .go_export section not found", fpath) return } reader = sec.Open() return }
func Depends(data []byte) (needed []string, err error) { e, err := elf.NewFile(bytes.NewReader(data)) if err != nil { return nil, err } section := e.Section(".dynamic") if section == nil { // not a dynamic binary. return nil, nil } // e.stringtable(section.Link) dynstr, _ := e.Sections[section.Link].Data() switch e.Class { case elf.ELFCLASS64: n := section.Size / 16 // 2*sizeof(uintptr) values := make([]elf.Dyn64, n) binary.Read(section.Open(), binary.LittleEndian, values) for _, v := range values { if elf.DynTag(v.Tag) == elf.DT_NEEDED { so := getstring(dynstr, int(v.Val)) needed = append(needed, so) } } case elf.ELFCLASS32: n := section.Size / 8 values := make([]elf.Dyn32, n) binary.Read(section.Open(), binary.LittleEndian, values) for _, v := range values { if elf.DynTag(v.Tag) == elf.DT_NEEDED { so := getstring(dynstr, int(v.Val)) needed = append(needed, so) } } } return needed, nil }
func findAddr(r io.ReaderAt, sym string) (uintptr, error) { file, err := elf.NewFile(r) if err != nil { return 0, err } defer file.Close() var ( textStart uint64 symtab, pclntab []byte ) if sect := file.Section(".text"); sect != nil { textStart = sect.Addr } if sect := file.Section(".gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, err } } if sect := file.Section(".gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, err } } tab, err := gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) if err != nil { return 0, err } fn := tab.LookupFunc(sym) if fn == nil { return 0, fmt.Errorf("could not find symbol %q", sym) } return uintptr(fn.Entry), nil }