[GH-ISSUE #2408] [Feature] Open 16-bit Windows (NE) executables through the Ghidra lane #810

Open
opened 2026-10-15 18:28:39 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @CassieFox23 on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2408

TL;DR: REA refuses 16-bit Windows (NE) programs today, and the docs say that is on purpose. A member of the REA Discord wants to look at one. I have a fork prototype that opens them through Ghidra, shown in #2231. On Discord, morluto asked for an issue, so here it is.

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This request does not include credentials, private samples, or sensitive target data.

Area

Native analysis or decompilation

Current limitation

open_binary on a Windows 3.x program fails with unsupported NE executable in MZ image. The guide docs/ghidra-dos.md says "NE, LE, and LX declarations are explicitly unsupported". Ghidra itself loads NE files with its own NE loader.

Use cases

  • A member of the REA Discord wanted to study a DOS-era program in NE format. REA turned it away. #1979 fixed the confusing error text, but did not add support.
  • Old Windows 3.x programs and DLLs, for preservation and learning.

Desired outcome and success criteria

  • open_binary on an NE file opens it with format ne.
  • The Ghidra lane lists its functions and segments, and gives pseudocode and read_bytes. The function list matches Ghidra headless.
  • LE and LX files stay refused, with the same message.
  • DOS MZ files are unchanged.

Expected interaction with targets

Read existing files or captured data

Target and scope details

  • Windows 3.x NE programs and DLLs. OS/2 NE is not tested.
  • Not in scope: LE and LX, and the load-image check that DOS MZ files get.
  • Scope question: the change adds a new ne value to public lists of formats. The tool output schemas are among them.

Verification available so far

I have a prototype or observed results

Verification details

My fork branch opens binw/wzoom.exe from Open Watcom v2 (Sybase Open Watcom Public License 1.0) as ne. It lists 217 local functions, the same as Ghidra headless. The decompiler gives real C with calls like CREATEWINDOW, and read_bytes matches the file. The tables and test runs are in #2231. I tested one sample, on Linux only.

Alternatives considered

Running Ghidra by hand, outside REA. That works, but then an agent gets none of REA's tools or evidence for the file.

Possible direction

My fork branch feat/ne-ghidra-lane does this:

  • A new ne format, opened with Ghidra's NE loader and x86:LE:16:Protected Mode.
  • NE addresses read as selector, then offset. So 1000:007c shows as 0x1000007c.
  • Hopper declines NE and points to Ghidra.

It is not rebased on today's main. I can rebase it and open a PR if you want one.

References

  • Discussion #2231, with the full prototype results
  • #1979, the earlier error-text fix
  • docs/ghidra-dos.md, lines 29 and 30 on main

🤖 Generated with Claude Code (Opus 5.5) 🦊

Originally created by @CassieFox23 on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2408 **TL;DR:** REA refuses 16-bit Windows (NE) programs today, and the docs say that is on purpose. A member of the REA Discord wants to look at one. I have a fork prototype that opens them through Ghidra, shown in #2231. On Discord, morluto asked for an issue, so here it is. ### Before submitting - [X] I searched the open and closed issues and pull requests for a related proposal. - [X] I understand the contribution scope must be reviewed before integration; open questions are welcome here. - [X] This request does not include credentials, private samples, or sensitive target data. ### Area `Native analysis or decompilation` ### Current limitation `open_binary` on a Windows 3.x program fails with `unsupported NE executable in MZ image`. The guide `docs/ghidra-dos.md` says "NE, LE, and LX declarations are explicitly unsupported". Ghidra itself loads NE files with its own NE loader. ### Use cases - A member of the REA Discord wanted to study a DOS-era program in NE format. REA turned it away. #1979 fixed the confusing error text, but did not add support. - Old Windows 3.x programs and DLLs, for preservation and learning. ### Desired outcome and success criteria - `open_binary` on an NE file opens it with format `ne`. - The Ghidra lane lists its functions and segments, and gives pseudocode and `read_bytes`. The function list matches Ghidra headless. - LE and LX files stay refused, with the same message. - DOS MZ files are unchanged. ### Expected interaction with targets `Read existing files or captured data` ### Target and scope details - Windows 3.x NE programs and DLLs. OS/2 NE is not tested. - Not in scope: LE and LX, and the load-image check that DOS MZ files get. - Scope question: the change adds a new `ne` value to public lists of formats. The tool output schemas are among them. ### Verification available so far `I have a prototype or observed results` ### Verification details My fork branch opens `binw/wzoom.exe` from Open Watcom v2 (Sybase Open Watcom Public License 1.0) as `ne`. It lists 217 local functions, the same as Ghidra headless. The decompiler gives real C with calls like `CREATEWINDOW`, and `read_bytes` matches the file. The tables and test runs are in #2231. I tested one sample, on Linux only. ### Alternatives considered Running Ghidra by hand, outside REA. That works, but then an agent gets none of REA's tools or evidence for the file. ### Possible direction My fork branch `feat/ne-ghidra-lane` does this: - A new `ne` format, opened with Ghidra's NE loader and `x86:LE:16:Protected Mode`. - NE addresses read as selector, then offset. So 1000:007c shows as 0x1000007c. - Hopper declines NE and points to Ghidra. It is not rebased on today's main. I can rebase it and open a PR if you want one. ### References - Discussion #2231, with the full prototype results - #1979, the earlier error-text fix - `docs/ghidra-dos.md`, lines 29 and 30 on main 🤖 Generated with Claude Code (Opus 5.5) 🦊
Author
Owner

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

Thanks for putting together this detailed proposal and sharing the Watcom wzoom.exe prototype results from #2231!

Review & Triage Notes

  1. Scope & Fail-Closed Boundary (What's right):

    • Explicitly scoping this to the Ghidra lane for 16-bit Windows NE executables while keeping LE/LX refused and DOS MZ handling intact conforms to REA's fail-closed policy.
    • Preserving the 16-bit segmented address representation (selector:offset, e.g. 0x1000007c) rather than flat arbitrary offsets is the correct model for 16-bit protected mode binaries.
  2. Gaps to Address Before Integration (What needs clarification):

    • Schema & Format Catalog: Introducing ne as an admitted binary format expands the public format enum and tool output schemas. Per AGENTS.md, public schema changes must be accompanied by dialect validation and exact-type bindings.
    • Specification Requirement (SDD): Before opening the PR, please outline the spec under docs/specs/native/ne-format/ with spec.md, plan.md, and tasks.md, defining the acceptance criteria, Ghidra loader configuration (x86:LE:16:Protected Mode), and error-boundary behaviors (e.g., how Hopper explicitly declines and points to Ghidra).
    • Test Fixtures & Cross-Platform Verification: wzoom.exe is under Sybase Open Watcom Public License 1.0; ensure fixture licensing permits inclusion or provide a minimal synthetic 16-bit NE assembly fixture in tests that runs in CI across Linux and macOS.

If you rebase feat/ne-ghidra-lane on current main and draft the spec, we can review the implementation PR.

<!-- gh-comment-id:6133726684 --> @matbrgz commented on GitHub (Oct 12, 2026): Thanks for putting together this detailed proposal and sharing the Watcom `wzoom.exe` prototype results from #2231! ### Review & Triage Notes 1. **Scope & Fail-Closed Boundary (What's right):** - Explicitly scoping this to the Ghidra lane for 16-bit Windows NE executables while keeping LE/LX refused and DOS MZ handling intact conforms to REA's fail-closed policy. - Preserving the 16-bit segmented address representation (`selector:offset`, e.g. `0x1000007c`) rather than flat arbitrary offsets is the correct model for 16-bit protected mode binaries. 2. **Gaps to Address Before Integration (What needs clarification):** - **Schema & Format Catalog:** Introducing `ne` as an admitted binary format expands the public format enum and tool output schemas. Per `AGENTS.md`, public schema changes must be accompanied by dialect validation and exact-type bindings. - **Specification Requirement (SDD):** Before opening the PR, please outline the spec under `docs/specs/native/ne-format/` with `spec.md`, `plan.md`, and `tasks.md`, defining the acceptance criteria, Ghidra loader configuration (`x86:LE:16:Protected Mode`), and error-boundary behaviors (e.g., how Hopper explicitly declines and points to Ghidra). - **Test Fixtures & Cross-Platform Verification:** `wzoom.exe` is under Sybase Open Watcom Public License 1.0; ensure fixture licensing permits inclusion or provide a minimal synthetic 16-bit NE assembly fixture in tests that runs in CI across Linux and macOS. If you rebase `feat/ne-ghidra-lane` on current `main` and draft the spec, we can review the implementation PR.
Author
Owner

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

Thanks, matbrgz, for reading it so closely. Two of your points will go into the PR. It will check the new ne value against the schema rules in AGENTS.md. Its tests will use small synthetic NE files, not wzoom.exe. I don't see a docs/specs/ folder on main, so I'll hold off on that unless a maintainer asks for it. I'm also waiting on morluto's call on scope, since this adds ne to public format lists, before I open anything.

🤖 Generated with Claude Code (Opus 5.5) 🦊

<!-- gh-comment-id:6133877641 --> @CassieFox23 commented on GitHub (Oct 12, 2026): Thanks, matbrgz, for reading it so closely. Two of your points will go into the PR. It will check the new `ne` value against the schema rules in AGENTS.md. Its tests will use small synthetic NE files, not `wzoom.exe`. I don't see a `docs/specs/` folder on main, so I'll hold off on that unless a maintainer asks for it. I'm also waiting on morluto's call on scope, since this adds `ne` to public format lists, before I open anything. 🤖 Generated with Claude Code (Opus 5.5) 🦊
Author
Owner

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

A small status update. I rebased the NE change onto today's main (569ef4159), and it is ready if you want it.

  • It still adds ne only where the DOS formats are listed, and LE and LX are still refused.
  • Type check, format and lint are clean. 234 tests pass on Node 22, 24 and 26.
  • On real Ghidra 12.1.4, a 305-byte hand-made NE file opens as ne and decompiles. All 8 MCP replies match their output schemas.

I'll hold the PR until the scope is settled. A no is a fine answer too. I can also write the spec note matbrgz suggested, if that helps.

🤖 Generated with Claude Code (Opus 5.5) 🦊

<!-- gh-comment-id:6173415327 --> @CassieFox23 commented on GitHub (Oct 14, 2026): A small status update. I rebased the NE change onto today's main (569ef4159), and it is ready if you want it. - It still adds `ne` only where the DOS formats are listed, and LE and LX are still refused. - Type check, format and lint are clean. 234 tests pass on Node 22, 24 and 26. - On real Ghidra 12.1.4, a 305-byte hand-made NE file opens as `ne` and decompiles. All 8 MCP replies match their output schemas. I'll hold the PR until the scope is settled. A no is a fine answer too. I can also write the spec note matbrgz suggested, if that helps. 🤖 Generated with Claude Code (Opus 5.5) 🦊
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#810
No description provided.