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
- RMHook: macOS Desktop
- RMHook-Win: Windows Desktop
- RMHook-iOS: iOS
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 pathANDROID_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:
- QNetworkAccessManager::createRequest - Intercepts HTTP/HTTPS requests
- 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.socompiles 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 theQUrl, 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
QStringfor the override host is built from the config file. Qt's copy-on-write means everysetHost()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 fromJNI_OnLoad, after shared-library constructors have completed, to avoid constructor-order races. - ShadowHook's
libshadowhook_nothing.socompanion is packaged besidelibrmhook.so; omitting it causesshadowhook_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.confare correct
Credits
- xovi-rmfakecloud: asivery/xovi-rmfakecloud - Original hooking information
- rmfakecloud: ddvk/rmfakecloud - Self-hosted reMarkable cloud
- ShadowHook: bytedance/android-inline-hook - Inline hook library for intercepting Qt function calls
- Dapitch666: dapitch666 - Initial proof-of-concept for hooking the reMarkable Android app
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.