Skip to content

docs: record that ImageFileName is truncated by Windows, not by us - #15

Merged
h4x0r merged 2 commits into
mainfrom
docs/imagefilename-truncation
Aug 8, 2026
Merged

docs: record that ImageFileName is truncated by Windows, not by us#15
h4x0r merged 2 commits into
mainfrom
docs/imagefilename-truncation

Conversation

@h4x0r

@h4x0r h4x0r commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

ps reports coreupdater.ex for a process whose executable is
coreupdater.exe, and that reads like a byte-loss bug. It is not — I filed it
as one and had to retract it, so the finding is written down where the next
reader will meet it rather than re-derive it.

_EPROCESS.ImageFileName is UCHAR[15] and the kernel NUL-terminates it,
reserving the final byte, so the field carries at most 14 CHARACTERS. Windows
truncates a longer executable name when populating it, before any tool reads it.

Confirmed in the artifact rather than reasoned from the struct definition. In
the Case-001 dump, for PID 3644:

0x02082cb38 coreupdater.ex\0 inside the _EPROCESS (PID as u64 within +/-0x400)
0x0195086ea coreupdater.exe\0 a different structure, not near that PID

So "read 15, stop at the first NUL" is correct and the short name is the
evidence.

Documented in three places, because each catches a different reader:

  • docs/interpreting-process-names.md — for the examiner reading the output:
    what the short name means, that it is not a reliable identifier for names of
    15+ characters, where the full path actually lives, and why corroboration
    from a filesystem or registry artifact is needed before naming a file.
  • process.rs at the read site, and psscan.rs on decode_image_name — for
    whoever next reads 15 and wonders whether it should be 16.
  • The page is registered in mkdocs nav; an unlisted page is an undiscoverable
    one.

The decode is deliberately unchanged. Rewriting the field to the expected
filename would fabricate evidence: the tool would report a value that is not in
the dump. Fuller names belong as separate, attributed enrichment from
SeAuditProcessCreationInfo.ImageFileName or RTL_USER_PROCESS_PARAMETERS.

Refs #13.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

h4x0r and others added 2 commits August 8, 2026 09:06
`ps` reports `coreupdater.ex` for a process whose executable is
`coreupdater.exe`, and that reads like a byte-loss bug. It is not — I filed it
as one and had to retract it, so the finding is written down where the next
reader will meet it rather than re-derive it.

`_EPROCESS.ImageFileName` is `UCHAR[15]` and the kernel NUL-terminates it,
reserving the final byte, so the field carries at most 14 CHARACTERS. Windows
truncates a longer executable name when populating it, before any tool reads it.

Confirmed in the artifact rather than reasoned from the struct definition. In
the Case-001 dump, for PID 3644:

  0x02082cb38  coreupdater.ex\0    inside the _EPROCESS (PID as u64 within +/-0x400)
  0x0195086ea  coreupdater.exe\0   a different structure, not near that PID

So "read 15, stop at the first NUL" is correct and the short name is the
evidence.

Documented in three places, because each catches a different reader:

  * docs/interpreting-process-names.md — for the examiner reading the output:
    what the short name means, that it is not a reliable identifier for names of
    15+ characters, where the full path actually lives, and why corroboration
    from a filesystem or registry artifact is needed before naming a file.
  * process.rs at the read site, and psscan.rs on decode_image_name — for
    whoever next reads `15` and wonders whether it should be 16.
  * The page is registered in mkdocs nav; an unlisted page is an undiscoverable
    one.

The decode is deliberately unchanged. Rewriting the field to the expected
filename would fabricate evidence: the tool would report a value that is not in
the dump. Fuller names belong as separate, attributed enrichment from
SeAuditProcessCreationInfo.ImageFileName or RTL_USER_PROCESS_PARAMETERS.

Refs #13.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow-up to the previous commit. Truncation is lossy, so the consequence is
sharper than "the name may be short": distinct executables collide in this field.

  MicrosoftEdgeUpdate.exe       (23)  ->  MicrosoftEdgeU
  MicrosoftEdgeUpdateCore.exe   (27)  ->  MicrosoftEdgeU
  coreupdaterupdater.exe        (22)  ->  coreupdaterupd
  coreupdaterupdater2.exe       (23)  ->  coreupdaterupd

The first pair is not contrived -- two real, separately signed Microsoft
binaries that _EPROCESS.ImageFileName cannot tell apart.

Two things follow, and both are worse than a cosmetic truncation:

  * The stored value often does not look like a filename at all.
    `MicrosoftEdgeU` has lost its extension, so an examiner who does not know
    the 14-byte limit gets no cue that anything was cut. `coreupdater.ex` at
    least hints at it via the mangled `.ex`.

  * It is a masquerading vector. Naming a binary so its first 14 characters
    match a legitimate process yields an identical ImageFileName, and a process
    list alone cannot separate them. No trickery is needed beyond a long enough
    name.

Documented as a collision table in docs/interpreting-process-names.md with the
practical rule -- a stored name of exactly 14 characters is the tell that
truncation may have occurred; treat it as a prefix and resolve against the full
path or a filesystem artifact before attributing behaviour to a named program.

The same point is noted on psscan's decode_image_name, where a caller is most
likely to treat the returned name as identifying a specific executable.

fmt clean, clippy -D warnings clean. Refs #13.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@h4x0r
h4x0r merged commit 81f0322 into main Aug 8, 2026
27 checks passed
@h4x0r
h4x0r deleted the docs/imagefilename-truncation branch August 8, 2026 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant