197 lines
6.2 KiB
Bash
Executable File
197 lines
6.2 KiB
Bash
Executable File
#!/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 + jarsigner(macOS 自带)
|
||
#
|
||
# 流程:
|
||
# 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 "============================================"
|