// Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pe import ( "encoding/binary" "fmt" "internal/saferio" "io" "strconv" ) // SectionHeader32 represents real PE COFF section header. type SectionHeader32 struct { Name [8]uint8 VirtualSize uint32 VirtualAddress uint32 SizeOfRawData uint32 PointerToRawData uint32 PointerToRelocations uint32 PointerToLineNumbers uint32 NumberOfRelocations uint16 NumberOfLineNumbers uint16 Characteristics uint32 } // fullName finds real name of section sh. Normally name is stored // in sh.Name, but if it is longer then 8 characters, it is stored // in COFF string table st instead. func (sh *SectionHeader32) fullName(st StringTable) (string, error) { if sh.Name[0] != '/' { return cstring(sh.Name[:]), nil } i, err := strconv.Atoi(cstring(sh.Name[1:])) if err != nil { return "", err } return st.String(uint32(i)) } // TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here // Reloc represents a PE COFF relocation. // Each section contains its own relocation list. type Reloc struct { VirtualAddress uint32 SymbolTableIndex uint32 Type uint16 } func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) { if sh.NumberOfRelocations <= 0 { return nil, nil } _, err := r.Seek(int64(sh.PointerToRelocations), io.SeekStart) if err != nil { return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err) } relocs := make([]Reloc, sh.NumberOfRelocations) err = binary.Read(r, binary.LittleEndian, relocs) if err != nil { return nil, fmt.Errorf("fail to read section relocations: %v", err) } return relocs, nil } // SectionHeader is similar to [SectionHeader32] with Name // field replaced by Go string. type SectionHeader struct { Name string VirtualSize uint32 VirtualAddress uint32 Size uint32 Offset uint32 PointerToRelocations uint32 PointerToLineNumbers uint32 NumberOfRelocations uint16 NumberOfLineNumbers uint16 Characteristics uint32 } // Section provides access to PE COFF section. type Section struct { SectionHeader Relocs []Reloc // Embed ReaderAt for ReadAt method. // Do not embed SectionReader directly // to avoid having Read and Seek. // If a client wants Read and Seek it must use // Open() to avoid fighting over the seek offset // with other clients. io.ReaderAt sr *io.SectionReader } // Data reads and returns the contents of the PE section s. // // If s.Offset is 0, the section has no contents, // and Data will always return a non-nil error. func (s *Section) Data() ([]byte, error) { return saferio.ReadDataAt(s.sr, uint64(s.Size), 0) } // Open returns a new ReadSeeker reading the PE section s. // // If s.Offset is 0, the section has no contents, and all calls // to the returned reader will return a non-nil error. func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } // Section characteristics flags. const ( IMAGE_SCN_CNT_CODE = 0x00000020 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 IMAGE_SCN_LNK_COMDAT = 0x00001000 IMAGE_SCN_MEM_DISCARDABLE = 0x02000000 IMAGE_SCN_MEM_EXECUTE = 0x20000000 IMAGE_SCN_MEM_READ = 0x40000000 IMAGE_SCN_MEM_WRITE = 0x80000000 )