[GH-ISSUE #2343] [Bug] MZ new-header signature check strips the high bit, so corrupt bytes read as NE/LX/PE (main CI red) #773

Closed
opened 2026-10-15 18:28:13 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @kaoru0822-kitauji on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2343

Observed behavior

Main CI has failed since c9fed5069 (fix(targets): recognize Windows headers after short DOS stubs). tests/boundary/go/goBinaryProvider.test.ts > rejects high-bit lookalikes of Windows signatures now fails for both cases:

AssertionError: expected Error: Unsupported target for inspect_go_… to be an instance of AnalysisInputError

A PE whose new-header signature bytes are CE C5 or CC D8 (high-bit lookalikes of NE / LX) is reported as an unsupported NE/LX executable, not as a malformed PE.

Reproduced locally on main 1c3791430: npm run test:focused -- tests/boundary/go/goBinaryProvider.test.ts gives 2 failed / 5 passed.

Cause

windowsHeaderSignature in src/domain/dosMz.ts (new in c9fed5069) classifies the signature with bytes.toString("ascii", 0, 2). Node's "ascii" decoder drops the high bit, so 0xCE 0xC5 decodes to "NE" and 0xCC 0xD8 to "LX". The same decoding is used in observeMzWindowsHeader for the "PE" prefix check, so 0xD0 0xC5 passes as "PE". The Go reader previously compared with "latin1", which keeps the byte value.

The function is shared by target resolution (BinaryTargetResolver), artifact inventory (classifyArtifactBytes) and the Go PE reader. All of them therefore misclassify these byte patterns.

Expected behavior

Only the exact bytes 4E 45 / 4C 45 / 4C 58 / 50 45 00 00 are recognized as NE/LE/LX/PE. High-bit lookalikes are treated as an unrecognized ("other") signature, and the existing regression passes again.

Originally created by @kaoru0822-kitauji on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2343 ### Observed behavior Main CI has failed since c9fed5069 (`fix(targets): recognize Windows headers after short DOS stubs`). `tests/boundary/go/goBinaryProvider.test.ts > rejects high-bit lookalikes of Windows signatures` now fails for both cases: ```text AssertionError: expected Error: Unsupported target for inspect_go_… to be an instance of AnalysisInputError ``` A PE whose new-header signature bytes are `CE C5` or `CC D8` (high-bit lookalikes of `NE` / `LX`) is reported as an *unsupported NE/LX executable*, not as a malformed PE. Reproduced locally on main 1c3791430: `npm run test:focused -- tests/boundary/go/goBinaryProvider.test.ts` gives 2 failed / 5 passed. ### Cause `windowsHeaderSignature` in `src/domain/dosMz.ts` (new in c9fed5069) classifies the signature with `bytes.toString("ascii", 0, 2)`. Node's `"ascii"` decoder drops the high bit, so `0xCE 0xC5` decodes to `"NE"` and `0xCC 0xD8` to `"LX"`. The same decoding is used in `observeMzWindowsHeader` for the `"PE"` prefix check, so `0xD0 0xC5` passes as `"PE"`. The Go reader previously compared with `"latin1"`, which keeps the byte value. The function is shared by target resolution (`BinaryTargetResolver`), artifact inventory (`classifyArtifactBytes`) and the Go PE reader. All of them therefore misclassify these byte patterns. ### Expected behavior Only the exact bytes `4E 45` / `4C 45` / `4C 58` / `50 45 00 00` are recognized as NE/LE/LX/PE. High-bit lookalikes are treated as an unrecognized ("other") signature, and the existing regression passes again.
bsakaguchi 2026-10-15 18:28:13 +00:00
Author
Owner

@matbrgz commented on GitHub (Oct 12, 2026):

Root Cause & Follow-up Verification

This issue correctly pinpointed the masking of bit 7 (0x80) when decoding byte slices via Buffer.toString("ascii") in Node.js (which performs a bitwise & 0x7f), converting high-bit lookalikes 0xCE 0xC5 into "NE" and 0xCC 0xD8 into "LX".

  • Direct fix: Commit ac57c88ef corrected windowsHeaderSignature in src/domain/dosMz.ts by using "latin1" decoding (which preserves all 8 bits 1:1 into character codes).
  • Comprehensive coverage across remaining magic checks: PR #2384 (fix(formats): preserve high bits in remaining magic-byte checks) systematically sweeps this across nativeAotPe.ts, WindowsNativeLoader.ts, KeyedArchiveReader.ts, and PNG IHDR validations.

Closing/triaging as resolved by ac57c88ef with remaining pattern sites tracked in PR #2384.

<!-- gh-comment-id:6134222045 --> @matbrgz commented on GitHub (Oct 12, 2026): ### Root Cause & Follow-up Verification This issue correctly pinpointed the masking of bit 7 (`0x80`) when decoding byte slices via `Buffer.toString("ascii")` in Node.js (which performs a bitwise `& 0x7f`), converting high-bit lookalikes `0xCE 0xC5` into `"NE"` and `0xCC 0xD8` into `"LX"`. - **Direct fix:** Commit `ac57c88ef` corrected `windowsHeaderSignature` in `src/domain/dosMz.ts` by using `"latin1"` decoding (which preserves all 8 bits 1:1 into character codes). - **Comprehensive coverage across remaining magic checks:** PR #2384 (`fix(formats): preserve high bits in remaining magic-byte checks`) systematically sweeps this across `nativeAotPe.ts`, `WindowsNativeLoader.ts`, `KeyedArchiveReader.ts`, and PNG `IHDR` validations. Closing/triaging as resolved by `ac57c88ef` with remaining pattern sites tracked in PR #2384.
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Addressed on main in ac57c88ef.

Windows native magic-byte classification rejects high-bit MZ/NE/PE lookalikes.

Validation: 48 focused regressions passed across DOS MZ classification, Go provider, archive comparison and Electron invalid paths; complete static gate passed.

Verification scope: No real Windows runtime run.

<!-- gh-comment-id:6158649538 --> @morluto commented on GitHub (Oct 14, 2026): Addressed on main in [ac57c88ef](https://github.com/morluto/rea/commit/ac57c88ef). Windows native magic-byte classification rejects high-bit MZ/NE/PE lookalikes. Validation: 48 focused regressions passed across DOS MZ classification, Go provider, archive comparison and Electron invalid paths; complete static gate passed. Verification scope: No real Windows runtime run.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#773
No description provided.