[AUTOMATED] fix(p4): win32-process-enumeration-loses — a callee-body walk with no path terminator proves nothing - #444
Merged
Conversation
…walk with no path terminator proves nothing `calleedeadarg` deletes a call argument when the callee's own body is shown to overwrite that register before reading it. The test is "the register is written before EVERY path terminator", which over an empty terminator list holds vacuously — for every register at once. A PE import lands there: its entry address is the IAT slot, so the walk decodes a pointer as instructions, and a slot starting `F4` is `hlt`, whose p-code branches to itself. Reduced to a 2560-byte PE fixture built here byte by byte; the acceptance probe of the need is promoted verbatim against it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
The problem
calleedeadargdrops an argument when the callee's body proves the calleeoverwrites that register before reading it. On a PE import the "callee body" is
the IAT slot, so the walk decodes a pointer as instructions — and when that
decode never reaches a path terminator, the proof it hands back is vacuous and
the argument disappears.
Build the fixture this PR adds and decompile its entry:
The snapshot handle is in RCX at both calls and in the disassembly, and
--option calleedeadarg offprints it. Same shape on the crackme this camefrom (crackmes.one
640a526833c5d447bc761899,sub_1400015c0), whereProcess32FirstWkeeps both its arguments in the same run.The fix
The pass's test is "the register is written before every terminator", which
is a conjunction — over an empty list it holds for every register at once.
already visited: a body that is one endless loop, and an IAT slot whose first
byte decodes to
HLT, whose p-code branches to itself.proves_dead, not in the walk: the walk really did coverevery path with nothing abandoned, so
completestays honest and only theclaim built on it is withheld.
The tests
tests/cli/win32-process-enumeration-loses.json(promoted acceptance probe) plusa unit test pinning both directions — no terminator proves nothing, one
terminator that wrote RCX still proves it dead. Gates:
make test675/675PARITY OK,
make test-stages635/635 PARITY OK,make test-cli40/40,make rust-testgreen,make check-specgreen,catalog OK. A pre/postdecompile-allsweep over 160 binaries and 15,048 functions (107 in-repofixtures plus 53 RE crackmes) moved exactly one: the witness itself.
🤖 Generated with Claude Code
Before / after —
sub_1400015c0inKeyCheker.exeReal captured kuna output on the function this feature was built for, with
option Noneflipped. Ported from kuna.None off(default)None onkuna — before (
option None off)kuna — after (
option None on)kuna reference (the goal, v9.2.223)