Advance the symbol cursor in the Weak Externals aux handler - #228
Open
arpitjain099 wants to merge 1 commit into
Open
arpitjain099 wants to merge 1 commit into
arpitjain099 wants to merge 1 commit into
Conversation
Every COFF auxiliary record is SYMTAB_RECORD_LEN, 18 bytes. Four of the five format handlers advance offset by exactly that. Format 3 advances it by 10, because the two readDword calls are issued against the same offset with no advance between or after them: f1 Function Definitions 4 + 4 + 4 + 6 = 18 f2 .bf and .ef 4 + 2 + 6 + 6 = 18 f3 Weak Externals 0 + 0 + 10 = 10 f4 Files 18 = 18 f5 Section Definitions 4 + 2 + 2 + 4 + 2 + 1 + 3 = 18 Two consequences in six lines. The cursor desynchronizes by 8 bytes for the rest of that symbol's auxiliary records, and characteristics is loaded from the tagIndex slot so it can never differ from tagIndex. The comment "// Read line number" above the tagIndex read is copy-paste from the Format 2 handler. This branch is rarely exercised: getSymbolTable returns immediately when PointerToSymbolTable is 0, which is the case for every normally linked PE image, and none of the 219 corkami seeds reaches it with a well-formed table. Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
arpitjain099
requested review from
ekilmer and
gsutherland-trailofbits
as code owners
September 13, 2026 17:46
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every COFF auxiliary record is
SYMTAB_RECORD_LEN, 18 bytes. Four of the five format handlers advanceoffsetby exactly that. Format 3 advances it by 10, because the tworeadDwordcalls are issued against the sameoffsetwith no advance between or after them:Counting the siblings, each of which comes to 18: Function Definitions is 4+4+4+6,
.bf/.efis 4+2+6+6, Files is a single 18, Section Definitions is 4+2+2+4+2+1+3. Weak Externals is 0+0+10.So there are two defects in six lines. The cursor desynchronizes by 8 bytes for the remainder of that symbol's auxiliary records, and
characteristicsis loaded from thetagIndexslot, so it can never hold anything but a second copy oftagIndex. The// Read line numbercomment above the first read is copy-paste from the Format 2 handler.Why it has not been caught:
getSymbolTablereturns immediately whenFileHeader.PointerToSymbolTable == 0, which is true of every normally linked PE image, so the whole symbol parser is dead code for ordinary input. Of the 219 valid seeds in the corkami corpus, 12 have a nonzero pointer and all 12 carry a garbage value that fails the firstreadQwordand aborts the parse before reaching any auxiliary branch.Verification uses the project's own diagnostic. Built at
9e4e358with-DPEPARSE_LIBRARY_WARNINGS=ON, which enables theoffset != nextSymbolOffsetcheck, and crafted a PE from stocktests/assets/example.exewith a 10-record symbol table appended andPointerToSymbolTable/NumberOfSymbolspatched to point at it. It holds one symbol of each of the five auxiliary formats, each withnumberOfAuxSymbols = 1, so a correct parser walks a uniform 36-byte stride and says nothing.One warning for one of the five symbols, and the arithmetic pins it to the weak external: the record header ends at
0x1d25a,0x1d25a + 10 = 0x1d264is the reported current,0x1d25a + 18 = 0x1d26cis the expected, and the 8-byte gap is exactly the two missing advances. The other four formats are silent on both sides, which is the control: the warning path works and does not fire for them.dump-peon the stockexample.exeis unchanged.