Files
workphone-sdk/sdk/scripts/inject_frida_gadget.sh

197 lines
6.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# inject_frida_gadget.sh — 免 Root Frida Gadget 注入微信 APK
#
# 用法:
# ./inject_frida_gadget.sh <wechat.apk> [output_dir]
#
# 前置:
# brew install apktool # APK 拆包/打包
# pip install lief # ELF 注入
# 需有 Java keytool + jarsignermacOS 自带)
#
# 流程:
# 1. apktool 解包微信 APK
# 2. 下载对应架构的 frida-gadget.so
# 3. 用 LIEF 将 gadget 注入微信的 native library
# 4. 写入 gadget 配置listen 0.0.0.0 随机端口)
# 5. apktool 重新打包
# 6. 签名debug 签名即可)
# 7. 输出可安装的 APK
#
set -euo pipefail
FRIDA_VERSION="${FRIDA_VERSION:-16.5.9}"
ARCH="${ARCH:-arm64}"
LISTEN_HOST="${LISTEN_HOST:-0.0.0.0}"
LISTEN_PORT="${LISTEN_PORT:-0}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
die() { echo -e "${RED}[✗]${NC} $*" >&2; exit 1; }
APK_PATH="${1:-}"
OUTPUT_DIR="${2:-./output}"
[ -z "$APK_PATH" ] && die "用法: $0 <wechat.apk> [output_dir]"
[ -f "$APK_PATH" ] || die "APK 不存在: $APK_PATH"
command -v apktool >/dev/null || die "apktool 未安装brew install apktool"
command -v python3 >/dev/null || die "python3 未安装"
python3 -c "import lief" 2>/dev/null || die "lief 未安装pip install lief"
WORK_DIR=$(mktemp -d)
trap "rm -rf '$WORK_DIR'" EXIT
log "工作目录: $WORK_DIR"
log "APK: $APK_PATH"
# ── Step 1: apktool 解包 ──
log "Step 1/7: 解包 APK..."
apktool d -f -o "$WORK_DIR/unpacked" "$APK_PATH" --no-res 2>/dev/null || \
apktool d -f -o "$WORK_DIR/unpacked" "$APK_PATH"
log "解包完成"
# ── Step 2: 下载 frida-gadget ──
GADGET_ARCH_MAP_arm64="arm64"
GADGET_ARCH_MAP_arm="arm"
GADGET_ARCH_MAP_x86="x86"
GADGET_ARCH_MAP_x86_64="x86_64"
GADGET_URL="https://github.com/AKA-L/frida-gadget-fix/releases/download/${FRIDA_VERSION}/frida-gadget-${FRIDA_VERSION}-android-${ARCH}.so.xz"
GADGET_FILE="$WORK_DIR/frida-gadget-${ARCH}.so"
if [ -f "$GADGET_FILE" ]; then
log "Step 2/7: Gadget 已存在,跳过下载"
else
log "Step 2/7: 下载 frida-gadget ${FRIDA_VERSION} (${ARCH})..."
curl -sL "$GADGET_URL" -o "$WORK_DIR/gadget.so.xz" || {
GADGET_URL="https://github.com/AKA-L/frida-gadget-fix/releases/download/${FRIDA_VERSION}/frida-gadget-${FRIDA_VERSION}-android-${ARCH}.so.xz"
warn "主源失败,尝试备用源..."
curl -sL "$GADGET_URL" -o "$WORK_DIR/gadget.so.xz" || die "下载 frida-gadget 失败"
}
xz -d "$WORK_DIR/gadget.so.xz"
mv "$WORK_DIR/gadget.so" "$GADGET_FILE"
log "下载完成: $(du -h "$GADGET_FILE" | cut -f1)"
fi
# ── Step 3: LIEF 注入 gadget ──
LIB_DIR="$WORK_DIR/unpacked/lib/${ARCH}"
[ -d "$LIB_DIR" ] || {
if [ "$ARCH" = "arm64" ] && [ -d "$WORK_DIR/unpacked/lib/arm64-v8a" ]; then
LIB_DIR="$WORK_DIR/unpacked/lib/arm64-v8a"
elif [ "$ARCH" = "arm" ] && [ -d "$WORK_DIR/unpacked/lib/armeabi-v7a" ]; then
LIB_DIR="$WORK_DIR/unpacked/lib/armeabi-v7a"
else
die "未找到 lib/${ARCH} 目录,当前有: $(ls "$WORK_DIR/unpacked/lib/" 2>/dev/null || echo '无')"
fi
}
log "Step 3/7: LIEF 注入 Gadget..."
TARGET_SO=$(find "$LIB_DIR" -name "*.so" -not -name "libfrida*" -not -name "libgadget*" | head -1)
[ -z "$TARGET_SO" ] && die "未找到可注入的 .so 文件"
TARGET_NAME=$(basename "$TARGET_SO")
log " 目标 so: $TARGET_NAME"
cp "$GADGET_FILE" "$LIB_DIR/libgadget.so"
python3 << PYEOF
import lief
import sys
target_path = "$TARGET_SO"
binary = lief.parse(target_path)
if binary is None:
print("LIEF 解析失败: " + target_path)
sys.exit(1)
existing = [str(lib) for lib in binary.libraries]
if "libgadget.so" in existing:
print("libgadget.so 已存在于 NEEDED 中,跳过")
else:
binary.add_library("libgadget.so")
print("已添加 libgadget.so 到 NEEDED")
binary.write(target_path)
print("LIEF 注入完成: " + target_path)
PYEOF
log " LIEF 注入完成"
# ── Step 4: 写入 gadget 配置 ──
if [ "$LISTEN_PORT" = "0" ]; then
LISTEN_PORT=$((RANDOM % 50000 + 10000))
fi
GADGET_CONFIG='{
"interaction": {
"type": "listen",
"address": "'"$LISTEN_HOST"'",
"port": '"$LISTEN_PORT"',
"on_port_conflict": "pick-next",
"on_load": "resume"
}
}'
CONFIG_SO_NAME="libgadget.config.so"
echo "$GADGET_CONFIG" > "$LIB_DIR/$CONFIG_SO_NAME"
log "Step 4/7: Gadget 配置写入 (port=$LISTEN_PORT)"
log " 配置: $GADGET_CONFIG"
# ── Step 5: apktool 重新打包 ──
log "Step 5/7: 重新打包..."
OUTPUT_UNSIGNED="$WORK_DIR/wechat-gadget-unsigned.apk"
apktool b -o "$OUTPUT_UNSIGNED" "$WORK_DIR/unpacked" 2>/dev/null || \
apktool b -o "$OUTPUT_UNSIGNED" "$WORK_DIR/unpacked"
log "打包完成"
# ── Step 6: 签名 ──
log "Step 6/7: 签名..."
KEYSTORE="$WORK_DIR/debug.keystore"
keytool -genkey -v -keystore "$KEYSTORE" -alias debug \
-keyalg RSA -keysize 2048 -validity 10000 \
-storepass android -keypass android \
-dname "CN=Debug,OU=Debug,O=Debug,L=Debug,S=Debug,C=CN" \
2>/dev/null
OUTPUT_SIGNED="$WORK_DIR/wechat-gadget-signed.apk"
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
-keystore "$KEYSTORE" -storepass android -keypass android \
-signedjar "$OUTPUT_SIGNED" "$OUTPUT_UNSIGNED" debug \
2>/dev/null
log "签名完成"
# ── Step 7: 输出 ──
mkdir -p "$OUTPUT_DIR"
FINAL_APK="$OUTPUT_DIR/wechat-frida-gadget.apk"
cp "$OUTPUT_SIGNED" "$FINAL_APK"
log "Step 7/7: 输出完成"
echo ""
echo "============================================"
echo " 免 Root Frida Gadget 注入完成"
echo "============================================"
echo " 输出 APK: $FINAL_APK"
echo " 大小: $(du -h "$FINAL_APK" | cut -f1)"
echo " Gadget 端口: $LISTEN_PORT"
echo " Gadget 地址: $LISTEN_HOST:$LISTEN_PORT"
echo ""
echo " 安装到设备:"
echo " adb install -r '$FINAL_APK'"
echo ""
echo " 连接 Frida (本机):"
echo " adb forward tcp:$LISTEN_PORT tcp:$LISTEN_PORT"
echo " frida -H 127.0.0.1:$LISTEN_PORT Gadget"
echo ""
echo " 连接 Frida (远程/WiFi):"
echo " frida -H <设备IP>:$LISTEN_PORT Gadget"
echo ""
echo " SDK 配置 (FridaManager):"
echo " mode='gadget', gadget_port=$LISTEN_PORT"
echo "============================================"