pecoff

package module
v0.0.0-...-a332238 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2020 License: GPL-3.0 Imports: 8 Imported by: 2

README

pecoff

Build Status Coverage Go Report Card GoDoc License

This package implements access to PE (Microsoft Windows Portable Executable) and MS-COFF (Microsoft Common Object File Format) files in Go programming language.

In contrast to the debug.pe package from the standard library of Go, this implementation gives you access to much more file contents, such as:

  • Dos header;
  • File header;
  • Optional header;
  • Data directories of an optional header;
  • Headers of sections;
  • Relocations of sections;
  • String table of a COFF file;
  • and others...
Example

The following example shows you how to check MachineType field inside a FileHeader

func Example_MachineType() {
    file, _ := os.Open(testDir + "exe_32_fasm+1-71-39_aslr")
    defer file.Close()
    // Creating PE/COFF File
    pe := pecoff.Explore(binutil.WrapReaderAt(file))
    // Reading DosHeader to get offset to the file header
    pe.ReadDosHeader()
    // Reading FileHeader
    pe.ReadFileHeader()
    // Releasing resources (i.e. file)
    pe.Seal()
    // Priting string represntation of the MachineType
    fmt.Println(windef.MAP_IMAGE_FILE_MACHINE[pe.FileHeader.Machine])
    // Output:
    // I386
}

More usage examples can be found in the tests

Limitations

This package can fully parse only PE/COFF files which are compiled for the following two architectures:

  • AMD64 IMAGE_FILE_MACHINE_AMD64
  • I386 IMAGE_FILE_MACHINE_I386
Thread safety

This package is not thread safe. Calling Read* methods must be done from a single thread, otherwise the consistency and correctness of the parsed data cannot be guaranteed. But all other operations, which don't modify the contents of the File can be safely performed from a multiple goroutines (i.e. accessing the File object and its fields).

TODO

Add support for the following data directories of an optional header:

  • Exports
  • Resources
  • Exceptions
  • Security
  • Debug
  • Architecture
  • GlobalPtrs
  • TLS
  • LoadConfig
  • BoundImports
  • IAT
  • DelayImports
  • COMDescriptors
License

GNU General Public License v3.0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBaseRelNotFound   = errors.New("pecoff: base relocation not found")
	ErrBaseRelsNotSorted = errors.New("pecoff: base relocations are not sorted")
)

List of errors

