#!/usr/bin/env bash REPO="NohamR/RMHook-Android" WORKDIR="/tmp/rmhook" set -euo pipefail # --- Check dependencies --- echo "[INFO] Checking dependencies..." MISSING=() for cmd in adb apktool keytool; do command -v "$cmd" >/dev/null 2>&1 || MISSING+=("$cmd") done # Check Android SDK build-tools (zipalign + apksigner) SDK_ROOT="${ANDROID_SDK_ROOT:-$HOME/Library/Android/sdk}" BUILD_TOOLS="$(find "$SDK_ROOT/build-tools" -maxdepth 1 -type d 2>/dev/null | sort -V | tail -1)" if [ -z "$BUILD_TOOLS" ] || [ ! -d "$BUILD_TOOLS" ]; then MISSING+=("Android SDK build-tools (zipalign, apksigner)") fi if [ ${#MISSING[@]} -gt 0 ]; then echo "❌ Missing required tools:" for m in "${MISSING[@]}"; do echo " - $m"; done echo "" echo "Install with:" echo " brew install apktool android-platform-tools" echo " # Android SDK build-tools via Android Studio SDK Manager" exit 1 fi export ANDROID_SDK_BUILD_TOOLS="$BUILD_TOOLS" # --- Setup workspace --- echo "[INFO] Setting up workspace..." rm -rf "$WORKDIR" mkdir -p "$WORKDIR/build" "$WORKDIR/libs" "$WORKDIR/config" "$WORKDIR/output" # --- Download .so files from releases --- echo "[INFO] Downloading librmhook.so..." curl -sL \ -o "$WORKDIR/build/librmhook.so" \ "https://github.com/$REPO/releases/latest/download/librmhook.so" echo "[INFO] Downloading libshadowhook_nothing.so..." curl -sL \ -o "$WORKDIR/libs/libshadowhook_nothing.so" \ "https://github.com/$REPO/releases/latest/download/libshadowhook_nothing.so" # --- Pull APK splits from device --- APK_DIR="$HOME/reMarkable/app" mkdir -p "$APK_DIR" echo "[INFO] Detecting reMarkable app on device..." PKG_PATHS="$(adb shell pm path com.remarkable.mobile 2>/dev/null || true)" if [ -z "$PKG_PATHS" ]; then echo "❌ reMarkable app not found on device. Install it from the Play Store first." exit 1 fi echo "[INFO] Pulling APK splits..." while IFS= read -r line; do APK_PATH="${line#package:}" APK_NAME="$(basename "$APK_PATH")" echo " Pulling $APK_NAME..." adb pull "$APK_PATH" "$APK_DIR/$APK_NAME" 2>/dev/null done <<< "$PKG_PATHS" if [ ! -f "$APK_DIR/base.apk" ]; then echo "❌ Failed to pull base.apk" exit 1 fi # --- Inject RMHook into APKs --- APK_DIR_INJECT="$APK_DIR" BUILD_DIR="$WORKDIR/build" OUTPUT_DIR="$WORKDIR/output" LIBS_DIR="$WORKDIR/libs" KEYSTORE="$WORKDIR/config/rmhook.keystore" KEYSTORE_PASS="rmhook" KEY_ALIAS="rmhook" ZIPALIGN="$BUILD_TOOLS/zipalign" APKSIGNER="$BUILD_TOOLS/apksigner" # Portable in-place sed (GNU vs BSD/macOS) sed_inplace() { if sed --version >/dev/null 2>&1; then sed -i "$@" else sed -i '' "$@" fi } echo "" echo "[INFO] Injecting RMHook into reMarkable APKs..." rm -rf "$OUTPUT_DIR" mkdir -p "$OUTPUT_DIR" rm -rf "$BUILD_DIR/base" "$BUILD_DIR/split_arm64" "$BUILD_DIR/split_xxhdpi" rm -f "$BUILD_DIR"/*.apk # --- Step 1: Decompile and patch base.apk (smali injection) --- echo "[1/4] Patching base.apk (smali injection)..." apktool d -r "$APK_DIR_INJECT/base.apk" -o "$BUILD_DIR/base" -f MAIN_SMALI="$BUILD_DIR/base/smali/com/remarkable/mobile/MainActivity.smali" if [ ! -f "$MAIN_SMALI" ]; then echo "❌ MainActivity.smali not found" exit 1 fi sed_inplace '/.method static constructor ()V/{ n /.locals/{ a\ \ const-string v0, "rmhook"\ \ invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V } }' "$MAIN_SMALI" if ! grep -q 'invoke-static {v0}, Ljava/lang/System;->loadLibrary' "$MAIN_SMALI"; then echo "❌ Failed to inject loadLibrary(\"rmhook\") into MainActivity.smali" exit 1 fi echo "✅ Injected System.loadLibrary(\"rmhook\") into MainActivity." apktool b "$BUILD_DIR/base" -o "$BUILD_DIR/base_patched.apk" # --- Step 2: Inject libraries into arm64 split --- echo "[2/4] Injecting ShadowHook libraries into arm64 split..." SPLIT_ARM64="$APK_DIR_INJECT/split_config.arm64_v8a.apk" if [ ! -f "$SPLIT_ARM64" ]; then echo "❌ $SPLIT_ARM64 not found" exit 1 fi mkdir -p "$BUILD_DIR/split_arm64" unzip -q "$SPLIT_ARM64" -d "$BUILD_DIR/split_arm64" cp "$BUILD_DIR/librmhook.so" "$BUILD_DIR/split_arm64/lib/arm64-v8a/" cp "$LIBS_DIR/libshadowhook_nothing.so" "$BUILD_DIR/split_arm64/lib/arm64-v8a/" rm -rf "$BUILD_DIR/split_arm64/META-INF" (cd "$BUILD_DIR/split_arm64" && zip -q -r -0 "$BUILD_DIR/split_arm64_raw.apk" .) # --- Step 3: Align APKs --- echo "[3/4] Aligning APKs..." "$ZIPALIGN" -p -f 4 "$BUILD_DIR/base_patched.apk" "$BUILD_DIR/base_aligned.apk" "$ZIPALIGN" -p -f 4 "$BUILD_DIR/split_arm64_raw.apk" "$BUILD_DIR/split_arm64_aligned.apk" SPLIT_XXHDPI="$APK_DIR_INJECT/split_config.xxhdpi.apk" if [ -f "$SPLIT_XXHDPI" ]; then mkdir -p "$BUILD_DIR/split_xxhdpi" unzip -q "$SPLIT_XXHDPI" -d "$BUILD_DIR/split_xxhdpi" rm -rf "$BUILD_DIR/split_xxhdpi/META-INF" (cd "$BUILD_DIR/split_xxhdpi" && zip -q -r -0 "$BUILD_DIR/split_xxhdpi_raw.apk" .) "$ZIPALIGN" -p -f 4 "$BUILD_DIR/split_xxhdpi_raw.apk" "$BUILD_DIR/split_xxhdpi_aligned.apk" fi # --- Step 4: Sign all APKs --- echo "[4/4] Signing APKs..." if [ ! -f "$KEYSTORE" ]; then mkdir -p "$(dirname "$KEYSTORE")" echo "🔑 Generating signing keystore..." keytool -genkeypair -v \ -keystore "$KEYSTORE" \ -alias "$KEY_ALIAS" \ -keyalg RSA -keysize 2048 \ -validity 10000 \ -storepass "$KEYSTORE_PASS" \ -keypass "$KEYSTORE_PASS" \ -dname "CN=RMHook, OU=Dev, O=RMHook, L=Unknown, ST=Unknown, C=US" \ 2>/dev/null fi sign_apk() { local input="$1" local output="$2" "$APKSIGNER" sign \ --ks "$KEYSTORE" \ --ks-pass "pass:$KEYSTORE_PASS" \ --ks-key-alias "$KEY_ALIAS" \ --key-pass "pass:$KEYSTORE_PASS" \ --out "$output" \ "$input" } sign_apk "$BUILD_DIR/base_aligned.apk" "$OUTPUT_DIR/base.apk" sign_apk "$BUILD_DIR/split_arm64_aligned.apk" "$OUTPUT_DIR/split_config.arm64_v8a.apk" if [ -f "$BUILD_DIR/split_xxhdpi_aligned.apk" ]; then sign_apk "$BUILD_DIR/split_xxhdpi_aligned.apk" "$OUTPUT_DIR/split_config.xxhdpi.apk" fi echo "✅ Injection successful!" # --- Install --- echo "[INFO] Installing patched APKs..." adb uninstall com.remarkable.mobile 2>/dev/null || true adb install-multiple --no-streaming "$WORKDIR/output/base.apk" "$WORKDIR/output/split_config.arm64_v8a.apk" "$WORKDIR/output/split_config.xxhdpi.apk" echo "" echo "✅ Done! RMHook is installed on your reMarkable." echo "" echo "📋 Next steps:" echo " 1. Open the reMarkable app" echo " 2. Configure your rmfakecloud host and port" echo "" echo "🔍 To debug:" echo " adb logcat -s 'RMHook:*'"