Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion file.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ func NewPE(reader io.ReaderAt) (*PE, error) {
// DOS Stub.
peHeaderOffset := int64(dosHeader.Data.Lfanew)
dosStubSize := peHeaderOffset - offset
p.DOSStub = NewSegment(reader, &offset, dosStubSize)
if dosStubSize > 0 {
p.DOSStub = NewSegment(reader, &offset, dosStubSize)
} else {
// Degenerate case: Lfanew points before or at the end of the DOS header.
offset = peHeaderOffset
}

// PE Signature.
p.PESignature, err = NewHeader[PESignature](reader, &offset)
Expand Down
21 changes: 20 additions & 1 deletion file_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package pego

import (
"bytes"
"debug/pe"
"encoding/binary"
"io"
"testing"

Expand Down Expand Up @@ -39,7 +41,24 @@ func TestFileReadExe(t *testing.T) {
assert.Assert(t, p.OptionalHeader64 == nil)
}

// TestFileReadTruncated verifies that NewPE returns an error when the input is truncated at various points.
func TestFileOverlappingHeaders(t *testing.T) {
// Minimal EXE where the PE structure starts inside the DOS header area (Lfanew = 4).
// This is a degenerate but valid technique used by size-optimized executables.
// The DOS stub should be absent since Lfanew points before the end of the DOS header.
data := make([]byte, 64)
binary.LittleEndian.PutUint16(data[0:], DOSHeaderMagic) // MZ magic.
binary.LittleEndian.PutUint32(data[4:], uint32(PESignatureMagic)) // PE signature at offset 4.
binary.LittleEndian.PutUint16(data[8:], pe.IMAGE_FILE_MACHINE_AMD64) // COFF machine type.
binary.LittleEndian.PutUint32(data[60:], 0x04) // Lfanew = 4 (inside DOS header).

p, err := NewPE(bytes.NewReader(data))
assert.NilError(t, err)
assert.Assert(t, p.DOSHeader != nil)
assert.Assert(t, p.DOSStub == nil) // No stub since Lfanew points inside the DOS header.
assert.Assert(t, p.PESignature != nil)
assert.Equal(t, p.COFFHeader.Data.Machine, uint16(pe.IMAGE_FILE_MACHINE_AMD64))
}

func TestFileReadTruncated(t *testing.T) {
tests := []struct {
name string
Expand Down