RMHook-Android

August 25, 2026 · View on GitHub

A native library injection tweak for the reMarkable Android app, enabling connection to self-hosted rmfakecloud servers.

Overview

RMHook-Android intercepts the reMarkable Android app's network calls at runtime and redirects them to your own rmfakecloud server. Unlike binary patching approaches, this requires no modification of rmfakecloud — the redirection is done transparently at the network layer, just like the iOS/macOS/Windows versions of RMHook.

Other platforms

Features

  • Network request interception and redirection
  • WebSocket connection patching
  • Runtime configuration via rmhook.conf
  • No modification of rmfakecloud required

Compatibility

Tested and working on:

  • reMarkable Android app 3.27.2 (build 1461), split into base.apk, split_config.arm64_v8a.apk, split_config.xxhdpi.apk (Qt 6, arm64-v8a)

Only arm64-v8a is supported (the hook library and PLT hooks are ARM64-specific).

Installation and usage

⚠️ For legal reasons, this repository does not include the reMarkable app. However, the latest compiled .so files are available in the Releases section.

Auto installation

Run in a terminal: Requirements: apktool, adb, Android SDK build-tools (zipalign, apksigner), and keytool must be installed.

bash <(curl -sL https://raw.githubusercontent.com/NohamR/RMHook-Android/refs/heads/main/scripts/auto-install.sh)

This will download the pre-built libraries, pull the APK splits from your device, inject the hook, and install the patched app.

Manual installation

Step 1: Pull the APK splits from your device

# List the paths of the installed splits
adb shell pm path com.remarkable.mobile

# Pull each file (replace the paths with the ones returned above)
mkdir -p ~/reMarkable/app && cd ~/reMarkable/app
adb pull /data/app/~~XXXXX==/com.remarkable.mobile-YYYYY==/base.apk
adb pull /data/app/~~XXXXX==/com.remarkable.mobile-YYYYY==/split_config.arm64_v8a.apk
adb pull /data/app/~~XXXXX==/com.remarkable.mobile-YYYYY==/split_config.xxhdpi.apk

You should now have three files in ~/reMarkable/app/:

  • base.apk (Java/Kotlin bytecode and resources)
  • split_config.arm64_v8a.apk (native libraries for ARM64 devices (Qt, reMarkable's xofm-libs))
  • split_config.xxhdpi.apk (graphics resources)

Build

./scripts/build.sh

Inject & sign

./scripts/inject.sh [apk_dir]   # apk_dir defaults to ~/reMarkable/app

Patches base.apk's smali to loadLibrary("rmhook"), bundles librmhook.so + libshadowhook_nothing.so into the arm64 split, aligns and signs everything and puts the result in output/.

Install

adb uninstall com.remarkable.mobile
adb install-multiple --no-streaming output/base.apk output/split_config.arm64_v8a.apk output/split_config.xxhdpi.apk

Configuration

Runtime configuration is loaded from rmhook.conf in the app's external files directory. If the file is missing or invalid, RMHook falls back to remarkable.example.com:443.

Push a rmhook.conf (see rmhook.conf.example) to the app's external files directory on the device:

host=example.com
port=443
adb push rmhook.conf /sdcard/Android/data/com.remarkable.mobile/files/rmhook.conf

Restart the app after changing the file. The file is read once during startup. rmhook.conf.example is provided as a template.

Building

1. Install Qt for Android

Qt headers and libraries are required at compile time (symbols are resolved at runtime via PLT hooking). Install them using aqtinstall:

# Create a Python virtual environment and install aqtinstall
python3 -m venv aqt_venv
source aqt_venv/bin/activate
pip install aqtinstall

# Install Qt 6.10.2 for Android (headers + libs)
aqt install-qt all_os android 6.10.2 android_arm64_v8a -m qtwebsockets --outputdir ~/Qt

This installs to ~/Qt/6.10.2/android_arm64_v8a/.

2. Set environment variables

Ensure the following are set or auto-detected:

  • ANDROID_NDK_HOME — Android NDK path
  • ANDROID_SDK_BUILD_TOOLS — Android SDK build-tools path (defaults to ~/Library/Android/sdk)
  • QT_DIR / QT_VERSION — Qt installation path and version

3. Compile

./scripts/build.sh

Debugging

Stream the device logs to see output from the hooks:

adb logcat -s 'RMHook:*'

How it works

RMHook-Android uses ShadowHook to hook Qt framework functions via PLT hooking at runtime:

  1. QNetworkAccessManager::createRequest - Intercepts HTTP/HTTPS requests
  2. QWebSocket::open - Patches WebSocket connections

When the app attempts to connect to reMarkable's servers (e.g., internal.cloud.remarkable.com), the hooks redirect these requests to your configured host and port.

Implementation notes

  • librmhook.so compiles as C++17 and includes Qt headers (QUrl, QString, QNetworkRequest, QWebSocket) directly — no manual ABI helpers or inline assembly needed.
  • ShadowHook handles memory protection, trampoline allocation, and instruction relocation automatically. Qt symbols are resolved with dlsym() after the Qt libraries are loaded, then passed to ShadowHook's direct-address API.
  • The hook clones each QNetworkRequest, rewrites the host and port in the QUrl, and passes the modified request to the original Qt function. This avoids modifying const data directly.
  • Configuration is loaded from the app-specific external files directory at startup via JNI. Host/port can be changed without rebuilding.
  • The QString for the override host is built from the config file. Qt's copy-on-write means every setHost() call just bumps the refcount of the shared data, so there's no per-request allocation.
  • ShadowHook is built as a static library and linked into librmhook.so. RMHook starts its hook thread from JNI_OnLoad, after shared-library constructors have completed, to avoid constructor-order races.
  • ShadowHook's libshadowhook_nothing.so companion is packaged beside librmhook.so; omitting it causes shadowhook_init() to fail during linker initialization.

Troubleshooting

Build fails

  • Ensure the Android NDK and SDK build-tools are installed and the environment variables are set
  • Verify Qt is installed at the expected path (~/Qt/6.10.2/android_arm64_v8a/)

App crashes on launch

  • Check adb logcat -s 'RMHook:*' for error messages
  • Ensure all three APK splits were installed correctly
  • Verify the keystore was generated and the APKs are properly signed

Document sync issues

  • Ensure your rmfakecloud server is running and accessible
  • Verify the host and port in rmhook.conf are correct

Credits

License

This project is licensed under the MIT License. See LICENSE for details.

Disclaimer

This project is not affiliated with, endorsed by, or sponsored by reMarkable AS. Use at your own risk. This tool modifies the reMarkable Android application and may violate the application's terms of service.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.