mirror of
https://github.com/NohamR/RMHook-Android.git
synced 2026-10-10 18:29:42 +00:00
Harden build and injection shell scripts
This commit is contained in:
@@ -3,10 +3,25 @@ set -euo pipefail
|
|||||||
|
|
||||||
# Builds shadowhook as a static library for Android arm64.
|
# Builds shadowhook as a static library for Android arm64.
|
||||||
# Produces: libs/libshadowhook.a and libs/libshadowhook_nothing.so
|
# Produces: libs/libshadowhook.a and libs/libshadowhook_nothing.so
|
||||||
|
#
|
||||||
|
# Skips the build entirely if both outputs already exist. Set FORCE_REBUILD=1
|
||||||
|
# to rebuild anyway (e.g. after changing CFLAGS, the toolchain, or the
|
||||||
|
# shadowhook sources themselves).
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
BUILD_DIR="$PROJECT_DIR/build/deps"
|
BUILD_DIR="$PROJECT_DIR/build/deps"
|
||||||
|
|
||||||
|
OUT_DIR="$SCRIPT_DIR"
|
||||||
|
SH="$SCRIPT_DIR/shadowhook/shadowhook/src/main/cpp"
|
||||||
|
|
||||||
|
if [ "${FORCE_REBUILD:-0}" != "1" ] \
|
||||||
|
&& [ -f "$OUT_DIR/libshadowhook.a" ] \
|
||||||
|
&& [ -f "$OUT_DIR/libshadowhook_nothing.so" ]; then
|
||||||
|
echo "=== shadowhook already built, skipping (FORCE_REBUILD=1 to rebuild) ==="
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p "$BUILD_DIR"
|
mkdir -p "$BUILD_DIR"
|
||||||
|
|
||||||
# --- Auto-detect Android NDK (same logic as build.sh) ---
|
# --- Auto-detect Android NDK (same logic as build.sh) ---
|
||||||
@@ -47,81 +62,67 @@ TOOLCHAIN_DIR="$(dirname "$CC")"
|
|||||||
AR="$TOOLCHAIN_DIR/llvm-ar"
|
AR="$TOOLCHAIN_DIR/llvm-ar"
|
||||||
CFLAGS="-O2 -ffunction-sections -fdata-sections -fPIC -DANDROID -Wall -Wextra -Wno-unused-parameter -Wno-unused-function"
|
CFLAGS="-O2 -ffunction-sections -fdata-sections -fPIC -DANDROID -Wall -Wextra -Wno-unused-parameter -Wno-unused-function"
|
||||||
|
|
||||||
OUT_DIR="$SCRIPT_DIR"
|
SH_SRCS=(
|
||||||
|
"$SH/sh_elf.c"
|
||||||
|
"$SH/sh_enter.c"
|
||||||
|
"$SH/sh_hub.c"
|
||||||
|
"$SH/sh_island.c"
|
||||||
|
"$SH/sh_linker.c"
|
||||||
|
"$SH/sh_recorder.c"
|
||||||
|
"$SH/sh_safe.c"
|
||||||
|
"$SH/sh_switch.c"
|
||||||
|
"$SH/sh_task.c"
|
||||||
|
"$SH/sh_xdl.c"
|
||||||
|
"$SH/shadowhook.c"
|
||||||
|
"$SH/arch/arm64/sh_a64.c"
|
||||||
|
"$SH/arch/arm64/sh_inst.c"
|
||||||
|
"$SH/arch/arm64/sh_glue.S"
|
||||||
|
"$SH/common/bytesig.c"
|
||||||
|
"$SH/common/sh_errno.c"
|
||||||
|
"$SH/common/sh_log.c"
|
||||||
|
"$SH/common/sh_ref.c"
|
||||||
|
"$SH/common/sh_trampo.c"
|
||||||
|
"$SH/common/sh_util.c"
|
||||||
|
"$SH/third_party/xdl/xdl.c"
|
||||||
|
"$SH/third_party/xdl/xdl_iterate.c"
|
||||||
|
"$SH/third_party/xdl/xdl_linker.c"
|
||||||
|
"$SH/third_party/xdl/xdl_lzma.c"
|
||||||
|
"$SH/third_party/xdl/xdl_util.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
SH_INCLUDES=(
|
||||||
|
"-I$SH"
|
||||||
|
"-I$SH/include"
|
||||||
|
"-I$SH/arch/arm64"
|
||||||
|
"-I$SH/common"
|
||||||
|
"-I$SH/third_party/xdl"
|
||||||
|
"-I$SH/third_party/bsd"
|
||||||
|
"-I$SH/third_party/lss"
|
||||||
|
)
|
||||||
|
|
||||||
|
NOTHING_SRC="$SH/nothing/sh_nothing.c"
|
||||||
|
|
||||||
echo "=== Building shadowhook (arm64-v8a) ==="
|
echo "=== Building shadowhook (arm64-v8a) ==="
|
||||||
|
|
||||||
SH="$SCRIPT_DIR/shadowhook/shadowhook/src/main/cpp"
|
SH_OBJS=()
|
||||||
|
for src in "${SH_SRCS[@]}"; do
|
||||||
SH_SRCS="
|
|
||||||
$SH/sh_elf.c
|
|
||||||
$SH/sh_enter.c
|
|
||||||
$SH/sh_hub.c
|
|
||||||
$SH/sh_island.c
|
|
||||||
$SH/sh_linker.c
|
|
||||||
$SH/sh_recorder.c
|
|
||||||
$SH/sh_safe.c
|
|
||||||
$SH/sh_switch.c
|
|
||||||
$SH/sh_task.c
|
|
||||||
$SH/sh_xdl.c
|
|
||||||
$SH/shadowhook.c
|
|
||||||
$SH/arch/arm64/sh_a64.c
|
|
||||||
$SH/arch/arm64/sh_inst.c
|
|
||||||
$SH/arch/arm64/sh_glue.S
|
|
||||||
$SH/common/bytesig.c
|
|
||||||
$SH/common/sh_errno.c
|
|
||||||
$SH/common/sh_log.c
|
|
||||||
$SH/common/sh_ref.c
|
|
||||||
$SH/common/sh_trampo.c
|
|
||||||
$SH/common/sh_util.c
|
|
||||||
$SH/third_party/xdl/xdl.c
|
|
||||||
$SH/third_party/xdl/xdl_iterate.c
|
|
||||||
$SH/third_party/xdl/xdl_linker.c
|
|
||||||
$SH/third_party/xdl/xdl_lzma.c
|
|
||||||
$SH/third_party/xdl/xdl_util.c
|
|
||||||
"
|
|
||||||
|
|
||||||
SH_INCLUDES="
|
|
||||||
-I$SH
|
|
||||||
-I$SH/include
|
|
||||||
-I$SH/arch/arm64
|
|
||||||
-I$SH/common
|
|
||||||
-I$SH/third_party/xdl
|
|
||||||
-I$SH/third_party/bsd
|
|
||||||
-I$SH/third_party/lss
|
|
||||||
"
|
|
||||||
|
|
||||||
SH_OBJS=""
|
|
||||||
for src in $SH_SRCS; do
|
|
||||||
[ -z "$src" ] && continue
|
|
||||||
src=$(echo "$src" | xargs)
|
|
||||||
if [ ! -f "$src" ]; then
|
if [ ! -f "$src" ]; then
|
||||||
echo "ERROR: shadowhook source not found: $src"
|
echo "ERROR: shadowhook source not found: $src"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
basename=$(echo "$src" | sed "s|$SH/||" | tr '/' '_')
|
rel="${src#"$SH"/}"
|
||||||
obj="$BUILD_DIR/sh_${basename%.c}.o"
|
flat="$(echo "$rel" | tr '/' '_')"
|
||||||
obj="${obj%.S.o}.o"
|
obj="$BUILD_DIR/sh_${flat%.*}.o"
|
||||||
|
|
||||||
if [[ "$src" == *.S ]]; then
|
"$CC" $CFLAGS "${SH_INCLUDES[@]}" -c "$src" -o "$obj"
|
||||||
"$CC" $CFLAGS $SH_INCLUDES -c "$src" -o "$obj"
|
SH_OBJS+=("$obj")
|
||||||
else
|
|
||||||
"$CC" $CFLAGS $SH_INCLUDES -c "$src" -o "$obj"
|
|
||||||
fi
|
|
||||||
SH_OBJS="$SH_OBJS $obj"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -z "$SH_OBJS" ]; then
|
"$AR" rcs "$OUT_DIR/libshadowhook.a" "${SH_OBJS[@]}"
|
||||||
echo "ERROR: shadowhook produced no object files."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
"$AR" rcs "$OUT_DIR/libshadowhook.a" $SH_OBJS
|
|
||||||
SH_SIZE=$(wc -c < "$OUT_DIR/libshadowhook.a" 2>/dev/null || echo "unknown")
|
SH_SIZE=$(wc -c < "$OUT_DIR/libshadowhook.a" 2>/dev/null || echo "unknown")
|
||||||
echo " Built $OUT_DIR/libshadowhook.a ($SH_SIZE bytes)"
|
echo " Built $OUT_DIR/libshadowhook.a ($SH_SIZE bytes)"
|
||||||
|
|
||||||
NOTHING_SRC="$SH/nothing/sh_nothing.c"
|
|
||||||
if [ ! -f "$NOTHING_SRC" ]; then
|
if [ ! -f "$NOTHING_SRC" ]; then
|
||||||
echo "ERROR: ShadowHook companion source not found: $NOTHING_SRC"
|
echo "ERROR: ShadowHook companion source not found: $NOTHING_SRC"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -133,4 +134,4 @@ fi
|
|||||||
-Wl,--strip-all -Wl,--as-needed -Wl,--hash-style=sysv \
|
-Wl,--strip-all -Wl,--as-needed -Wl,--hash-style=sysv \
|
||||||
-Wl,--build-id=none \
|
-Wl,--build-id=none \
|
||||||
-o "$OUT_DIR/libshadowhook_nothing.so" "$NOTHING_SRC"
|
-o "$OUT_DIR/libshadowhook_nothing.so" "$NOTHING_SRC"
|
||||||
echo " Built $OUT_DIR/libshadowhook_nothing.so"
|
echo " Built $OUT_DIR/libshadowhook_nothing.so"
|
||||||
@@ -95,6 +95,7 @@ echo "✅ Qt libraries ready at $QT_LIB_DIR"
|
|||||||
# --- Step 2: Compile native hooking library ---
|
# --- Step 2: Compile native hooking library ---
|
||||||
echo "[2/2] Compiling $SO_NAME..."
|
echo "[2/2] Compiling $SO_NAME..."
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
"$CC" -shared -fPIC -O2 -std=c++17 -stdlib=libc++ -fno-exceptions -fno-rtti \
|
"$CC" -shared -fPIC -O2 -std=c++17 -stdlib=libc++ -fno-exceptions -fno-rtti \
|
||||||
-DQT_NO_VERSION_TAGGING \
|
-DQT_NO_VERSION_TAGGING \
|
||||||
-o "$BUILD_DIR/$SO_NAME" \
|
-o "$BUILD_DIR/$SO_NAME" \
|
||||||
@@ -120,4 +121,4 @@ echo "📍 Library: $BUILD_DIR/$SO_NAME ($(ls -lh "$BUILD_DIR/$SO_NAME" | awk '{
|
|||||||
echo ""
|
echo ""
|
||||||
echo "🚀 To inject into the reMarkable application:"
|
echo "🚀 To inject into the reMarkable application:"
|
||||||
echo " ./script/inject.sh"
|
echo " ./script/inject.sh"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -33,6 +33,17 @@ KEYSTORE="$PROJECT_DIR/config/rmhook.keystore"
|
|||||||
KEYSTORE_PASS="rmhook"
|
KEYSTORE_PASS="rmhook"
|
||||||
KEY_ALIAS="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() {
|
usage() {
|
||||||
echo "Usage: $0 [apk_dir]"
|
echo "Usage: $0 [apk_dir]"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -56,6 +67,8 @@ fi
|
|||||||
# Clean and create output directory
|
# Clean and create output directory
|
||||||
rm -rf "$OUTPUT_DIR"
|
rm -rf "$OUTPUT_DIR"
|
||||||
mkdir -p "$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) ---
|
# --- Step 1: Decompile and patch base.apk (smali injection only, no resources) ---
|
||||||
echo "[1/4] Patching base.apk (smali injection)..."
|
echo "[1/4] Patching base.apk (smali injection)..."
|
||||||
@@ -69,7 +82,7 @@ if [ ! -f "$MAIN_SMALI" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Insert System.loadLibrary("rmhook") at the very start of <clinit>
|
# Insert System.loadLibrary("rmhook") at the very start of <clinit>
|
||||||
sed -i '' '/.method static constructor <clinit>()V/{
|
sed_inplace '/.method static constructor <clinit>()V/{
|
||||||
n
|
n
|
||||||
/.locals/{
|
/.locals/{
|
||||||
a\
|
a\
|
||||||
@@ -80,6 +93,12 @@ a\
|
|||||||
}
|
}
|
||||||
}' "$MAIN_SMALI"
|
}' "$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>"
|
echo "✅ Injected System.loadLibrary(\"rmhook\") into MainActivity.<clinit>"
|
||||||
|
|
||||||
apktool b "$BUILD_DIR/base" -o "$BUILD_DIR/base_patched.apk"
|
apktool b "$BUILD_DIR/base" -o "$BUILD_DIR/base_patched.apk"
|
||||||
@@ -100,8 +119,8 @@ cp "$LIBS_DIR/libshadowhook_nothing.so" "$BUILD_DIR/split_arm64/lib/arm64-v8a/"
|
|||||||
|
|
||||||
rm -rf "$BUILD_DIR/split_arm64/META-INF"
|
rm -rf "$BUILD_DIR/split_arm64/META-INF"
|
||||||
|
|
||||||
(cd "$BUILD_DIR/split_arm64" && zip -q -r -0 "$BUILD_DIR/split_arm64_raw.apk" . -x "*.so")
|
# Store everything uncompressed (-0), including the native libraries.
|
||||||
(cd "$BUILD_DIR/split_arm64" && zip -q -r "$BUILD_DIR/split_arm64_raw.apk" lib/)
|
(cd "$BUILD_DIR/split_arm64" && zip -q -r -0 "$BUILD_DIR/split_arm64_raw.apk" .)
|
||||||
|
|
||||||
# --- Step 3: Align APKs ---
|
# --- Step 3: Align APKs ---
|
||||||
echo "[3/4] Aligning APKs..."
|
echo "[3/4] Aligning APKs..."
|
||||||
@@ -160,7 +179,8 @@ echo ""
|
|||||||
echo "🚀 To install on your reMarkable:"
|
echo "🚀 To install on your reMarkable:"
|
||||||
echo " adb uninstall com.remarkable.mobile"
|
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 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 ""
|
||||||
echo "🔍 To debug:"
|
echo "🔍 To debug:"
|
||||||
echo " adb logcat -s 'RMHook:*'"
|
echo " adb logcat -s 'RMHook:*'"
|
||||||
echo ""
|
echo ""
|
||||||
Reference in New Issue
Block a user