View Source
var (
	ErrAlreadyRead    = errors.New("pecoff: already read")
	ErrInvPeSign      = errors.New("pecoff: invalid PE signature")
	ErrUnsuppMachType = errors.New("pecoff: unsupported image file machine type")

	// A group of errors which are most-likey to be returned if a client
	// of this package is using Read* methods in a wrong order.
	ErrNoDosHeader       = errors.New("pecoff: dos header is not read")
	ErrNoFileHeader      = errors.New("pecoff: file header is not read")
	ErrNoOptHeader       = errors.New("pecoff: optional file header is not read")
	ErrNoSectionsHeaders = errors.New("pecoff: headers of sections are not read")

	// A group of errors which are returned by Read* wrapper methods, such as
	//     ReadAll, ReadHeaders, ReadSectionsRawData, ReadDataDirs, etc...
	// These errors specify what exatcly has been failed to read (or check).
	ErrFailReadHeaders         = errors.New("pecoff: failed to read headers")
	ErrFailReadDosHeader       = errors.New("pecoff: failed to read DOS header")
	ErrFailReadSignature       = errors.New("pecoff: failed to read PE signature")
	ErrFailReadFileHeader      = errors.New("pecoff: failed to read file header")
	ErrFailReadOptHeader       = errors.New("pecoff: failed to read optional file header")
	ErrFailReadSymbols         = errors.New("pecoff: failed to read symbols")
	ErrFailReadStringTable     = errors.New("pecoff: failed to read string table")
	ErrFailReadSectionsHeaders = errors.New("pecoff: failed to read headers of sections")
	ErrFailReadSectionsData    = errors.New("pecoff: failed to read sections raw data")
	ErrFailReadSectionsRelocs  = errors.New("pecoff: failed to read relocations of sections")
	ErrFailReadSectionsLineNrs = errors.New("pecoff: failed to read line numbers of sections")
	ErrFailReadDataDirs        = errors.New("pecoff: failed to read data directories")
	ErrFailReadImports         = errors.New("pecoff: failed to read imports data directory")
	ErrFailReadBaseRelocs      = errors.New("pecoff: failed to read base relocations data directory")
	ErrFailCheckDosHeader      = errors.New("pecoff: failed to check whether the file has DOS header")

	// A group of errors which are to be formatted (used in errorf or wrapErrorf method)
	ErrfFailVaToOff             = "pecoff: failed to convert VA (@%08X) to file offset"                  //fmt: VirtualAddress
	ErrfFailGetSectByVA         = "pecoff: failed to find section which contains VA (@%08X)"             //fmt: VirtualAddress
	ErrfOptHdrUnkSize           = "pecoff: optionalHeader has unexpected size (%d)"                      //fmt: size
	ErrfFailReadSectionHeader   = "pecoff: failed to read a header of section#%d (%X)"                   //fmt: sectionId, offset
	ErrfFailReadSectionRawData  = "pecoff: failed to read rawdata of section#%d (%X)"                    //fmt: sectionId, offset
	ErrfFailReadSectionReloc    = "pecoff: failed to read relocation#%d of section #%d (%X)"             //fmt: relocationId, sectionId, offset
	ErrfFailReadSymbol          = "pecoff: failed to read symbol#%d (%X)"                                //fmt: symbolId, offset
	ErrfFailReadStrTblSize      = "pecoff: failed to read string table size (%X)"                        //fmt: offset
	ErrfFailReadStrTbl          = "pecoff: failed to read string table (%X)"                             //fmt: offset
	ErrfFailReadImpDesc         = "pecoff: failed to read import descriptor#%d (%X)"                     //fmt: descriptorId, offset
	ErrfFailReadLibName         = "pecoff: failed to read library name (@%08X)"                          //fmt: nameVA
	ErrfFailReadImpThunk        = "pecoff: failed to read import thunk (%X)"                             //fmt: offset
	ErrfFailReadImpThunkHint    = "pecoff: failed to read import thunk hint (@%08X)"                     //fmt: VirtualAddress
	ErrfFailReadImpThunkName    = "pecoff: failed to read import thunk name (@%08X)"                     //fmt: VirtualAddress
	ErrfFailReadBaseRel         = "pecoff: failed to read base relocation#%d (%X)"                       //fmt: relocationId, offset
	ErrfFailReadBaseRelEntries  = "pecoff: failed to read base relocation#%d entries (%X)"               //fmt: relocationId, offset
	ErrfFailFindBaseRelsFromInt = "pecoff: failed to find base relocations within interval [%08X; %08X)" //fmt: VirtualAddress, VirtualAddress
)

List of errors

View Source
var (
	ErrSectionsNoIndexMap = errors.New("pecoff: sections are sorted, but no indexMap was set")
	ErrSectionsNotSorted  = errors.New("pecoff: sections array is not sorted")
	ErrSectionNotFound    = errors.New("pecoff: section was not found")
)

