Files
daniel-lynch--ovrplugin-ope…/docs/research/RECON.md
T
Daniel LynchandClaude Opus 5 1f3dc40c07 docs+build: hygiene pass — close leak risk, de-drift docs, fix build prereqs
Repo hygiene round following a full review. No shim behaviour changes.

Leak risk:
- .gitignore: ignore CLAUDE.md (personal assistant-lane config, was one
  `git add -A` away from a public commit) and scratch_obj/.

Docs vs. reality:
- shim/README.md: rewritten. It described a pre-implementation skeleton with
  "core fns are TODO stubs returning -1005", three mutually inconsistent stub
  counts, and four completed milestones listed as open. Now carries the verified
  breakdown: 438/438 exports = 371 generated stubs + 46 core + 7 layers + 2
  Vulkan queries + 12 passthru trampolines.
- TESTING.md: dropped the self-contradicting "NOT yet" block (5 of 6 items were
  done or misstated, and contradicted the same file 45 lines above). Path B now
  points at tools/desktop-harness, which exists, instead of the orphaned
  shim/tests/harness.c. Path A prereqs marked as the record they are.
- HOST.md: corrected the runtime assumption. The OpenXR runtime inside Lepton is
  SteamVR (vendor/etc/openxr/1/active_runtime.json -> vrclient.so), not Monado.
  Favourable: SteamVR emulates Oculus Touch by default and advertises the
  XR_FB_foveation family, so the existing input and foveation paths should carry
  over. The old "remaining unknowns" are resolved by Lepton's published source
  and replaced with the items to check before a first Frame boot.
- README.md: same runtime correction.
- docs/research/RECON.md: the four passages prescribing an entitlement
  NOP/stub/bypass are corrected in place rather than merely disclaimed by the
  top banner, which they contradicted.

Build correctness:
- shim/build_android.sh: missing patchelf is now fatal. It warned and exited 0,
  producing a .so that cannot resolve the OpenXR loader at runtime.
- scripts/fetch_deps.sh + packaging/build_openxr_loader.sh: pin the OpenXR and
  Vulkan header versions (were tracking `main`), overridable via OPENXR_TAG /
  VULKAN_HEADERS_TAG; require cmake for the loader build.
- packaging/steamframe_patches.sh: use the apktool.jar that fetch_deps.sh
  downloads. Its prereq check demanded an `apktool` binary on PATH that the
  documented setup never provides, so it could not run after a clean setup.
- shim/gen_stubs.sh: it reads all_exports.txt, not shim_surface.txt; comment and
  emitted banner corrected. stubs.c regenerated (banner line only).
- shim/src/core.c: split seven `if (out) ...; return ...;` one-liners. Host
  build now compiles with zero warnings, down from seven.

Verified: host build 0 warnings; gen_stubs.sh output identical on regeneration;
bash -n clean on all edited scripts; pinned header/tarball URLs return 200 and
the tag tarball extracts to the expected directory name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 02:15:10 -04:00

8.8 KiB

RE4 VR (Quest 2) — Dump & Recon Checklist

Goal of this phase: non-destructively dump your own legally-owned copy of RE4 VR off the Quest 2 and answer the one question that decides the whole project — is the VR runtime OpenXR (shimmable) or VrApi (proprietary, must reimplement)?

Target app: com.Armature.VR4 (Armature Studio / Capcom / Oculus, UE 4.25.3)

Legal posture: dump-your-own only. We extract from hardware you own running a copy you own. Nothing here gets redistributed — only patches/shims you author, applied by people who dump their own copy. Same model as ReXGlue.

Editor's note (2026-06, revised 2026-09): this is a historical recon document. Its original text proposed an entitlement-stub approach in a few places (§4, the wiring summary, the decision tree). That was not carried into the project: entitlement handling is out of scope and the shim ships no circumvention code (see the README's scope section). Those passages have since been corrected in place so the document no longer reads as instructions; the correction is noted inline where it applies.


