[GH-ISSUE #3111] [Windows] Native controls self-check blocks static Android APK analysis on Win11 build 26300 (rea-agents 6.4.0) #1083

Open
opened 2026-10-15 18:30:55 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @yangwb1999 on GitHub (Oct 14, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/3111

Summary

On Windows 11 (build 26300) with rea-agents 6.4.0, the Windows native controls self-check fails deterministically. Beyond the Ghidra provider already reported in #1701, this also blocks the static Android APK analysis path — confirmed with a fully provisioned, hash-verified JADX engine.

Environment

  • OS: Windows 11 Pro, build 26300
  • rea-agents: 6.4.0 (npm global install)
  • Node.js: v22.20.0
  • JDK: 17 (JAVA_HOME configured)
  • adb: 34.0.4 (auto-detected from PATH)
  • JADX engine: jadx-headless-mcp-0.7.1-all.jar (40.6 MB, SHA-256 6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75, verified against REA's pinned digest), placed at C:\Users\<user>\.local\share\rea\android\, REA_JADX_MCP_JAR set
  • Native addon: rea-windows-x64.node present and loads successfully

Reproduction

Target: ApiDemos-debug.apk (appium/android-apidemos v6.0.18, 6.22 MB, SHA-256 a9eecf37b26cd084855c530db81c2bb1b91f4c1b095a04f47aa7c20e2791f686)

$ rea inspect-android-package ApiDemos-debug.apk
... REA Windows native controls are unavailable: Delete owned object by handle failed
[C:\Users\<user>\AppData\Local\Temp\rea-native-probe-<32hex>] (Win32 5): access denied

Fails 100% across multiple consecutive attempts, both sandboxed and unsandboxed, with and without elevation.

What this adds beyond #1701

  • The same native-controls self-check failure also blocks the Android static analysis path (JADX provider) — not just Ghidra. The JADX engine was fully in place and hash-verified, so the failure occurs purely at the Windows native probe step, before any provider-specific work.
  • Independent confirmation on the same OS build (26300) as the latest failing-host report in #1701.
  • Ruled out as causes: third-party AV (Defender-only machine), temp ACLs (manual deletion of leftover probe dirs succeeds), network/proxy, sandboxing, Node version, and elevation state.
  • A reproducible fixture is available: ApiDemos-debug.apk (hash above). rea inspect-android-package on this APK can serve as a minimal regression test for the native probe fix.

Notes

  • Leftover empty rea-native-probe-* directories accumulate in %TEMP% with no cleanup path (as also noted in #1701).
  • No workaround found: REA_WORKSPACE_ROOT is irrelevant to the probe path, and replacing the addon is blocked by REA's SHA-256 pinning.
Originally created by @yangwb1999 on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3111 ## Summary On Windows 11 (build 26300) with rea-agents 6.4.0, the Windows native controls self-check fails deterministically. Beyond the Ghidra provider already reported in #1701, this also blocks the **static Android APK analysis** path — confirmed with a fully provisioned, hash-verified JADX engine. ## Environment - OS: Windows 11 Pro, build 26300 - rea-agents: 6.4.0 (npm global install) - Node.js: v22.20.0 - JDK: 17 (JAVA_HOME configured) - adb: 34.0.4 (auto-detected from PATH) - JADX engine: `jadx-headless-mcp-0.7.1-all.jar` (40.6 MB, SHA-256 `6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75`, verified against REA's pinned digest), placed at `C:\Users\<user>\.local\share\rea\android\`, `REA_JADX_MCP_JAR` set - Native addon: `rea-windows-x64.node` present and loads successfully ## Reproduction Target: `ApiDemos-debug.apk` (appium/android-apidemos v6.0.18, 6.22 MB, SHA-256 `a9eecf37b26cd084855c530db81c2bb1b91f4c1b095a04f47aa7c20e2791f686`) ``` $ rea inspect-android-package ApiDemos-debug.apk ... REA Windows native controls are unavailable: Delete owned object by handle failed [C:\Users\<user>\AppData\Local\Temp\rea-native-probe-<32hex>] (Win32 5): access denied ``` Fails 100% across multiple consecutive attempts, both sandboxed and unsandboxed, with and without elevation. ## What this adds beyond #1701 - The same native-controls self-check failure also blocks the **Android static analysis** path (JADX provider) — not just Ghidra. The JADX engine was fully in place and hash-verified, so the failure occurs purely at the Windows native probe step, before any provider-specific work. - Independent confirmation on the same OS build (26300) as the latest failing-host report in #1701. - Ruled out as causes: third-party AV (Defender-only machine), temp ACLs (manual deletion of leftover probe dirs succeeds), network/proxy, sandboxing, Node version, and elevation state. - A reproducible fixture is available: `ApiDemos-debug.apk` (hash above). `rea inspect-android-package` on this APK can serve as a minimal regression test for the native probe fix. ## Notes - Leftover empty `rea-native-probe-*` directories accumulate in `%TEMP%` with no cleanup path (as also noted in #1701). - No workaround found: `REA_WORKSPACE_ROOT` is irrelevant to the probe path, and replacing the addon is blocked by REA's SHA-256 pinning.
Author
Owner

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

This looks like the same self-test failure as #1701 (Delete owned object by handle failed, Win32 5, rea-native-probe-* left in %TEMP%), reached here from the JADX path.

Re-checked today on a host with the same build where the self-test passes: Windows 11 Pro 26H2, build 26300.9457, non-elevated, Defender only (real-time on, Controlled Folder Access off), %TEMP% on local NTFS C:, rea-agents 6.4.0 with its bundled rea-windows-x64.node (SHA-256 c4fd9f37…b6d5), Node.js 22.22.3. rea doctor --provider ghidra --json reports native_authority healthy ("Verified Windows native Job Object, private DACL, and reparse-safe handle controls") and leaves no probe directory behind. The share-mode matrix and the addon replay from this host are in https://github.com/morluto/rea/issues/1701#issuecomment-6121147310. The host's setup is public and reproducible in rea-lab, which pins rea, Ghidra 12.1.4 and the JDK (package.json, tools.json) and records the passing rea doctor result in its status.

So build 26300 alone does not cause it. Three facts from your host would help tell the two apart:

  1. The modules loaded into a node.exe started from the same shell, for example node -e "setTimeout(() => {}, 60000)" and then tasklist /m /fi "imagename eq node.exe". On one failing host in #1701, the difference was a DLL that hooks NtCreateFile and NtSetInformationFile.
  2. fltmc filters from an elevated prompt, to list file-system minifilters beyond Defender's WdFilter.
  3. fsutil fsinfo volumeinfo for the volume that holds %TEMP%, and fsutil reparsepoint query "%TEMP%", to rule out a Dev Drive, ReFS or a redirected folder.
<!-- gh-comment-id:6161528047 --> @pablodiazjorge commented on GitHub (Oct 14, 2026): This looks like the same self-test failure as #1701 (`Delete owned object by handle failed`, Win32 5, `rea-native-probe-*` left in `%TEMP%`), reached here from the JADX path. Re-checked today on a host with the same build where the self-test passes: Windows 11 Pro 26H2, build 26300.9457, non-elevated, Defender only (real-time on, Controlled Folder Access off), `%TEMP%` on local NTFS `C:`, `rea-agents` 6.4.0 with its bundled `rea-windows-x64.node` (SHA-256 `c4fd9f37…b6d5`), Node.js 22.22.3. `rea doctor --provider ghidra --json` reports `native_authority` healthy ("Verified Windows native Job Object, private DACL, and reparse-safe handle controls") and leaves no probe directory behind. The share-mode matrix and the addon replay from this host are in https://github.com/morluto/rea/issues/1701#issuecomment-6121147310. The host's setup is public and reproducible in [rea-lab](https://github.com/pablodiazjorge/rea-lab), which pins rea, Ghidra 12.1.4 and the JDK (`package.json`, `tools.json`) and records the passing `rea doctor` result in its [status](https://github.com/pablodiazjorge/rea-lab#status). So build 26300 alone does not cause it. Three facts from your host would help tell the two apart: 1. The modules loaded into a `node.exe` started from the same shell, for example `node -e "setTimeout(() => {}, 60000)"` and then `tasklist /m /fi "imagename eq node.exe"`. On one failing host in #1701, the difference was a DLL that hooks `NtCreateFile` and `NtSetInformationFile`. 2. `fltmc filters` from an elevated prompt, to list file-system minifilters beyond Defender's `WdFilter`. 3. `fsutil fsinfo volumeinfo` for the volume that holds `%TEMP%`, and `fsutil reparsepoint query "%TEMP%"`, to rule out a Dev Drive, ReFS or a redirected folder.
Author
Owner

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

@yangwb1999 Your host is the one thing this bug has been missing: a deterministic reproducer. Everyone who can build the addon is on a host where the self-test passes, and everyone who reproduces it cannot build. If you are willing to run one instrumented build, it would likely settle the root cause.

Where this stands

Four reports, one root cause: this, #1701, #2196, and the fix under review in #2445. Worth tracking together; the JADX path you hit is the same inspect self-test gate the Ghidra lane hits, which is why a fully provisioned, hash-verified engine makes no difference.

Why a measurement is still needed

The leading theory is that the retained create handle lacks FILE_SHARE_DELETE, so the object cannot be marked delete-pending. @liudong-geek's matrix shows exactly that on their host. On mine it does not hold: SetFileInformationByHandle(FileDispositionInfo) succeeds on a directory whose sole handle was created with FILE_SHARE_READ and no FILE_SHARE_DELETE — 30/30 through the addon, and in an isolated CreateFileW replication, including with a second non-sharing reader held open (details).

Both results can be true if the share rule is enforced only when something else holds the object. That is what the instrumented build measures, and it is the difference between "add the share flag" and "find the other handle holder".

The instrumented build

Patch and build recipe are in this comment on #1701. It applies to main at 5190843, compiles clean with the documented MinGW lane, and I verified the resulting addon loads and passes on a non-reproducing host, so the instrumentation itself does not change the outcome.

On the failure path only, it prints one line before the existing error:

REA_DIAG_1701 {"classicWin32":5,"grantedAccess":"0x...","handleCount":N,"pointerCount":N,
               "deletePending":false,"directory":true,"children":0,"posixDispositionWin32":0}
  • handleCount is the decisive field. > 1 means another handle holds the object and the share mode is the mechanism; == 1 means a sole handle is blocking its own transition, which is not the documented rule and points at a filter driver instead.
  • grantedAccess confirms whether the handle actually holds DELETE (0x00010000).
  • posixDispositionWin32 tests whether FileDispositionInfoEx with POSIX semantics succeeds where the classic call fails — 0 there would make that a candidate fix.

No MSVC needed; the lane cross-compiles from Linux, and a container satisfies it (that is how I build on a Windows host with no C++ toolchain). One caveat stated plainly: the POSIX probe is not read-only — where it reports 0 the object is unlinked, so that run leaks no probe directory. The thrown error is otherwise identical to the stock build.

If a container is not practical for you, say so and I will attach a prebuilt .node with its SHA-256 instead — I would just rather you not run a stranger's binary if building is an option.

One note on #2445

The proposed fix adds FILE_SHARE_DELETE. On a passing host it does not regress the self-test (30/30 here), but it does change cleanup behaviour: the native lane fails at cleanupFailureRetainsOwnershipForRetry, where cleanup with a live reader now returns ERROR_SHARING_VIOLATION at the open step instead of the documented delete-denied constraint. Base passes the same lane, head does not — A/B detail. So that PR probably needs another pass, and confirmation from a host like yours that it actually fixes the failure, which no one has produced yet.

🤖 Posted by Claude Code

<!-- gh-comment-id:6163500075 --> @Rinkia commented on GitHub (Oct 14, 2026): @yangwb1999 Your host is the one thing this bug has been missing: a **deterministic** reproducer. Everyone who can build the addon is on a host where the self-test passes, and everyone who reproduces it cannot build. If you are willing to run one instrumented build, it would likely settle the root cause. ### Where this stands Four reports, one root cause: this, #1701, #2196, and the fix under review in #2445. Worth tracking together; the JADX path you hit is the same `inspect` self-test gate the Ghidra lane hits, which is why a fully provisioned, hash-verified engine makes no difference. ### Why a measurement is still needed The leading theory is that the retained create handle lacks `FILE_SHARE_DELETE`, so the object cannot be marked delete-pending. @liudong-geek's matrix shows exactly that on their host. On mine it does **not** hold: `SetFileInformationByHandle(FileDispositionInfo)` succeeds on a directory whose sole handle was created with `FILE_SHARE_READ` and no `FILE_SHARE_DELETE` — 30/30 through the addon, and in an isolated `CreateFileW` replication, including with a second non-sharing reader held open ([details](https://github.com/morluto/rea/issues/1701#issuecomment-6128245661)). Both results can be true if the share rule is enforced only when something *else* holds the object. That is what the instrumented build measures, and it is the difference between "add the share flag" and "find the other handle holder". ### The instrumented build Patch and build recipe are in [this comment on #1701](https://github.com/morluto/rea/issues/1701#issuecomment-6130599030). It applies to `main` at `5190843`, compiles clean with the documented MinGW lane, and I verified the resulting addon loads and passes on a non-reproducing host, so the instrumentation itself does not change the outcome. On the failure path only, it prints one line before the existing error: ``` REA_DIAG_1701 {"classicWin32":5,"grantedAccess":"0x...","handleCount":N,"pointerCount":N, "deletePending":false,"directory":true,"children":0,"posixDispositionWin32":0} ``` - `handleCount` is the decisive field. `> 1` means another handle holds the object and the share mode is the mechanism; `== 1` means a sole handle is blocking its own transition, which is not the documented rule and points at a filter driver instead. - `grantedAccess` confirms whether the handle actually holds `DELETE` (`0x00010000`). - `posixDispositionWin32` tests whether `FileDispositionInfoEx` with POSIX semantics succeeds where the classic call fails — `0` there would make that a candidate fix. No MSVC needed; the lane cross-compiles from Linux, and a container satisfies it (that is how I build on a Windows host with no C++ toolchain). One caveat stated plainly: the POSIX probe is **not** read-only — where it reports `0` the object is unlinked, so that run leaks no probe directory. The thrown error is otherwise identical to the stock build. If a container is not practical for you, say so and I will attach a prebuilt `.node` with its SHA-256 instead — I would just rather you not run a stranger's binary if building is an option. ### One note on #2445 The proposed fix adds `FILE_SHARE_DELETE`. On a passing host it does not regress the self-test (30/30 here), but it does change cleanup behaviour: the native lane fails at `cleanupFailureRetainsOwnershipForRetry`, where cleanup with a live reader now returns `ERROR_SHARING_VIOLATION` at the open step instead of the documented delete-denied constraint. Base passes the same lane, head does not — [A/B detail](https://github.com/morluto/rea/pull/2445#pullrequestreview-5504130007). So that PR probably needs another pass, and confirmation from a host like yours that it actually fixes the failure, which no one has produced yet. _🤖 Posted by [Claude Code](https://claude.com/claude-code)_
Author
Owner

@e-micsun commented on GitHub (Oct 14, 2026):

I'm on a similar Win11 x64 setup and my native controls self-check passes (rea then drives Ghidra fine). Details that may help narrow the host-related factor:

  • OS: Windows 11 23H2, build 22631.4602 (non-elevated / normal user, UAC on)
  • AV: only Microsoft Defender, no third-party AV
  • %TEMP%: on local NTFS drive C: (not a network/redirector path)
  • REA: 6.4.0, built from source; Node 22.22.2; JDK 21.0.12.1; Ghidra 12.1.4
  • Result: after supplying the prebuilt native/windows/build/rea-windows-x64.node (from the npm package — source installs don't ship it), rea doctor shows Ghidra healthy and analyze runs end-to-end (e.g. notepad.exe → 915 functions, 635 strings).
    So on this host the job-object / directory-permission self-check succeeds. If the failing cases correlate with a specific Windows build, Defender config, or a non-NTFS/redirected %TEMP%, a passing sample on 22631.4602 might help bracket it. Happy to run any diagnostic you want on this machine.
<!-- gh-comment-id:6169366221 --> @e-micsun commented on GitHub (Oct 14, 2026): I'm on a similar Win11 x64 setup and my native controls self-check passes (rea then drives Ghidra fine). Details that may help narrow the host-related factor: - OS: Windows 11 23H2, build 22631.4602 (non-elevated / normal user, UAC on) - AV: only Microsoft Defender, no third-party AV - %TEMP%: on local NTFS drive C: (not a network/redirector path) - REA: 6.4.0, built from source; Node 22.22.2; JDK 21.0.12.1; Ghidra 12.1.4 - Result: after supplying the prebuilt native/windows/build/rea-windows-x64.node (from the npm package — source installs don't ship it), rea doctor shows Ghidra healthy and analyze runs end-to-end (e.g. notepad.exe → 915 functions, 635 strings). So on this host the job-object / directory-permission self-check succeeds. If the failing cases correlate with a specific Windows build, Defender config, or a non-NTFS/redirected %TEMP%, a passing sample on 22631.4602 might help bracket it. Happy to run any diagnostic you want on this machine.
Author
Owner

@yangwb1999 commented on GitHub (Oct 17, 2026):

Confirmed fixed in rea-agents 6.5.0.

Retest (same host as reported above: Windows 11, build 26300)

Upgraded via npm install --global rea-agents@latest (6.4.0 → 6.5.0), then re-ran the previously failing reproduction from this issue:

$ rea inspect-android-package ApiDemos-debug.apk

Result: succeeds. The Windows native controls self-check no longer fails — the

REA Windows native controls are unavailable: Delete owned object by handle failed (Win32 5)

error is gone entirely. The static Android analysis path now works end to end:

  • Provider: jadx (jadx-headless-mcp 0.7.1, JAR SHA-256 verified against the pinned digest)
  • Fixture: same ApiDemos-debug.apk as in the issue body (sha256 a9eecf37b26cd084855c530db81c2bb1b91f4c1b095a04f47aa7c20e2791f686)
  • Parsed: 2876 classes, 869 resources, package io.appium.android.apis v6.0.18

Also confirmed the %TEMP% probe-directory cleanup works now (no rea-native-probe-* leftovers after runs).

Thanks for the quick turnaround on the fix.

<!-- gh-comment-id:6230918560 --> @yangwb1999 commented on GitHub (Oct 17, 2026): Confirmed fixed in rea-agents **6.5.0**. ## Retest (same host as reported above: Windows 11, build 26300) Upgraded via `npm install --global rea-agents@latest` (6.4.0 → 6.5.0), then re-ran the previously failing reproduction from this issue: ``` $ rea inspect-android-package ApiDemos-debug.apk ``` **Result: succeeds.** The Windows native controls self-check no longer fails — the ``` REA Windows native controls are unavailable: Delete owned object by handle failed (Win32 5) ``` error is gone entirely. The static Android analysis path now works end to end: - Provider: `jadx` (jadx-headless-mcp 0.7.1, JAR SHA-256 verified against the pinned digest) - Fixture: same `ApiDemos-debug.apk` as in the issue body (sha256 `a9eecf37b26cd084855c530db81c2bb1b91f4c1b095a04f47aa7c20e2791f686`) - Parsed: **2876 classes, 869 resources**, package `io.appium.android.apis` v6.0.18 Also confirmed the `%TEMP%` probe-directory cleanup works now (no `rea-native-probe-*` leftovers after runs). Thanks for the quick turnaround on the fix.
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#1083
No description provided.