List of errors {{{1

View Source
var (
	ErrStrOffOutOfBounds = errors.New("string offset is out of bounds")
)

List of errors which can be returned by methods of StringTable.

Functions

func ErrorFlatten

func ErrorFlatten(err error) error

ErrorFlatten returns err.ToMultiError if `err` implements FileError, if not, an `err` without modifications is returned.

Types

type BaseRelocationBlock

type BaseRelocationBlock struct {
	windef.BaseRelocation
	// contains filtered or unexported fields
}

BaseRelocationBlock embedds windef.BaseRelocation, and holds its parsed base relocation entries.

func (*BaseRelocationBlock) Entries

func (brb *BaseRelocationBlock) Entries() []BaseRelocationEntry

Entries returns a slice of base relcation entries of this block. Returned slice must not be modified directly!

type BaseRelocationEntry

type BaseRelocationEntry uint16

BaseRelocationEntry is a 16 bit value (according to the pecoff specification) which has bitfields: Type (4 H.O. bits) and Offset (12 L.O. bits).

func (BaseRelocationEntry) Offset

func (r BaseRelocationEntry) Offset() uint32

Offset from the starting address that was specified in the Page RVA field for the block (BaseRelocationBlock.VirtualAddress) It specifies where the base relocation is to be applied.

func (BaseRelocationEntry) Type

func (r BaseRelocationEntry) Type() int

Type returns a value, which can be any of IMAGE_REL_BASED_* constant.

type DataDirs

type DataDirs struct {
	// Exports         *DdExports
	Imports *DdImports
	// Resources       *DdResources
	// Exceptions      *DdExceptions
	// Security        *DdSecurity
	BaseRelocations *DdBaseRelocations
}

DataDirs represents a collection of pointers to all possible data directories.

type DdBaseRelocations

type DdBaseRelocations struct {
	windef.DataDirectory
	// contains filtered or unexported fields
}

DdBaseRelocations is a base relocations data directory wrapper which holds a (sorted ascending by VirtualAddress) slice of (pointers to) BaseRelocationBlock-s

func (*DdBaseRelocations) Get

Get returns a slice of (pointers to) base relocation blocks. Returned slice must not be modified directly!

func (*DdBaseRelocations) GetByVA

GetByVA is a wrapper method of GetIDByVA, which returns a (pointer to the) block instead of an id.

func (*DdBaseRelocations) GetFromInterval

func (r *DdBaseRelocations) GetFromInterval(begin, end uint32) ([]*BaseRelocationBlock, error)

GetFromInterval returns a 'sliced' slice `blocks` of (pointers to) BaseRelocationBlock-s, which have VirtualAddress in the specified interval [begin; end). This method assumes a slice of blocks to be sorted according to the specification of DdBaseRelocations struct.

func (*DdBaseRelocations) GetIDByVA

func (r *DdBaseRelocations) GetIDByVA(va uint32) (int, error)

GetIDByVA uses a binary search (sort.Search) to find an id of a block which contains virtual address `va`. If such block doesn't exist an error ErrBaseRelNotFound is returned. This method requires a slice of blocks to be sorted, otherwise an error ErrBaseRelsNotSorted is returned.

func (*DdBaseRelocations) Len

func (r *DdBaseRelocations) Len() int

Len returns a count of base relocation blocks This method is required to implement the sort.Interface

func (*DdBaseRelocations) Less

func (r *DdBaseRelocations) Less(i, j int) bool

Less returns true if VirtualAddress of blocks[i] is less that VirtualAddress of blocks[j] This method is required to implement the sort.Interface

func (*DdBaseRelocations) Swap

func (r *DdBaseRelocations) Swap(i, j int)

Swap swaps blocks This method is required to implement the sort.Interface

type DdImports

type DdImports struct {
	windef.DataDirectory
	// contains filtered or unexported fields
}

DdImports is an imports data directory wrapper which holds imported libraries and their functions.

func (*DdImports) Get

func (i *DdImports) Get() map[string]*Import

Get returns a map of imported functions, where the key is a library.

func (*DdImports) Import

func (i *DdImports) Import(library string) *Import

Import returns a pointer to Import with specified library. If library is not imported, nil is returned.

type File

type File struct {
	binutil.ReaderAtInto
	DosHeader      *windef.DosHeader
	Signature      [4]byte
	FileHeader     *windef.FileHeader
	OptionalHeader *OptionalHeader
	Sections       *Sections
	Symbols        Symbols
	StringTable    StringTable
}

File contains embedded io.Reader and all the fields of a PE/COFF file.

func Explore

func Explore(reader binutil.ReaderAtInto) *File

Explore creates a new File object

func (*File) GetFileHeaderOffset

func (f *File) GetFileHeaderOffset() int64

GetFileHeaderOffset returns an offset to the FileHeader within PE file. If DosHeader is nil (i.e. doesn't exists, or wasn't read), offset is returned in terms of a COFF file.

func (*File) HasDosHeader

func (f *File) HasDosHeader() (bool, error)

HasDosHeader returns true if file has DOS header. If DosHeader is not nil (i.e. DOS header has already been read), true is returned straight away, otherwise first two bytes of a file are read and a result of comparison with ascii 'MZ' is returned instead. An error is returned only if it occured during the read.

func (*File) HasOptHeader

func (f *File) HasOptHeader() (bool, error)

HasOptHeader returns true if OptionalHeader has already been read or it can be read. Note: if FileHeader AND OptionalHeader hasn't been read, an error ErrNoFileHeader is returned.

func (*File) Is64Bit

func (f *File) Is64Bit() (bool, error)

Is64Bit returns true if Machine type of file header equals to AMD64 or IA64 If FileHeader is nil (i.e. wasn't read) an error ErrNoFileHeader is returned.

func (*File) IsPe32Plus

func (f *File) IsPe32Plus() (bool, error)

IsPe32Plus returns true if Magic field of optional header equals to HDR64_MAGIC. If OptionalHeader is nil (i.e. wasn't read) an error ErrNoOptHeader is returned.

func (*File) IsSupportedMachineType

func (f *File) IsSupportedMachineType() (bool, error)

IsSupportedMachineType returns true only if Machine type (in the FileHeader) is fully supported by all the functions in this package. If FileHeader is nil, an error ErrNoFileHeader is returned.

func (*File) IsValidPeSignature

func (f *File) IsValidPeSignature() bool

IsValidPeSignature returns whether file Signature equals to the PE file signature ('PE\0\0').

func (*File) ReadAll

func (f *File) ReadAll() (err error)

ReadAll parses pe/coff file reading all the data of the file into the memory. Returns an error if any occured during the parsing.

func (*File) ReadDataDirBaseRels

func (f *File) ReadDataDirBaseRels() (err error)

ReadDataDirBaseRels reads base relocations data directory of a PE file. OptionalHeader must be read before calling this method, otherwise an error ErrNoOptHeader is returned. Returns an error ErrAlreadyRead, if it has already been read, or an error from ReadAtInto method, if any.

func (*File) ReadDataDirImports

func (f *File) ReadDataDirImports() (err error)

ReadDataDirImports reads import data directory of a PE file. OptionalHeader must be read before calling this method, otherwise an error ErrNoOptHeader is returned. Returns an error ErrAlreadyRead, if it has already been read, or an error from ReadAtInto method, if any.

func (*File) ReadDataDirs

func (f *File) ReadDataDirs() error

ReadDataDirs calls methods which read a

func (*File) ReadDosHeader

func (f *File) ReadDosHeader() error

ReadDosHeader reads DOS header from the file. If DosHeader has already been read an error ErrAlreadyRead is returned.

func (*File) ReadFileHeader

func (f *File) ReadFileHeader() error

ReadFileHeader reads PE/COFF file header. Returns an error ErrAlreadyRead, if it has already been read, or an error from ReadAtInto method, if any.

func (*File) ReadHeaders

func (f *File) ReadHeaders() (err error)

ReadHeaders reads:

  • DosHeader (if it is presented in the file);
  • Signature (if it is presented in the file), and validates it;
  • FileHeader;
  • OptionalHeader (if it is presented);
  • Headers of sections;

Returns error if any

func (*File) ReadOptHeader

func (f *File) ReadOptHeader() error

ReadOptHeader reads an optional header of a PE file. FileHeader must be read before calling this method, otherwise an error ErrNoFileHeader is returned. Returns an error ErrAlreadyRead, if it has already been read, or an error from ReadAtInto method, if any.

func (*File) ReadSectionsHeaders

func (f *File) ReadSectionsHeaders() error

ReadSectionsHeaders reads headers of sections of a PE/COFF file. Returns an error ErrAlreadyRead, if it has already been read, or an error from ReadAtInto method, if any.

func (*File) ReadSectionsLineNumbers

func (f *File) ReadSectionsLineNumbers() error

ReadSectionsLineNumbers reads line numbers of all sections. Headers of sections must be read before calling this method, otherwise an error ErrNoSectionsHeaders is returned. An error is returned if any occured while reading data.

func (*File) ReadSectionsRawData

func (f *File) ReadSectionsRawData() error

ReadSectionsRawData reads contents (raw data) of all sections into memory. Headers of sections must be read before calling this method, otherwise an error ErrNoSectionsHeaders is returned. An error is returned if any occured while reading data.

func (*File) ReadSectionsRelocations

func (f *File) ReadSectionsRelocations() error

ReadSectionsRelocations reads relocations of all sections. Headers of sections must be read before calling this method, otherwise an error ErrNoSectionsHeaders is returned. An error is returned if any occured while reading data.

func (*File) ReadSignature

func (f *File) ReadSignature() error

ReadSignature tries to read a signature ('PE\0\0') pointed by lfanew field of the DosHeader. Returns an error ErrNoDosHeader if DosHeader is not presented, or an error from ReadAtInto method, if any.

func (*File) ReadStringTable

func (f *File) ReadStringTable() error

ReadStringTable reads the whole COFF string table into the memory. FileHeader must be read before calling this method, otherwise an error ErrNoFileHeader is returned. An error is returned if any occured while reading data.

func (*File) ReadStringVa

func (f *File) ReadStringVa(va uint32, maxlen int) (string, error)

ReadStringVa is a wrapper method, which uses VaToOffset to convert virtual address `va` to a file offset and calls ReadStringAt method afterwards. If a call to VaToOffset fails, empty string and an error are returned.

func (*File) ReadSymbols

func (f *File) ReadSymbols() error

ReadSymbols reads all symbols from the symbol table. FileHeader must be read before calling this method, otherwise an error ErrNoFileHeader is returned. An error is returned if any occured while reading data.

func (*File) ReadVaInto

func (f *File) ReadVaInto(p interface{}, va uint32) error

ReadVaInto is a wrapper method, which uses VaToOffset to convert virtual address `va` to a file offset and calls ReadAtInto method afterwards. If a call to VaToOffset fails, an error is returned.

func (*File) Seal

func (f *File) Seal()

Seal eliminates all external pointers (relatively to this package), so a File object can be long-term stored without holding any (useless) resources. For example after calling ReadAll method, and having all the data read from the file.

func (*File) VaToOffset

func (f *File) VaToOffset(va uint32) (int64, error)

VaToOffset returns a file offset which points to data pointed by `va` virtual address

type FileError

type FileError struct {
	// contains filtered or unexported fields
}

FileError represents an internal error which may occur while reading/parsing a PE/COFF file.

func (*FileError) ToMultiError

func (e *FileError) ToMultiError() (list MultiError)

ToMultiError returns a flattened list of errors formed from 'recursive' innerErrors

type Import

type Import struct {
	windef.ImportDescriptor
	// contains filtered or unexported fields
}

Import represents a collection of imported functions, which belong to one library.

func (*Import) Functions

func (i *Import) Functions() []ImportFunc

Functions returns a slice of ImportFunc

func (*Import) Library

func (i *Import) Library() string

Library returns a library name, which has imported functions of the current import.

type ImportFunc

type ImportFunc struct {
	Hint uint16
	Name string
}

ImportFunc represents an import entry inside a PE import data directory, it has two fields:

  • Hint: an index into the export name pointer table. A match is attempted first with this value. If it fails, a binary search is performed on the DLL’s export name pointer table.
  • Name: an ASCII string that contains the name to import. This is the string that must be matched to the public name in the DLL. This string is case sensitive and terminated by a null byte.

type ImportThunk

type ImportThunk interface {
	IsNull() bool
	IsOrdinal() bool

	Ordinal() uint16
	HintRVA() uint32
	NameRVA() uint32

	Size() int64
}

ImportThunk is an interface for 32/64 bit import thunks

type ImportThunk32

type ImportThunk32 uint32

func (ImportThunk32) HintRVA

func (t ImportThunk32) HintRVA() uint32

func (ImportThunk32) IsNull

func (t ImportThunk32) IsNull() bool

func (ImportThunk32) IsOrdinal

func (t ImportThunk32) IsOrdinal() bool

func (ImportThunk32) NameRVA

func (t ImportThunk32) NameRVA() uint32

func (ImportThunk32) Ordinal

func (t ImportThunk32) Ordinal() uint16

func (ImportThunk32) Size

func (t ImportThunk32) Size() int64

type ImportThunk64

type ImportThunk64 uint64

func (ImportThunk64) HintRVA

func (t ImportThunk64) HintRVA() uint32

func (ImportThunk64) IsNull

func (t ImportThunk64) IsNull() bool

func (ImportThunk64) IsOrdinal

func (t ImportThunk64) IsOrdinal() bool

func (ImportThunk64) NameRVA

func (t ImportThunk64) NameRVA() uint32

func (ImportThunk64) Ordinal

func (t ImportThunk64) Ordinal() uint16

func (ImportThunk64) Size

func (t ImportThunk64) Size() int64

type MultiError

type MultiError []error

MultiError represents a collection of errors

func (MultiError) Error

func (e MultiError) Error() string

Error checks count of errors which are stored in the MultiError and returns a string represntation of an error, if:

0 entries   : "" (empty string);
1 entry     : Error() value of the first error;
>=2 entries : Error() values separated with new line character ('\n').

type OptionalHeader

type OptionalHeader struct {
	windef.OptionalHeaderCommon
	DataDirs DataDirs
}

OptionalHeader embedds windef.OptionalHeaderCommon, and stores DataDirs.

func (*OptionalHeader) From32

func (oh *OptionalHeader) From32(oh32 *windef.OptionalHeader32)

From32 sets values of OptionalHeaderCommon from a 32-bit version of an optional header.

func (*OptionalHeader) From64

func (oh *OptionalHeader) From64(oh64 *windef.OptionalHeader64)

From64 sets values of OptionalHeaderCommon from a 64-bit version of an optional header.

type Section

type Section struct {
	windef.SectionHeader
	// contains filtered or unexported fields
}

Section embedds a windef.SectionHeader struct and stores unexported fields of parsed data of a section, such as string represntation of the section name, raw data, and etc...

func (*Section) ID

func (s *Section) ID() int

ID returns a real id of a section inside a PE/COFF file.

func (*Section) NameString

func (s *Section) NameString() string

NameString returns string represntation of a SectionHeader.Name field.

func (*Section) RawData

func (s *Section) RawData() []byte

RawData returns slice of bytes ([]byte) which contains raw data of a section.

func (*Section) Relocations

func (s *Section) Relocations() []windef.Relocation

Relocations returns a slice of relocations of the section.

func (*Section) VaToFileOffset

func (s *Section) VaToFileOffset(va uint32) int64

VaToFileOffset converts virtual address to the file offset.

func (*Section) VaToSectionOffset

func (s *Section) VaToSectionOffset(va uint32) int64

VaToSectionOffset converts virtual address to the offset within section.

type Sections

type Sections struct {
	// contains filtered or unexported fields
}

Sections contains unexpected fields. Implements a sort.Interface, and can be sorted ascending by Section.VirtualAddress.

func (*Sections) Array

func (s *Sections) Array() []*Section

Array returns a slice of (pointers to) sections. Returned slice must not be modified directly!

func (*Sections) GetByID

func (s *Sections) GetByID(id int16) (*Section, error)

GetByID returns a section with specified **1-based** id number. The reason for 1-based indices is that all the sections numbers according to the PE/COFF file specification are 1-based. If an id is outside a valid range, an error ErrSectionNotFound is returned.

func (Sections) GetByVA

func (s Sections) GetByVA(va uint32) (*Section, error)

GetByVA returns a (pointer to) Section, which has specified virtual address in its address range. If no such section exist, nil and an error ErrSectionNotFound are returned.

func (*Sections) Len

func (s *Sections) Len() int

Len returns count of sections This method is required to implement the sort.Interface

func (*Sections) Less

func (s *Sections) Less(i, j int) bool

Less returns true if VirtualAddress of section[i] is less that VirtualAddress of section[j] This method is required to implement the sort.Interface

func (*Sections) Swap

func (s *Sections) Swap(i, j int)

Swap swaps sections This method is required to implement the sort.Interface

type StringTable

type StringTable []byte

StringTable represents a COFF string table. Please note, first four bytes of the string table (uint32 value), represent the size of the string table (including the size value), so strings are stored after the 4th byte in the table.

func (StringTable) GetString

func (t StringTable) GetString(offset int) (string, error)

GetString returns a string which starts at specified offset inside the string table.

type Symbol

type Symbol struct {
	windef.Symbol
	// contains filtered or unexported fields
}

Symbol embedds a windef.Symbol struct and stores unexported fields of parsed data of a symbol.

func (*Symbol) NameString

func (s *Symbol) NameString() string

NameString returns a string represntation of the field `Name`.

type Symbols

type Symbols []*Symbol

Symbols represents a collection of pointers to Symbol objects.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL