{"record":{"id":"31a8463c2a042c9c","repo":"QL-Win/QuickLook","slug":"section-headers-incomplete","errorCode":null,"errorMessage":"Section headers incomplete.","messagePattern":"Section headers incomplete\\.","errorType":"exception","errorClass":"PEImageParseException","httpStatus":null,"severity":"error","filePath":"QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs","lineNumber":203,"sourceCode":"                NumberOfRvaAndSizes = reader.ReadUInt32()\n            };\n        }\n        else if (magic == 0x107)\n        {\n            throw new PEImageParseException((int)reader.BaseStream.Position - 2, \"Optional header for ROM's is not supported.\");\n        }\n        else\n        {\n            throw new PEImageParseException((int)reader.BaseStream.Position - 2, \"Optional header magic value of '0x\" + magic.ToString(\"x4\") + \"' unknown.\");\n        }\n\n        // Data Directories\n        if (reader.BaseStream.Length - reader.BaseStream.Position < OptionalHeader.NumberOfRvaAndSizes * 8) throw new PEImageParseException((int)reader.BaseStream.Position, \"Data directories incomplete.\");\n\n        OptionalHeader.DataDirectories = Create.Array((int)OptionalHeader.NumberOfRvaAndSizes, i => new ImageDataDirectory((ImageDataDirectoryName)i, reader.ReadUInt32(), reader.ReadUInt32()));\n\n        // Section Headers\n        if (reader.BaseStream.Length - reader.BaseStream.Position < CoffHeader.NumberOfSections * 40) throw new PEImageParseException((int)reader.BaseStream.Position, \"Section headers incomplete.\");\n\n        Sections = Create\n            .Enumerable(CoffHeader.NumberOfSections, i => new ImageSectionHeader\n            {\n                Name = reader.ReadBytes(8).TakeWhile(c => c != 0).ToArray().ToUTF8String(),\n                VirtualSize = reader.ReadUInt32(),\n                VirtualAddress = reader.ReadUInt32(),\n                SizeOfRawData = reader.ReadUInt32(),\n                PointerToRawData = reader.ReadUInt32(),\n                PointerToRelocations = reader.ReadUInt32(),\n                PointerToLineNumbers = reader.ReadUInt32(),\n                NumberOfRelocations = reader.ReadUInt16(),\n                NumberOfLineNumbers = reader.ReadUInt16(),\n                Characteristics = (ImageSectionFlags)reader.ReadUInt32()\n            })\n            .Select(header =>\n            {\n                return new ImageSection(header);","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/QL-Win/QuickLook/blob/cb5d9c429c81d9796fac469da2a68efb5626946d/QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs#L185-L221","documentation":"After the data directory table, the PE format stores a section header table consisting of NumberOfSections entries (from the COFF header), each exactly 40 bytes. The parser checks that NumberOfSections * 40 bytes remain; if not, the section header table is incomplete and section names, virtual addresses, and raw data pointers cannot be read.","triggerScenarios":"CoffHeader.NumberOfSections multiplied by 40 exceeds the remaining bytes in the stream. This happens when NumberOfSections is corrupted to an abnormally large value, or when the file is physically truncated before all section headers are present.","commonSituations":"A corrupted NumberOfSections field in the COFF header (byte damage causing it to be much larger than the actual section count); a file truncated between the data directories and the end of the section header table; a malformed binary from an obfuscator or packer.","solutions":["Use a PE viewer to verify NumberOfSections in the COFF header matches the actual number of sections present","Re-download the file and verify its integrity","Pre-validate by reading NumberOfSections from the COFF header and checking that PEHeaderOffset + 4 + 20 + optionalHeaderSize + dataDirectorySize + NumberOfSections * 40 does not exceed the file length","Wrap the parse call in try-catch(PEImageParseException) to handle malformed PE files gracefully"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Sanity-check NumberOfSections against remaining file size\nstatic bool HasValidSectionCount(string path)\n{\n    byte[] b = File.ReadAllBytes(path);\n    if (b.Length < 0x40) return false;\n    int peOff = BitConverter.ToInt32(b, 0x3C);\n    int coffOff = peOff + 4;\n    if (coffOff + 20 > b.Length) return false;\n    // NumberOfSections is at COFF offset + 2 (2 bytes)\n    ushort numSections = BitConverter.ToUInt16(b, coffOff + 2);\n    // Each section header is 40 bytes; typical executables have < 20 sections\n    return numSections > 0 && numSections <= 96\n        && (long)b.Length >= (long)coffOff + 20 + (long)numSections * 40;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var image = PEImage.FromFile(path);\n}\ncatch (PEImageParseException ex) when (ex.Message.Contains(\"Section headers\"))\n{\n    // NumberOfSections is corrupt or file is truncated before section headers\n    logger.Warn($\"Corrupt section header table: {ex.Message} at offset {ex.Offset}\");\n}","preventionTips":["Sanity-check NumberOfSections before full parsing — typical executables have fewer than 20 sections; a value in the thousands indicates corruption","Verify that file length accommodates NumberOfSections * 40 bytes after the headers","Verify file integrity via hash when processing untrusted PE binaries"],"tags":["pe-format","binary-parsing","truncated-file","corrupted-file","section-headers"],"backgroundTag":null,"analyzedSha":"cb5d9c429c81d9796fac469da2a68efb5626946d","analyzedAt":"2026-08-13T11:51:01.370Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}