func openExecutablePath(path string) (*pe.File, error) { f, err := os.OpenFile(path, 0, os.ModePerm) if err != nil { return nil, err } return pe.NewFile(f) }
func CheckPE(file string) bool { r := _ioReader(file) //reader interface for file f, err := pe.NewFile(r) //open the file as a PE if err != nil { return false //Not a PE file } //Reading DOS header var dosheader [96]byte r.ReadAt(dosheader[0:], 0) if dosheader[0] == 'M' && dosheader[1] == 'Z' { //if we get MZ signoff := int64(binary.LittleEndian.Uint32(dosheader[0x3c:])) var sign [4]byte r.ReadAt(sign[:], signoff) if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) { //if not PE\0\0 return false //Invalid PE File Format } } if (f.Characteristics & 0x2000) == 0x2000 { //IMAGE_FILE_DLL signature return false //it's a DLL, OCX, CPL file, we want a EXE file } f.Close() return true //it is a valid EXE file }
func Open(files string) { file := ioReader(files) f, err := pe.NewFile(file) if err != nil { 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 openPE(r *os.File) (rawFile, error) { f, err := pe.NewFile(r) if err != nil { return nil, err } switch f.OptionalHeader.(type) { case *pe.OptionalHeader32, *pe.OptionalHeader64: // ok default: return nil, fmt.Errorf("unrecognized PE format") } return &peFile{f}, 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 }
func (dbp *Process) findExecutable(path string) (*pe.File, error) { if path == "" { // TODO: Find executable path from PID/handle on Windows: // https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx return nil, fmt.Errorf("not yet implemented") } f, err := os.OpenFile(path, 0, os.ModePerm) if err != nil { return nil, err } peFile, err := pe.NewFile(f) if err != nil { return nil, err } dbp.dwarf, err = dwarfFromPE(peFile) if err != nil { return nil, err } return peFile, nil }
func peSymbols(f *os.File) []Sym { p, err := pe.NewFile(f) if err != nil { errorf("parsing %s: %v", f.Name(), err) return nil } var syms []Sym for _, s := range p.Symbols { sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} if s.SectionNumber == 0 { sym.Code = 'U' } else if int(s.SectionNumber) <= len(p.Sections) { sect := p.Sections[s.SectionNumber-1] const ( text = 0x20 data = 0x40 bss = 0x80 permX = 0x20000000 permR = 0x40000000 permW = 0x80000000 ) ch := sect.Characteristics switch { case ch&text != 0: sym.Code = 'T' case ch&data != 0: if ch&permW == 0 { sym.Code = 'R' } else { sym.Code = 'D' } case ch&bss != 0: sym.Code = 'B' } } syms = append(syms, sym) } return syms }
// zipExeReaderPe treats the file as a Portable Exectuable binary // (Windows executable) and attempts to find a zip archive. func zipExeReaderPe(rda io.ReaderAt, size int64) (*zip.Reader, error) { file, err := pe.NewFile(rda) if err != nil { return nil, err } var max int64 for _, sec := range file.Sections { // Check if this section has a zip file if zfile, err := zip.NewReader(sec, int64(sec.Size)); err == nil { return zfile, nil } // Otherwise move end of file pointer end := int64(sec.Offset + sec.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 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 } pf, err := pe.NewFile(f) if err == nil { data, _ := pf.Section(".debug_line").Data() return data } mf, _ := macho.NewFile(f) data, _ := mf.Section("__debug_line").Data() return data }
func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn string) error { if ctxt.Debugvlog != 0 { ctxt.Logf("%5.2f ldpe %s\n", obj.Cputime(), pn) } localSymVersion := ctxt.Syms.IncVersion() sectsyms := make(map[*pe.Section]*Symbol) sectdata := make(map[*pe.Section][]byte) // Some input files are archives containing multiple of // object files, and pe.NewFile seeks to the start of // input file and get confused. Create section reader // to stop pe.NewFile looking before current position. sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1) // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details) f, err := pe.NewFile(sr) if err != nil { return err } defer f.Close() // TODO return error if found .cormeta // create symbols for mapped sections for _, sect := range f.Sections { if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 { continue } if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 { // This has been seen for .idata sections, which we // want to ignore. See issues 5106 and 5273. continue } data, err := sect.Data() if err != nil { return err } sectdata[sect] = data name := fmt.Sprintf("%s(%s)", pkg, sect.Name) s := ctxt.Syms.Lookup(name, localSymVersion) switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) { case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata s.Type = obj.SRODATA case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss s.Type = obj.SNOPTRBSS case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data s.Type = obj.SNOPTRDATA case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text s.Type = obj.STEXT default: return fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name) } s.P = data s.Size = int64(len(data)) sectsyms[sect] = s if sect.Name == ".rsrc" { setpersrc(ctxt, s) } } // load relocations for _, rsect := range f.Sections { if _, found := sectsyms[rsect]; !found { continue } if rsect.NumberOfRelocations == 0 { continue } if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 { continue } if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 { // This has been seen for .idata sections, which we // want to ignore. See issues 5106 and 5273. continue } rs := make([]Reloc, rsect.NumberOfRelocations) for j, r := range rsect.Relocs { rp := &rs[j] if int(r.SymbolTableIndex) >= len(f.COFFSymbols) { return fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols)) } pesym := &f.COFFSymbols[r.SymbolTableIndex] gosym, err := readpesym(ctxt, f, pesym, sectsyms, localSymVersion) if err != nil { return err } if gosym == nil { name, err := pesym.FullName(f.StringTable) if err != nil { name = string(pesym.Name[:]) } return fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type) } rp.Sym = gosym rp.Siz = 4 rp.Off = int32(r.VirtualAddress) switch r.Type { default: Errorf(sectsyms[rsect], "%s: unknown relocation type %d;", pn, r.Type) fallthrough case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 IMAGE_REL_AMD64_ADDR32NB: rp.Type = obj.R_PCREL rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:]))) case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32: rp.Type = obj.R_ADDR // load addend from image rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:]))) case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 rp.Siz = 8 rp.Type = obj.R_ADDR // load addend from image rp.Add = int64(Le64(sectdata[rsect][rp.Off:])) } // ld -r could generate multiple section symbols for the // same section but with different values, we have to take // that into account if issect(pesym) { rp.Add += int64(pesym.Value) } } sort.Sort(rbyoff(rs[:rsect.NumberOfRelocations])) s := sectsyms[rsect] s.R = rs s.R = s.R[:rsect.NumberOfRelocations] } // enter sub-symbols into symbol table. for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 { pesym := &f.COFFSymbols[i] numaux = int(pesym.NumberOfAuxSymbols) name, err := pesym.FullName(f.StringTable) if err != nil { return err } if name == "" { continue } if issect(pesym) { continue } if int(pesym.SectionNumber) > len(f.Sections) { continue } if pesym.SectionNumber == IMAGE_SYM_DEBUG { continue } var sect *pe.Section if pesym.SectionNumber > 0 { sect = f.Sections[pesym.SectionNumber-1] if _, found := sectsyms[sect]; !found { continue } } s, err := readpesym(ctxt, f, pesym, sectsyms, localSymVersion) if err != nil { return err } if pesym.SectionNumber == 0 { // extern if s.Type == obj.SDYNIMPORT { s.Plt = -2 // flag for dynimport in PE object files. } if s.Type == obj.SXREF && pesym.Value > 0 { // global data s.Type = obj.SNOPTRDATA s.Size = int64(pesym.Value) } continue } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) { sect = f.Sections[pesym.SectionNumber-1] if _, found := sectsyms[sect]; !found { Errorf(s, "%s: missing sect.sym", pn) } } else { Errorf(s, "%s: sectnum < 0!", pn) } if sect == nil { return nil } if s.Outer != nil { if s.Attr.DuplicateOK() { continue } Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name) } sectsym := sectsyms[sect] s.Sub = sectsym.Sub sectsym.Sub = s s.Type = sectsym.Type | obj.SSUB s.Value = int64(pesym.Value) s.Size = 4 s.Outer = sectsym if sectsym.Type == obj.STEXT { if s.Attr.External() && !s.Attr.DuplicateOK() { Errorf(s, "%s: duplicate symbol definition", pn) } s.Attr |= AttrExternal } } // Sort outer lists by address, adding to textp. // This keeps textp in increasing address order. for _, sect := range f.Sections { s := sectsyms[sect] if s == nil { continue } if s.Sub != nil { s.Sub = listsort(s.Sub) } if s.Type == obj.STEXT { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList ctxt.Textp = append(ctxt.Textp, s) for s = s.Sub; s != nil; s = s.Sub { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList ctxt.Textp = append(ctxt.Textp, s) } } } return nil }
func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte, err error) { if obj, err := elf.NewFile(f); err == nil { if sect := obj.Section(".text"); sect != nil { textStart = sect.Addr textData, _ = sect.Data() } if sect := obj.Section(".gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, nil, err } } if sect := obj.Section(".gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, nil, err } } return textStart, textData, symtab, pclntab, nil } if obj, err := macho.NewFile(f); err == nil { if sect := obj.Section("__text"); sect != nil { textStart = sect.Addr textData, _ = sect.Data() } if sect := obj.Section("__gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, nil, err } } if sect := obj.Section("__gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, nil, err } } return textStart, textData, symtab, pclntab, nil } if obj, err := pe.NewFile(f); err == nil { var imageBase uint64 switch oh := obj.OptionalHeader.(type) { case *pe.OptionalHeader32: imageBase = uint64(oh.ImageBase) case *pe.OptionalHeader64: imageBase = oh.ImageBase default: return 0, nil, nil, nil, fmt.Errorf("pe file format not recognized") } if sect := obj.Section(".text"); sect != nil { textStart = imageBase + uint64(sect.VirtualAddress) textData, _ = sect.Data() } if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil { return 0, nil, nil, nil, err } if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil { return 0, nil, nil, nil, err } return textStart, textData, symtab, pclntab, nil } if obj, err := plan9obj.NewFile(f); err == nil { sym, err := findPlan9Symbol(obj, "text") if err != nil { return 0, nil, nil, nil, err } textStart = sym.Value if sect := obj.Section("text"); sect != nil { textData, _ = sect.Data() } if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil { return 0, nil, nil, nil, err } if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil { return 0, nil, nil, nil, err } return textStart, textData, symtab, pclntab, nil } return 0, nil, nil, nil, fmt.Errorf("unrecognized binary format") }
func peSymbols(f *os.File) (syms []Sym, goarch string) { p, err := pe.NewFile(f) if err != nil { errorf("parsing %s: %v", f.Name(), err) return } // Build sorted list of addresses of all symbols. // We infer the size of a symbol by looking at where the next symbol begins. var addrs []uint64 var imageBase uint64 switch oh := p.OptionalHeader.(type) { case *pe.OptionalHeader32: imageBase = uint64(oh.ImageBase) goarch = "386" case *pe.OptionalHeader64: imageBase = oh.ImageBase goarch = "amd64" default: errorf("parsing %s: file format not recognized", f.Name()) return } for _, s := range p.Symbols { const ( N_UNDEF = 0 // An undefined (extern) symbol N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) N_DEBUG = -2 // A debugging symbol ) sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} switch s.SectionNumber { case N_UNDEF: sym.Code = 'U' case N_ABS: sym.Code = 'C' case N_DEBUG: sym.Code = '?' default: if s.SectionNumber < 0 { errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber) return } if len(p.Sections) < int(s.SectionNumber) { errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections)) return } sect := p.Sections[s.SectionNumber-1] const ( text = 0x20 data = 0x40 bss = 0x80 permX = 0x20000000 permR = 0x40000000 permW = 0x80000000 ) ch := sect.Characteristics switch { case ch&text != 0: sym.Code = 'T' case ch&data != 0: if ch&permW == 0 { sym.Code = 'R' } else { sym.Code = 'D' } case ch&bss != 0: sym.Code = 'B' } sym.Addr += imageBase + uint64(sect.VirtualAddress) } syms = append(syms, sym) addrs = append(addrs, sym.Addr) } sort.Sort(uint64s(addrs)) for i := range syms { j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) if j < len(addrs) { syms[i].Size = int64(addrs[j] - syms[i].Addr) } } return }
func check(fname string) error { f, err := os.Open(fname) if err != nil { return err } defer f.Close() pefile, err := pe.NewFile(f) if err != nil { return err } dch := getDllCharacteristics(pefile) subsystem := getSubsystem(pefile) if flagVerbose { log.Printf(" Machine = 0x%04d\n", pefile.Machine) log.Printf(" Subsystem = %d\n", subsystem) log.Printf(" DllCharacteristics = 0x%04x\n", dch) } // Device drivers always have these flags set. if subsystem != IMAGE_SUBSYSTEM_NATIVE { if dch&IMAGE_DLLCHARACTERISTICS_NX_COMPAT == 0 { fmt.Printf("%s:does not have NXCOMPAT bit set\n", fname) } if dch&IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE == 0 { fmt.Printf("%s:does not have DYNAMICBASE bit set\n", fname) } } // Check for the /GS flag dir, err := readImageLoadConfigDirectory(pefile) if err != nil { return err } if dir != nil { var securityCookie uint64 switch imdir := dir.(type) { case *ImageLoadConfigDirectory32: securityCookie = uint64(imdir.SecurityCookie) case *ImageLoadConfigDirectory64: securityCookie = imdir.SecurityCookie default: panic("bad load config directory type") } if flagVerbose { log.Printf(" SecurityCookie = 0x%x", securityCookie) } if securityCookie == 0 { fmt.Printf("%s:does not use security cookies\n", fname) } // Check for SAFESEH on Windows x86 only if pefile.Machine == pe.IMAGE_FILE_MACHINE_I386 { if dch&IMAGE_DLLCHARACTERISTICS_NO_SEH == 0 { handlerTable := dir.(*ImageLoadConfigDirectory32).SEHandlerTable handlerCount := dir.(*ImageLoadConfigDirectory32).SEHandlerTable if handlerTable == 0 { fmt.Printf("%s:does not use SAFESEH\n", fname) } if flagVerbose { log.Printf(" SEHandlerTable = 0x%x\n", handlerTable) log.Printf(" SEHandlerCount = 0x%x\n", handlerCount) } } else if flagVerbose { log.Println(" Skipping SAFESEH check because image has NO_SEH bit set") } } else if flagVerbose { log.Println(" Skipping SAFESEH check on non-x86 file") } } // Check for R/W shared image sections var rwSharedFlags uint32 = IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE for _, section := range pefile.Sections { if section.Characteristics&rwSharedFlags == rwSharedFlags { fmt.Printf("%s:has a R/W shared section named %s\n", fname, section.Name) } } return nil }