92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
|
package pe
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
// ErrBadMZSignature is returned when the MZ signature is invalid.
|
||
|
ErrBadMZSignature = errors.New("mz: bad signature")
|
||
|
|
||
|
// ErrBadPESignature is returned when the PE signature is invalid.
|
||
|
ErrBadPESignature = errors.New("pe: bad signature")
|
||
|
|
||
|
// ErrUnknownOptionalHeaderMagic is returned when the optional header
|
||
|
// magic field has an unknown value.
|
||
|
ErrUnknownOptionalHeaderMagic = errors.New("pe: unknown optional header magic")
|
||
|
)
|
||
|
|
||
|
// Module contains a parsed and loaded PE file.
|
||
|
type Module struct {
|
||
|
IsPE64 bool
|
||
|
DOSHeader ImageDOSHeader
|
||
|
Header ImageNTHeaders64
|
||
|
Sections []ImageSectionHeader
|
||
|
}
|
||
|
|
||
|
// LoadModule loads a PE module into memory.
|
||
|
func LoadModule(r io.ReadSeeker) (*Module, error) {
|
||
|
m := &Module{}
|
||
|
|
||
|
r.Seek(0, io.SeekStart)
|
||
|
dos := ImageDOSHeader{}
|
||
|
if err := binary.Read(r, binary.LittleEndian, &dos); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if dos.Signature != MZSignature {
|
||
|
return nil, ErrBadMZSignature
|
||
|
}
|
||
|
m.DOSHeader = dos
|
||
|
|
||
|
r.Seek(int64(dos.NewHeaderAddr), io.SeekStart)
|
||
|
pesig := [4]byte{}
|
||
|
if err := binary.Read(r, binary.LittleEndian, &pesig); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if pesig != PESignature {
|
||
|
return nil, ErrBadPESignature
|
||
|
}
|
||
|
|
||
|
optmagic := uint16(0)
|
||
|
r.Seek(int64(dos.NewHeaderAddr)+OffsetOfOptionalHeaderFromNTHeader, io.SeekStart)
|
||
|
if err := binary.Read(r, binary.LittleEndian, &optmagic); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
r.Seek(int64(dos.NewHeaderAddr), io.SeekStart)
|
||
|
switch optmagic {
|
||
|
case ImageNTOptionalHeader32Magic:
|
||
|
m.IsPE64 = false
|
||
|
nt := ImageNTHeaders32{}
|
||
|
if err := binary.Read(r, binary.LittleEndian, &nt); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
m.Header = nt.To64()
|
||
|
case ImageNTOptionalHeader64Magic:
|
||
|
m.IsPE64 = true
|
||
|
nt := ImageNTHeaders64{}
|
||
|
if err := binary.Read(r, binary.LittleEndian, &nt); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
m.Header = nt
|
||
|
default:
|
||
|
return nil, ErrUnknownOptionalHeaderMagic
|
||
|
}
|
||
|
|
||
|
// Seek past end of optional headers.
|
||
|
r.Seek(int64(dos.NewHeaderAddr)+OffsetOfOptionalHeaderFromNTHeader+int64(m.Header.FileHeader.SizeOfOptionalHeader), io.SeekStart)
|
||
|
|
||
|
for i := uint16(0); i < m.Header.FileHeader.NumberOfSections; i++ {
|
||
|
section := ImageSectionHeader{}
|
||
|
if err := binary.Read(r, binary.LittleEndian, §ion); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
m.Sections = append(m.Sections, section)
|
||
|
}
|
||
|
|
||
|
return m, nil
|
||
|
}
|