A native library injection tweak for the reMarkable Android app, enabling connection to self-hosted rmfakecloud servers.
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.
- RMHook: macOS Desktop
- RMHook-Win: Windows Desktop
- RMHook-iOS: iOS
- Network request interception and redirection
- WebSocket connection patching
- Runtime configuration via
rmhook.conf - No modification of rmfakecloud required
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).
.so files are available in the Releases section.
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.
# 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.apkYou 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)
./scripts/build.sh./scripts/inject.sh [apk_dir] # apk_dir defaults to ~/reMarkable/appPatches 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/.
adb uninstall com.remarkable.mobile
adb install-multiple --no-streaming output/base.apk output/split_config.arm64_v8a.apk output/split_config.xxhdpi.apkRuntime 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.confRestart the app after changing the file. The file is read once during startup. rmhook.conf.example is provided as a template.
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 ~/QtThis installs to ~/Qt/6.10.2/android_arm64_v8a/.
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
./scripts/build.shStream the device logs to see output from the hooks:
adb logcat -s 'RMHook:*'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.
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.
- 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/)
- 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
- Ensure your rmfakecloud server is running and accessible
- Verify the host and port in
rmhook.confare correct
- 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
This project is licensed under the MIT License. See LICENSE for details.
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.
Contributions are welcome! Please feel free to submit issues or pull requests.

