QL-Win/QuickLook · error · PEImageParseException

DOS header not found.

Error message

DOS header not found.

What it means

Thrown after reading the first UInt16 when it is not 0x5a4d (little-endian 'MZ'). Every DOS/PE executable begins with the 'MZ' mark, so a mismatch means the file is not a Microsoft executable despite being at least 2 bytes. PEImageParseException(0, ...) records the error at offset 0.

Source

Thrown at QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs:52

    /// <summary>
    /// Gets the optional header of this PE image file.
    /// </summary>
    public ImageOptionalHeader OptionalHeader { get; private set; }

    /// <summary>
    /// Gets the collection of section headers and data of this PE image file.
    /// </summary>
    public ImageSection[] Sections { get; private set; }

    private PEImage(byte[] originalImage)
    {
        OriginalImage = originalImage;

        using BinaryReader reader = new(new MemoryStream(OriginalImage));

        // MZ
        if (reader.BaseStream.Length < 2) throw new PEImageParseException(0, "DOS signature not found.");
        if (reader.ReadUInt16() != 0x5a4d) throw new PEImageParseException(0, "DOS header not found.");

        // DOS Header
        if (reader.BaseStream.Length - reader.BaseStream.Position < 64) throw new PEImageParseException((int)reader.BaseStream.Position, "DOS header incomplete.");

        DosHeader = new()
        {
            LastPageSize = reader.ReadUInt16(),
            PageCount = reader.ReadUInt16(),
            RelocationCount = reader.ReadUInt16(),
            HeaderSize = reader.ReadUInt16(),
            MinAlloc = reader.ReadUInt16(),
            MaxAlloc = reader.ReadUInt16(),
            InitialSS = reader.ReadUInt16(),
            InitialSP = reader.ReadUInt16(),
            Checksum = reader.ReadUInt16(),
            InitialIP = reader.ReadUInt16(),
            InitialCS = reader.ReadUInt16(),
            RelocationOffset = reader.ReadUInt16(),

View on GitHub (pinned to cb5d9c429c)

Solutions

  1. Sniff the first 2 bytes for 'MZ' (0x5A4D) before constructing PEImage.
  2. Use TryCanHandle-style detection so non-PE files never reach the parser.
  3. Catch PEImageParseException and show 'not a valid PE/EXE' instead of crashing.
  4. Route ELF/Mach-O files to the correct viewer.

Example fix

// before
if (reader.ReadUInt16() != 0x5a4d) throw new PEImageParseException(0, "DOS header not found.");

// after — caller-side magic check
using var fs = File.OpenRead(path);
var b0 = fs.ReadByte(); var b1 = fs.ReadByte();
if (b0 != 0x4D || b1 != 0x5A) return null; // not 'MZ'
Defensive patterns

Strategy: validation

Validate before calling

using var fs = File.OpenRead(path);
int b0 = fs.ReadByte(), b1 = fs.ReadByte();
if (b0 != 0x4D || b1 != 0x5A) return; // not 'MZ'

Type guard

static bool HasMzMagic(byte[] head) => head.Length >= 2 && head[0]==0x4D && head[1]==0x5A;

Try / catch

try { var img = PEImage.FromFile(path); }
catch (PEImageParseException ex) when (ex.Message.Contains("DOS header not found")) { /* not an executable */ }

Prevention

When it happens

Trigger: Constructing PEImage from a byte array whose first two bytes are not 0x4D 0x5A — e.g. an ELF Mach-O, a text/script file, a .NET assembly's raw IL dump, or arbitrary data misnamed .exe.

Common situations: Previewing a non-PE file whose extension routed it to PEViewer; an installer stub that is actually an SFX container with a non-standard preamble; cross-platform binaries (ELF/Mach-O) opened on Windows.

Related errors


AI-assisted analysis of QL-Win/QuickLook@cb5d9c429c (2026-08-13). Data as JSON: /api/errors/2650b31f8dd77857. Report an issue: GitHub.