[GH-ISSUE #4447] [Feature] Link Android UniFFI/JNA bindings to their native exports (Rust libraries have no Java_* symbols) #1763

Open
opened 2026-10-16 21:09:59 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @Rinkia on GitHub (Oct 16, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4447

Before submitting

  • I searched the open and closed issues for a related report (JNA, uniffi, JNI binding, Java_ export, android native bridge). Closest: #2379 (JNI correlation design, still open). There is no mention of JNA or UniFFI in src/ or docs/ on main @ d72d856f5.
  • I understand the contribution scope; this asks for static linkage only.
  • This report contains no credentials or private target samples.

Area

Android or mobile analysis

Current limitation

More and more Android apps ship Rust through UniFFI bindings. The generated Kotlin calls the library through JNA, not JNI. A UniffiLib interface declares one method per C export of the same name, and Native.register/Native.load binds it at run time. These libraries export no Java_* symbols and no JNI_OnLoad.

REA currently has no way to connect the two sides:

  • inspect_android_method on a binding method returns "method exists but has no decompiled body (native/abstract)", with no library or symbol.
  • project_android_application_graph's bridge hypotheses are a path-based Cartesian product of DEX classes and .so files, and the docs note this "does not identify a specific JNI binding".
  • JNI-style correlation (Java_<class>_<method>) can't work for these libraries either. The only JNI library involved is JNA's own libjnidispatch.so, so a JNI matcher would link every binding to JNA's dispatcher instead of to the real library.

Public example: Element X 26.09.1, F-Droid arm64 build. It uses JNA 5.19.1 and org.matrix.rustcomponents:sdk-android:26.08.25 at tag v26.09.1. Dynamic exports, read from .dynsym:

Library Size Exports Java_* uniffi_* JNI_OnLoad
libmatrix_sdk_ffi.so 63,058,304 1,875 0 1,450 no
libuniffi_wysiwyg_composer.so 3,109,256 161 0 108 no
libjnidispatch.so (JNA) 165,992 127 69 0 yes

REA lists 579 methods in org.matrix.rustcomponents.sdk.UniffiLib, and every one of its 577 uniffi_*/ffi_* methods matches a libmatrix_sdk_ffi.so export by exact name (577/577). The APK also has per-crate uniffi.<crate>.UniffiLib interfaces (matrix_sdk_crypto, matrix_sdk_ui, ruma_events, …).

The same pattern holds in a large proprietary VPN app I analysed. In aggregate, five of its Rust libraries have 0–1 Java_* exports each, against 41–163 uniffi_* exports. So the gap isn't specific to Matrix.

Desired outcome and success criteria

A static, evidence-backed binding facet. For example, inspect_android_class (or a dedicated tool or graph projection) would report, for an interface that extends com.sun.jna.Library or is passed to Native.register/Native.load:

  • the library-name candidates from the literal passed to JNA ("matrix_sdk_ffi") and the matching lib<name>.so in the APK or split, each with its SHA-256;
  • per method, an exact-name match against that library's dynamic exports: matched, unmatched, or ambiguous when several libraries export the name;
  • explicit coverage and unknowns: computed library names, Native.load through helper functions, R8-renamed interfaces (UniFFI keeps the symbol names in method names, but a minifier could rename them), and JNA Structure/callback types;
  • no runtime claims: a match doesn't prove the library is loaded or the method called.

Recognising the UniFFI checksum interface (IntegrityCheckingUniffiLib, uniffi_*_checksum_*) and ffi_*_rust_future_* helpers would be a bonus, not a requirement.

Expected interaction with targets

Read the APK, split APKs and .so files only. No execution.

Verification available so far

  • APK: https://github.com/element-hq/element-x-android/releases/download/v26.09.1/app-fdroid-arm64-v8a-release-signed.apk. This is the binary F-Droid ships for versionCode 202609012 (reproducible build). sha256 ceb076564298cd0aef4688ad79058b55638d196b9beb5ac47ab421d757335bf3 matches the GitHub asset digest. The signing certificate's SHA-256, 6a2fdc31…e92d47, equals fdroiddata's AllowedAPKSigningKeys.
  • Exports were read from the ELF .dynsym: defined STT_FUNC symbols with non-local binding.
  • REA: rea-agents@6.5.0, search-android-classes … UniffiLib, inspect-android-class org.matrix.rustcomponents.sdk.UniffiLib, and inspect-android-method … uniffi_matrix_sdk_ffi_fn_func_sdk_git_sha.

Alternatives considered

  • JNI symbol matching alone: it can't see these libraries (the table above).
  • Leaving it to the analyst: a 577-way name match is mechanical and exact, which is what REA's evidence model is good at.

References

#2379 (Java/JNI correlation design), #3489 (native method flags), #717 (APK roadmap).

Originally created by @Rinkia on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4447 ### Before submitting - [x] I searched the open and closed issues for a related report (JNA, uniffi, JNI binding, Java_ export, android native bridge). Closest: #2379 (JNI correlation design, still open). There is no mention of JNA or UniFFI in `src/` or `docs/` on `main` @ `d72d856f5`. - [x] I understand the contribution scope; this asks for static linkage only. - [x] This report contains no credentials or private target samples. ### Area Android or mobile analysis ### Current limitation More and more Android apps ship Rust through [UniFFI](https://github.com/mozilla/uniffi-rs) bindings. The generated Kotlin calls the library through **JNA**, not JNI. A `UniffiLib` interface declares one method per C export of the same name, and `Native.register`/`Native.load` binds it at run time. These libraries export no `Java_*` symbols and no `JNI_OnLoad`. REA currently has no way to connect the two sides: - `inspect_android_method` on a binding method returns `"method exists but has no decompiled body (native/abstract)"`, with no library or symbol. - `project_android_application_graph`'s bridge hypotheses are a path-based Cartesian product of DEX classes and `.so` files, and the docs note this "does not identify a specific JNI binding". - JNI-style correlation (`Java_<class>_<method>`) can't work for these libraries either. The only JNI library involved is JNA's own `libjnidispatch.so`, so a JNI matcher would link every binding to JNA's dispatcher instead of to the real library. **Public example: Element X 26.09.1**, F-Droid arm64 build. It uses JNA 5.19.1 and `org.matrix.rustcomponents:sdk-android:26.08.25` at tag `v26.09.1`. Dynamic exports, read from `.dynsym`: | Library | Size | Exports | `Java_*` | `uniffi_*` | `JNI_OnLoad` | |---|---:|---:|---:|---:|---| | `libmatrix_sdk_ffi.so` | 63,058,304 | 1,875 | 0 | 1,450 | no | | `libuniffi_wysiwyg_composer.so` | 3,109,256 | 161 | 0 | 108 | no | | `libjnidispatch.so` (JNA) | 165,992 | 127 | 69 | 0 | yes | REA lists 579 methods in `org.matrix.rustcomponents.sdk.UniffiLib`, and every one of its 577 `uniffi_*`/`ffi_*` methods matches a `libmatrix_sdk_ffi.so` export by **exact name** (577/577). The APK also has per-crate `uniffi.<crate>.UniffiLib` interfaces (`matrix_sdk_crypto`, `matrix_sdk_ui`, `ruma_events`, …). The same pattern holds in a large proprietary VPN app I analysed. In aggregate, five of its Rust libraries have 0–1 `Java_*` exports each, against 41–163 `uniffi_*` exports. So the gap isn't specific to Matrix. ### Desired outcome and success criteria A static, evidence-backed binding facet. For example, `inspect_android_class` (or a dedicated tool or graph projection) would report, for an interface that extends `com.sun.jna.Library` or is passed to `Native.register`/`Native.load`: - the library-name candidates from the literal passed to JNA (`"matrix_sdk_ffi"`) and the matching `lib<name>.so` in the APK or split, each with its SHA-256; - per method, an exact-name match against that library's dynamic exports: `matched`, `unmatched`, or `ambiguous` when several libraries export the name; - explicit coverage and unknowns: computed library names, `Native.load` through helper functions, R8-renamed interfaces (UniFFI keeps the symbol names in method names, but a minifier could rename them), and JNA `Structure`/callback types; - no runtime claims: a match doesn't prove the library is loaded or the method called. Recognising the UniFFI checksum interface (`IntegrityCheckingUniffiLib`, `uniffi_*_checksum_*`) and `ffi_*_rust_future_*` helpers would be a bonus, not a requirement. ### Expected interaction with targets Read the APK, split APKs and `.so` files only. No execution. ### Verification available so far - APK: https://github.com/element-hq/element-x-android/releases/download/v26.09.1/app-fdroid-arm64-v8a-release-signed.apk. This is the binary F-Droid ships for versionCode 202609012 (reproducible build). sha256 `ceb076564298cd0aef4688ad79058b55638d196b9beb5ac47ab421d757335bf3` matches the GitHub asset digest. The signing certificate's SHA-256, `6a2fdc31…e92d47`, equals fdroiddata's `AllowedAPKSigningKeys`. - Exports were read from the ELF `.dynsym`: defined `STT_FUNC` symbols with non-local binding. - REA: `rea-agents@6.5.0`, `search-android-classes … UniffiLib`, `inspect-android-class org.matrix.rustcomponents.sdk.UniffiLib`, and `inspect-android-method … uniffi_matrix_sdk_ffi_fn_func_sdk_git_sha`. ### Alternatives considered - JNI symbol matching alone: it can't see these libraries (the table above). - Leaving it to the analyst: a 577-way name match is mechanical and exact, which is what REA's evidence model is good at. ### References #2379 (Java/JNI correlation design), #3489 (native method flags), #717 (APK roadmap).
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#1763
No description provided.