[PR #1678] [MERGED] fix(native): bound PE resource RVAs by section virtual size #4747

Closed
opened 2026-10-31 00:54:38 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1678
Author: @kaoru0822-kitauji
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/pe-resources-virtual-size


📝 Commits (2)

  • f2d3eb7 fix(native): bound PE resource RVAs by section virtual size
  • 13ab289 Merge remote-tracking branch 'origin/main' into fix/pe-resources-virtual-size

📊 Changes

2 files changed (+70 additions, -5 deletions)

View changed files

📝 src/native/pe/PeResourceLayout.ts (+11 -5)
📝 src/native/pe/PeResourceParser.test.ts (+59 -0)

📄 Description

Summary

#1596 found that managed RVA reads treated a section as max(VirtualSize, SizeOfRawData) bytes, and 975dff2e2 fixed that in ManagedPeReader. The PE resource reader that #1482 added has the same mapping in src/native/pe/PeResourceLayout.ts, so inspect_pe_resources still shows both symptoms on main:

  • Payload from padding. A resource data entry whose RVA lies in the raw alignment padding past VirtualSize is reported with a status of complete, a file range and a SHA-256 of bytes the image loader never maps.
  • Shadowed later section. A section whose virtual range starts inside an earlier section's raw padding is refused with "Resource RVA has missing or overlapping section mappings", although only one section virtually contains the RVA.

Change

Containment, header-overlap and section-overlap checks now use the loader's virtual extent: VirtualSize, or SizeOfRawData when VirtualSize is 0. A range that starts inside a section but runs past its virtual extent fails with "Resource range leaves its section's virtual size." The existing file-backed requirement is unchanged.

One deliberate difference from the managed fix: for VirtualSize == 0, the managed reader addresses no RVA, matching System.Reflection.Metadata's PEReader. Native resources are read from the image the Windows loader maps, and that loader uses SizeOfRawData when VirtualSize is zero. Old linkers and packers emit such sections, so they keep working here.

src/domain/native/nativeAotPe.ts uses the same max(...) extent in read() and virtualBytesRemaining(). I left it unchanged because its claims need NativeAOT fixture verification that I can't run here.

Verification

  • src/native/pe/PeResourceParser.test.ts has four new cases: a payload starting in padding, a payload straddling VirtualSize, VirtualSize 0 still mapping the section, and a later section inside earlier padding resolving to its own file bytes. The padding and later-section cases (3) fail against main's PeResourceLayout.ts. The VirtualSize 0 case passes on both and guards the loader rule.
  • npm run test:focused -- src/native/pe/PeResourceParser.test.ts tests/boundary/filesystem/peResources.test.ts: passed. npm run typecheck passes.
  • Real PE files on this Mac (Tabby's clink x64/x86/arm64 DLLs, XLD's tak_deco_lib.dll, TeX Live's wtestopenfiles.exe): inspect-pe-resources output is byte-identical between main and this branch, with every result complete.
  • The oxlint max-lines-per-function warning on readPeResourceLayout already exists on main (111 lines, now 112).

Synthetic fixtures plus local real files; no Windows loader run. No Hopper/Ghidra involvement.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1678 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/pe-resources-virtual-size` --- ### 📝 Commits (2) - [`f2d3eb7`](https://github.com/morluto/rea/commit/f2d3eb7cdf72c2aaed34f171710d1b6f0fdf3115) fix(native): bound PE resource RVAs by section virtual size - [`13ab289`](https://github.com/morluto/rea/commit/13ab2893591eb93fa2fe5d791488fd5c2b5261ac) Merge remote-tracking branch 'origin/main' into fix/pe-resources-virtual-size ### 📊 Changes **2 files changed** (+70 additions, -5 deletions) <details> <summary>View changed files</summary> 📝 `src/native/pe/PeResourceLayout.ts` (+11 -5) 📝 `src/native/pe/PeResourceParser.test.ts` (+59 -0) </details> ### 📄 Description ## Summary #1596 found that managed RVA reads treated a section as `max(VirtualSize, SizeOfRawData)` bytes, and 975dff2e2 fixed that in `ManagedPeReader`. The PE resource reader that #1482 added has the same mapping in `src/native/pe/PeResourceLayout.ts`, so `inspect_pe_resources` still shows both symptoms on main: - **Payload from padding.** A resource data entry whose RVA lies in the raw alignment padding past `VirtualSize` is reported with a status of complete, a file range and a SHA-256 of bytes the image loader never maps. - **Shadowed later section.** A section whose virtual range starts inside an earlier section's raw padding is refused with "Resource RVA has missing or overlapping section mappings", although only one section virtually contains the RVA. ## Change Containment, header-overlap and section-overlap checks now use the loader's virtual extent: `VirtualSize`, or `SizeOfRawData` when `VirtualSize` is 0. A range that starts inside a section but runs past its virtual extent fails with "Resource range leaves its section's virtual size." The existing file-backed requirement is unchanged. One deliberate difference from the managed fix: for `VirtualSize == 0`, the managed reader addresses no RVA, matching System.Reflection.Metadata's `PEReader`. Native resources are read from the image the Windows loader maps, and that loader uses `SizeOfRawData` when `VirtualSize` is zero. Old linkers and packers emit such sections, so they keep working here. `src/domain/native/nativeAotPe.ts` uses the same `max(...)` extent in `read()` and `virtualBytesRemaining()`. I left it unchanged because its claims need NativeAOT fixture verification that I can't run here. ## Verification - `src/native/pe/PeResourceParser.test.ts` has four new cases: a payload starting in padding, a payload straddling `VirtualSize`, `VirtualSize` 0 still mapping the section, and a later section inside earlier padding resolving to its own file bytes. The padding and later-section cases (3) fail against main's `PeResourceLayout.ts`. The `VirtualSize` 0 case passes on both and guards the loader rule. - `npm run test:focused -- src/native/pe/PeResourceParser.test.ts tests/boundary/filesystem/peResources.test.ts`: passed. `npm run typecheck` passes. - Real PE files on this Mac (Tabby's clink x64/x86/arm64 DLLs, XLD's `tak_deco_lib.dll`, TeX Live's `wtestopenfiles.exe`): `inspect-pe-resources` output is byte-identical between main and this branch, with every result complete. - The oxlint `max-lines-per-function` warning on `readPeResourceLayout` already exists on main (111 lines, now 112). Synthetic fixtures plus local real files; no Windows loader run. No Hopper/Ghidra involvement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:54:38 +00:00
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#4747
No description provided.