0. Prereqs (do while the Quest charges)

  • Install Android platform-tools (adb): sudo apt install android-tools-adb or grab Google's platform-tools zip.
  • Verify: adb version
  • Install analysis tooling:
    • Ghidra (native .so disassembly/patching)
    • patchelf, binutils (readelf, nm, objdump), file, unzip
    • Python 3 + pip install lief (scripted ELF inspection/patching)
    • FModel or umodel/UModel (UE 4.25 .pak browsing) — optional this phase
    • FluffyQuack's UnrealPak tools — optional this phase
  • Enable Developer Mode on the Quest (Meta Quest mobile app → Devices → Developer Mode → on; requires a registered dev org — free).
  • Plug Quest into PC via USB-C, put on headset, Allow USB debugging when prompted (and check "always allow from this computer").

1. Confirm the device + app are visible

adb devices                 # should list one device, state "device" not "unauthorized"
adb shell pm list packages | grep -i armature   # expect: com.Armature.VR4
adb shell dumpsys package com.Armature.VR4 | grep -i versionName
  • Device shows as device
  • com.Armature.VR4 present
  • Note the versionName here: ____________

2. Locate and pull the APK(s)

Split APKs are common, so grab every path.

adb shell pm path com.Armature.VR4          # prints one or more base/split apk paths
mkdir -p ~/dev/re4vr-port/dump && cd ~/dev/re4vr-port/dump
# pull each path the command above printed, e.g.:
adb pull /data/app/~~xxxx/com.Armature.VR4-yyyy/base.apk .
# repeat for any split_*.apk lines
  • base.apk pulled
  • Any split_*.apk pulled
  • Record sizes: ls -lh *.apk

3. Pull the OBB (game data / .pak files)

