Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+79
-38
@@ -13,6 +13,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/bits"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -83,10 +84,14 @@ func (s *SectionHeader) NameString() string {
|
||||
return string(s.Name[:])
|
||||
}
|
||||
|
||||
type peReader interface {
|
||||
io.Closer
|
||||
type peReaderBase interface {
|
||||
io.ReaderAt
|
||||
io.ReadSeeker
|
||||
}
|
||||
|
||||
type peReader interface {
|
||||
peReaderBase
|
||||
io.Closer
|
||||
Base() uintptr
|
||||
Limit() uintptr
|
||||
}
|
||||
@@ -136,7 +141,7 @@ func checkMagic(oh OptionalHeader, machine uint16) bool {
|
||||
case dpe.IMAGE_FILE_MACHINE_AMD64, dpe.IMAGE_FILE_MACHINE_ARM64:
|
||||
expectedMagic = 0x020B
|
||||
default:
|
||||
panic("unsupported machine")
|
||||
panic(fmt.Sprintf("unsupported machine 0x%04X", machine))
|
||||
}
|
||||
|
||||
return oh.GetMagic() == expectedMagic
|
||||
@@ -147,22 +152,32 @@ type peBounds struct {
|
||||
limit uintptr
|
||||
}
|
||||
|
||||
func (peb *peBounds) Base() uintptr {
|
||||
return peb.base
|
||||
}
|
||||
|
||||
func (peb *peBounds) Limit() uintptr {
|
||||
return peb.limit
|
||||
}
|
||||
|
||||
type peFile struct {
|
||||
*os.File
|
||||
peReaderBase
|
||||
peBounds
|
||||
}
|
||||
|
||||
func (pef *peFile) Base() uintptr {
|
||||
return pef.base
|
||||
}
|
||||
func (pef *peFile) Close() error {
|
||||
if pef.peReaderBase == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pef *peFile) Limit() uintptr {
|
||||
if pef.limit == 0 {
|
||||
if fi, err := pef.Stat(); err == nil {
|
||||
pef.limit = uintptr(fi.Size())
|
||||
if cl, ok := pef.peReaderBase.(io.Closer); ok {
|
||||
if err := cl.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return pef.limit
|
||||
|
||||
pef.peReaderBase = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
type peModule struct {
|
||||
@@ -171,14 +186,6 @@ type peModule struct {
|
||||
modLock uintptr
|
||||
}
|
||||
|
||||
func (pei *peModule) Base() uintptr {
|
||||
return pei.base
|
||||
}
|
||||
|
||||
func (pei *peModule) Limit() uintptr {
|
||||
return pei.limit
|
||||
}
|
||||
|
||||
// NewPEFromFileName opens a PE binary located at filename and parses its PE
|
||||
// headers. Upon success it returns a non-nil *PEHeaders, otherwise it returns a
|
||||
// nil *PEHeaders and a non-nil error.
|
||||
@@ -193,8 +200,18 @@ func NewPEFromFileName(filename string) (*PEHeaders, error) {
|
||||
}
|
||||
|
||||
func newPEFromFile(f *os.File) (*PEHeaders, error) {
|
||||
// peBounds base is 0, limit is loaded lazily
|
||||
pef := &peFile{File: f}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newPEFromReaderBase(f, uintptr(fi.Size()))
|
||||
}
|
||||
|
||||
func newPEFromReaderBase(rb peReaderBase, size uintptr) (*PEHeaders, error) {
|
||||
// peBounds base is 0, limit is size
|
||||
pef := &peFile{peReaderBase: rb, peBounds: peBounds{limit: size}}
|
||||
peh, err := loadHeaders(pef)
|
||||
if err != nil {
|
||||
pef.Close()
|
||||
@@ -204,6 +221,15 @@ func newPEFromFile(f *os.File) (*PEHeaders, error) {
|
||||
return peh, nil
|
||||
}
|
||||
|
||||
// NewPEFromBlob parses the headers from contents of a PE file stored in blob.
|
||||
// The blob must contain the contents of a file, not a module. Upon success it
|
||||
// returns a non-nil *PEHeaders, otherwise it returns a nil *PEHeaders and a
|
||||
// non-nil error.
|
||||
// Call Close() on the returned *PEHeaders when it is no longer needed.
|
||||
func NewPEFromBlob(blob []byte) (*PEHeaders, error) {
|
||||
return newPEFromReaderBase(bytes.NewReader(blob), uintptr(len(blob)))
|
||||
}
|
||||
|
||||
// Close frees any resources that were opened when peh was created.
|
||||
func (peh *PEHeaders) Close() error {
|
||||
return peh.r.Close()
|
||||
@@ -213,17 +239,20 @@ type rvaType interface {
|
||||
~int8 | ~int16 | ~int32 | ~uint8 | ~uint16 | ~uint32
|
||||
}
|
||||
|
||||
// addOffset ensures that, if off is negative, it does not underflow base.
|
||||
func addOffset[O rvaType](base uintptr, off O) uintptr {
|
||||
// addOffset ensures that off neither overflows nor underflows base.
|
||||
func addOffset[O rvaType](base uintptr, off O) (addr uintptr, ok bool) {
|
||||
if off >= 0 {
|
||||
return base + uintptr(off)
|
||||
if upoff := uintptr(off); upoff <= (math.MaxUint - base) {
|
||||
return base + upoff, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
negation := uintptr(-off)
|
||||
if negation >= base {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
return base - negation
|
||||
return base - negation, true
|
||||
}
|
||||
|
||||
func binaryRead(r io.Reader, data any) (err error) {
|
||||
@@ -254,9 +283,12 @@ func readStruct[T any, R rvaType](r peReader, rva R) (*T, error) {
|
||||
|
||||
return result, nil
|
||||
case *peModule:
|
||||
addr := addOffset(r.Base(), rva)
|
||||
szT := unsafe.Sizeof(*((*T)(nil)))
|
||||
if addr+szT >= v.Limit() {
|
||||
addr, ok := addOffset(r.Base(), rva)
|
||||
if !ok {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
szT := uint32(unsafe.Sizeof(*((*T)(nil))))
|
||||
if addr2, ok := addOffset(addr, szT); !ok || addr2 >= v.Limit() {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
|
||||
@@ -285,9 +317,12 @@ func readStructArray[T any, R rvaType](r peReader, rva R, count int) ([]T, error
|
||||
|
||||
return result, nil
|
||||
case *peModule:
|
||||
addr := addOffset(r.Base(), rva)
|
||||
szT := reflect.ArrayOf(count, reflect.TypeOf((*T)(nil)).Elem()).Size()
|
||||
if addr+szT >= v.Limit() {
|
||||
addr, ok := addOffset(r.Base(), rva)
|
||||
if !ok {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
szT := uint32(reflect.ArrayOf(count, reflect.TypeFor[T]()).Size())
|
||||
if addr2, ok := addOffset(addr, szT); !ok || addr2 >= v.Limit() {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
|
||||
@@ -330,7 +365,7 @@ func loadHeaders(r peReader) (*PEHeaders, error) {
|
||||
if e_lfanew <= 0 {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
if addOffset(r.Base(), e_lfanew) >= r.Limit() {
|
||||
if addr, ok := addOffset(r.Base(), e_lfanew); !ok || addr >= r.Limit() {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
|
||||
@@ -352,7 +387,7 @@ func loadHeaders(r peReader) (*PEHeaders, error) {
|
||||
|
||||
// Read the file header
|
||||
fileHeaderOffset := uint32(e_lfanew) + uint32(unsafe.Sizeof(pe))
|
||||
if r.Base()+uintptr(fileHeaderOffset) >= r.Limit() {
|
||||
if addr, ok := addOffset(r.Base(), fileHeaderOffset); !ok || addr >= r.Limit() {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
|
||||
@@ -368,7 +403,7 @@ func loadHeaders(r peReader) (*PEHeaders, error) {
|
||||
|
||||
// Read the optional header
|
||||
optionalHeaderOffset := uint32(fileHeaderOffset) + uint32(unsafe.Sizeof(*fileHeader))
|
||||
if r.Base()+uintptr(optionalHeaderOffset) >= r.Limit() {
|
||||
if addr, ok := addOffset(r.Base(), optionalHeaderOffset); !ok || addr >= r.Limit() {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
|
||||
@@ -402,7 +437,7 @@ func loadHeaders(r peReader) (*PEHeaders, error) {
|
||||
|
||||
// Read in the section table
|
||||
sectionTableOffset := optionalHeaderOffset + uint32(fileHeader.SizeOfOptionalHeader)
|
||||
if r.Base()+uintptr(sectionTableOffset) >= r.Limit() {
|
||||
if addr, ok := addOffset(r.Base(), sectionTableOffset); !ok || addr >= r.Limit() {
|
||||
return nil, ErrInvalidBinary
|
||||
}
|
||||
|
||||
@@ -474,6 +509,8 @@ const (
|
||||
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = DataDirectoryIndex(dpe.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
|
||||
)
|
||||
|
||||
const _IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
|
||||
|
||||
// DataDirectoryEntry returns information from nfo's data directory at index idx.
|
||||
// The type of the return value depends on the value of idx. Most values for idx
|
||||
// currently return the DataDirectoryEntry itself, however it will return more
|
||||
@@ -486,9 +523,13 @@ const (
|
||||
// sophisticated return values, so be careful to structure your type assertions
|
||||
// accordingly.
|
||||
func (nfo *PEHeaders) DataDirectoryEntry(idx DataDirectoryIndex) (any, error) {
|
||||
if ii := int(idx); ii < 0 || ii >= _IMAGE_NUMBEROF_DIRECTORY_ENTRIES {
|
||||
return nil, ErrIndexOutOfRange
|
||||
}
|
||||
|
||||
dd := nfo.optionalHeader.GetDataDirectory()
|
||||
if int(idx) >= len(dd) {
|
||||
return nil, ErrIndexOutOfRange
|
||||
return nil, ErrNotPresent
|
||||
}
|
||||
|
||||
dde := dd[idx]
|
||||
|
||||
Reference in new issue
Block a user