Add auto-install flow and move scripts folder

This commit is contained in:
√(noham)²
2026-08-26 00:23:17 +02:00
parent d5ef3c2fb9
commit d407221fda
4 changed files with 113 additions and 17 deletions

94
scripts/auto-install.sh Executable file
View File

@@ -0,0 +1,94 @@
#!/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"
# --- Download inject script ---
echo "[INFO] Downloading inject script..."
curl -sL \
-o "$WORKDIR/inject.sh" \
"https://raw.githubusercontent.com/$REPO/refs/heads/main/scripts/inject.sh"
chmod +x "$WORKDIR/inject.sh"
# --- 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
# --- Run inject ---
echo "[INFO] Running inject script..."
"$WORKDIR/inject.sh" "$APK_DIR"
# --- 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:*'"

124
scripts/build.sh Executable file
View File

@@ -0,0 +1,124 @@
#!/bin/bash
# Script to compile the native hooking library for Android
set -euo pipefail
PROJECT_DIR=$(cd "$(dirname "$0")/.." && pwd)
SRC_DIR="$PROJECT_DIR/src"
BUILD_DIR="$PROJECT_DIR/build"
LIBS_DIR="$PROJECT_DIR/libs"
API_LEVEL="${ANDROID_API_LEVEL:-21}"
# Qt path detection
QT_DIR="${QT_DIR:-$HOME/Qt}"
QT_VERSION="${QT_VERSION:-6.10.2}"
QT_HOST_DIR="$QT_DIR/$QT_VERSION/android_arm64_v8a"
QT_LIB_DIR="$QT_HOST_DIR/lib"
SO_NAME="librmhook.so"
# --- Auto-detect Android NDK ---
find_ndk() {
if [ -n "${ANDROID_NDK_HOME:-}" ] && [ -d "$ANDROID_NDK_HOME" ]; then
echo "$ANDROID_NDK_HOME"; return
fi
local brew_ndk
brew_ndk=$(find /opt/homebrew /usr/local -path "*/android-ndk/*/toolchains/llvm/prebuilt" -type d 2>/dev/null | head -1)
if [ -n "$brew_ndk" ]; then
echo "$(dirname "$(dirname "$(dirname "$brew_ndk")")")"; return
fi
local sdk_ndk
sdk_ndk=$(find "$HOME/Library/Android/sdk/ndk" -maxdepth 1 -type d 2>/dev/null | sort -V | tail -1)
if [ -n "$sdk_ndk" ] && [ -d "$sdk_ndk" ]; then
echo "$sdk_ndk"; return
fi
for p in /opt/android-ndk /usr/local/android-ndk "$HOME/android-ndk"; do
if [ -d "$p" ]; then echo "$p"; return; fi
done
echo ""
}
NDK_HOME="$(find_ndk)"
CC=""
if [ -n "$NDK_HOME" ]; then
CC=$(find "$NDK_HOME/toolchains/llvm/prebuilt" -type f \
-name "aarch64-linux-android${API_LEVEL}-clang" -print -quit 2>/dev/null)
fi
if [ -z "$CC" ]; then
echo "❌ aarch64-linux-android clang not found."
echo " Set ANDROID_NDK_HOME to your NDK path, or install via:"
echo " brew install --cask android-ndk"
exit 1
fi
echo "🔨 Compiling $SO_NAME..."
echo "📦 Qt path: $QT_HOST_DIR"
echo "📦 NDK: $NDK_HOME"
echo ""
# Clean and create build directories
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
# --- Step 0: Build dependencies (shadowhook) ---
echo "[0/2] Building hooking library (shadowhook)..."
"$LIBS_DIR/build_deps.sh"
# --- Step 1: Prepare Qt headers ---
echo "[1/2] Preparing Qt headers..."
if [ ! -d "$QT_HOST_DIR/include" ]; then
echo "⚠️ Qt not found at $QT_HOST_DIR/include"
echo " Install with: aqt install-qt all_os android $QT_VERSION -m qtwebsockets --outputdir $QT_DIR"
exit 1
fi
for qt_lib in \
"$QT_LIB_DIR/libQt6Core_arm64-v8a.so" \
"$QT_LIB_DIR/libQt6Network_arm64-v8a.so" \
"$QT_LIB_DIR/libQt6WebSockets_arm64-v8a.so"; do
if [ ! -f "$qt_lib" ]; then
echo "ERROR: Required Qt library not found: $qt_lib"
exit 1
fi
done
QT_INCLUDES="-I$QT_HOST_DIR/include"
for subdir in "$QT_HOST_DIR/include"/*/; do
QT_INCLUDES="$QT_INCLUDES -I$subdir"
done
echo "✅ Qt headers ready at $QT_HOST_DIR"
echo "✅ Qt libraries ready at $QT_LIB_DIR"
# --- Step 2: Compile native hooking library ---
echo "[2/2] Compiling $SO_NAME..."
# shellcheck disable=SC2086
"$CC" -shared -fPIC -O2 -std=c++17 -stdlib=libc++ -fno-exceptions -fno-rtti \
-DQT_NO_VERSION_TAGGING \
-o "$BUILD_DIR/$SO_NAME" \
"$SRC_DIR/rmhook.cpp" \
"$SRC_DIR/Config.cpp" \
$QT_INCLUDES \
-I"$LIBS_DIR/shadowhook/shadowhook/src/main/cpp/include" \
-I"$SRC_DIR" \
-L"$LIBS_DIR" -lshadowhook \
-L"$QT_LIB_DIR" \
-Wl,--no-undefined \
-Wl,-z,defs \
-l:libQt6WebSockets_arm64-v8a.so \
-l:libQt6Network_arm64-v8a.so \
-l:libQt6Core_arm64-v8a.so \
-lc++_shared \
-llog -ldl -lm \
-Wno-incompatible-pointer-types
echo ""
echo "✅ Compilation successful!"
echo "📍 Library: $BUILD_DIR/$SO_NAME ($(ls -lh "$BUILD_DIR/$SO_NAME" | awk '{print $5}'))"
echo ""
echo "🚀 To inject into the reMarkable application:"
echo " ./scripts/inject.sh"
echo ""

186
scripts/inject.sh Executable file
View File

@@ -0,0 +1,186 @@
#!/bin/bash
# Script to patch and sign the reMarkable Android APKs
set -euo pipefail
PROJECT_DIR=$(cd "$(dirname "$0")/.." && pwd)
BUILD_DIR="$PROJECT_DIR/build"
OUTPUT_DIR="$PROJECT_DIR/output"
LIBS_DIR="$PROJECT_DIR/libs"
# --- Auto-detect Android SDK build tools ---
find_build_tools() {
local sdk_root="${ANDROID_SDK_ROOT:-$HOME/Library/Android/sdk}"
local bt
bt=$(find "$sdk_root/build-tools" -maxdepth 1 -type d 2>/dev/null | sort -V | tail -1)
if [ -n "$bt" ] && [ -d "$bt" ]; then
echo "$bt"; return
fi
echo ""
}
BUILD_TOOLS="${ANDROID_SDK_BUILD_TOOLS:-$(find_build_tools)}"
if [ -z "$BUILD_TOOLS" ] || [ ! -d "$BUILD_TOOLS" ]; then
echo "❌ Android SDK build-tools not found."
echo " Set ANDROID_SDK_BUILD_TOOLS to your build-tools path."
exit 1
fi
ZIPALIGN="$BUILD_TOOLS/zipalign"
APKSIGNER="$BUILD_TOOLS/apksigner"
KEYSTORE="$PROJECT_DIR/config/rmhook.keystore"
KEYSTORE_PASS="rmhook"
KEY_ALIAS="rmhook"
# --- Portable in-place sed (GNU sed vs BSD/macOS sed take -i differently) ---
sed_inplace() {
if sed --version >/dev/null 2>&1; then
# GNU sed
sed -i "$@"
else
# BSD/macOS sed requires an explicit (possibly empty) backup suffix
sed -i '' "$@"
fi
}
usage() {
echo "Usage: $0 [apk_dir]"
echo ""
echo " apk_dir - Directory containing the split APKs (default: ~/reMarkable/app)"
echo ""
echo "Output: patched APKs in $OUTPUT_DIR/"
exit 1
}
APK_DIR="${1:-$HOME/reMarkable/app}"
echo "💉 Injecting RMHook into reMarkable APKs..."
echo "📦 APK source: $APK_DIR"
echo ""
if [ ! -f "$BUILD_DIR/librmhook.so" ]; then
echo "❌ librmhook.so not found. Run ./scripts/build.sh first."
exit 1
fi
# Clean and create output directory
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 only, no resources) ---
echo "[1/4] Patching base.apk (smali injection)..."
# Use -r (--no-res) to skip decoding/recoding resources. We only need to modify the DEX.
apktool d -r "$APK_DIR/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
# Insert System.loadLibrary("rmhook") at the very start of <clinit>
sed_inplace '/.method static constructor <clinit>()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"
echo " The <clinit> block's shape may have changed - inspect $MAIN_SMALI manually."
exit 1
fi
echo "✅ Injected System.loadLibrary(\"rmhook\") into MainActivity.<clinit>"
apktool b "$BUILD_DIR/base" -o "$BUILD_DIR/base_patched.apk"
# --- Step 2: Patch split_config.arm64_v8a.apk (add hook library) ---
echo "[2/4] Injecting ShadowHook libraries into arm64 split..."
SPLIT_ARM64="$APK_DIR/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"
# Store everything uncompressed (-0), including the native libraries.
(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/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 ""
echo "✅ Injection successful!"
echo "📍 Patched APKs in: $OUTPUT_DIR/"
ls -lh "$OUTPUT_DIR/"*.apk
echo ""
echo "🚀 To install on your reMarkable:"
echo " adb uninstall com.remarkable.mobile"
echo " adb install-multiple --no-streaming $OUTPUT_DIR/base.apk $OUTPUT_DIR/split_config.arm64_v8a.apk $OUTPUT_DIR/split_config.xxhdpi.apk"
echo " adb push rmhook.conf /sdcard/Android/data/com.remarkable.mobile/files/rmhook.conf"
echo ""
echo "🔍 To debug:"
echo " adb logcat -s 'RMHook:*'"
echo ""