adb shell ls -la /sdcard/Android/obb/com.Armature.VR4/
adb pull /sdcard/Android/obb/com.Armature.VR4/ .
  • OBB pulled (e.g. main.NNN.com.Armature.VR4.obb)
  • Note the version number NNN in the OBB filename: ______ (you'll need it if you ever repack)

4. ⭐ THE DECISIVE CHECK — OpenXR vs VrApi

This is the whole reason we're here. Inspect the native libs in the APK.

cd ~/dev/re4vr-port/dump
unzip -l base.apk | grep -iE 'lib/arm64-v8a/.*\.so'        # list native libs
# the money grep:
unzip -l base.apk | grep -iE 'arm64.*(vrapi|openxr|ovrplatform|oculus|UE4)'

Interpret the result:

Lib found in lib/arm64-v8a/ Meaning Difficulty
libopenxr_loader.so ✅ Standard OpenXR — Steam Frame provides a runtime; you translate vendor extensions. Tractable
libvrapi.so ⚠️ Proprietary Meta VrApi — must reimplement/shim the runtime. Hard
libovrplatformloader.so Present either way — the platform/entitlement library. Left untouched by this project (out of scope). Not patched
libUE4.so (or split into modules) The Unreal runtime itself — the host you'll be hooking. n/a
  • RESULT — runtime is: ☑ VrApi (legacy OVRPlugin path). Confirmed 2026-06-23 on app v2.3 (versionCode 203). libvrapi.so present, libopenxr_loader.so ABSENT. libOVRPlugin.so NEEDs libvrapi.so and imports 114 vrapi_* symbols; 0 OpenXR symbols anywhere.
  • libovrplatformloader.so present? ☑ yes (hard-NEEDED by libUE4.so)

REFINED WIRING (the seam that matters):

libUE4.so --(ovrp_* C API, 239 refs)--> libOVRPlugin.so --(114 vrapi_)--> libvrapi.so --> Horizon OS
libUE4.so --(NEEDED + ovr_* Platform SDK, 132 refs)--> libovrplatformloader.so  (entitlement)
  • libUE4.so has 0 vrapi_ refs — game speaks OVRPlugin's ovrp_ C API*, not VrApi directly. libvrapi is just OVRPlugin's backend.
  • => PORT SEAM = reimplement libOVRPlugin.so (ovrp_ on OpenXR), drop libvrapi.* ovrp_* is the documented Unity-shared API (OVR_Plugin.h); modern Meta OVRPlugin has an OpenXR backend = reference impl / prior art.
  • => Leave the ovr_ Platform SDK alone* (libovrplatformloader.so). Entitlement and account handling are out of scope: the original library is kept and its real check runs unchanged. (The original recon note here proposed stubbing it; that was not carried into the project — see the README's scope section.)

If you want to double-check beyond filename presence, extract and inspect imports of libUE4.so (it may dynamically link the runtime):

unzip base.apk 'lib/arm64-v8a/*' -d apk_libs
readelf -d apk_libs/lib/arm64-v8a/libUE4.so | grep -i NEEDED
nm -D --defined-only apk_libs/lib/arm64-v8a/libopenxr_loader.so 2>/dev/null | grep -i xr | head
nm -D apk_libs/lib/arm64-v8a/libUE4.so | grep -iE 'xrCreate|vrapi_' | head

xrCreate*/xr* symbols → OpenXR codepath. vrapi_* symbols → VrApi codepath. A binary can ship both libs but only call one — the symbol check tells you which is actually wired up.


5. Manifest & build recon

# Needs apktool (sudo apt install apktool) OR aapt from build-tools
aapt dump badging base.apk | grep -iE 'sdkVersion|native-code|package'
apktool d -s base.apk -o apk_decoded     # -s = don't decode .dex, faster
grep -iE 'oculus|vr|xr|entitlement|permission' apk_decoded/AndroidManifest.xml
  • minSdk / targetSdk noted: ______
  • native-code ABI (expect arm64-v8a): ______
  • Any Oculus/entitlement metadata flags in manifest noted below.

6. Confirm .pak accessibility (asset layer)

The community reports these are unencrypted — verify so you know the asset layer is open if you ever need it.

# unzip the OBB (it's a zip), find Content/Paks/*.pak, then:
# try opening in FModel/umodel as UE 4.25.3, no AES key
  • .pak opens with no AES key (confirms community finding) ☑ yes Verified 2026-06-23: pakchunk9 footer bEncryptedIndex=0, EncryptionKeyGuid all-zero, pak version 9 (FrozenIndex / UE4.25-26). Plaintext index — 53 readable asset paths incl. /Game/Levels/BIO4/... Asset layer fully open.
  • OBB layout: store (uncompressed) zip. main.203 (4.0GB) + patch.203 (4.0GB, the v2.3 update layer) + a stashed VR4-Android-Shipping-arm64.apk (== base.apk). Paks at VR4/Content/Paks/pakchunk{0..9}[optional]-Android_ETC2.pak (ETC2 = Android texture compression; 'optional' = hi-res texture chunks). Bink cutscenes at VR4/Content/Movies/*.bk2.

7. Record findings → decide path

Fill this in, then we branch:

versionName:        2.3 (versionCode 203, minSdk 25, targetSdk 29)
runtime:            VrApi  (libvrapi via libOVRPlugin; NO openxr)  [CONFIRMED 2026-06-23]
ovrplatform loader: present (hard-NEEDED by libUE4.so)
UE version:         4.25.3 (engine = libUE4.so, stripped, arm64)
ABIs:               arm64-v8a (single base.apk, no splits)
paks encrypted:     NO — unencrypted, no AES key (CONFIRMED 2026-06-23, pak v9)
device:             Quest 2 serial <redacted-serial> (codename hollywood)

Decision tree:

  • OpenXR → next phase: map which Meta OpenXR vendor extensions the binary requests, plan the OpenXR→Steam-Frame-runtime shim. This is the "weekend-of-shimming" branch.
  • VrApi → next phase: scope a VrApi reimplementation/translation shim (much larger). Reassess whether the project is worth it vs. waiting/UEVR.
  • Either way → libovrplatformloader.so is left as shipped. Entitlement handling is out of scope for this project and no bypass is part of it; on Quest the platform's real check runs unchanged. (The original recon note assumed a patch here; superseded.)

Notes / scratch

(paste command output, symbol dumps, and decisions here as you go)