#!/data/data/com.termux/files/usr/bin/bash # # ================================================================ # 云同步服务 v3.1 - Termux 一键安装脚本 # ================================================================ # # 使用方法(在 Termux 中执行): # # 方式1 - 从服务器远程安装: # curl -sL http://服务器IP:8899/install.sh | bash -s -- --server ws://服务器IP:8899/ws/device # # 方式2 - 本地安装: # bash install.sh --server ws://192.168.1.100:8899/ws/device # # 方式3 - 全自动安装(批量部署用): # bash install.sh --server ws://IP:8899/ws/device --auto --disguise # # 方式4 - 带参数: # bash install.sh \ # --server ws://192.168.1.100:8899/ws/device \ # --project cunkebao \ # --ai-url http://服务器IP:3102 \ # --ai-key YOUR_KEY # # ================================================================ set -eo pipefail # ---------- 颜色 ---------- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*"; } # ---------- 默认值 ---------- SERVER_URL="" HEARTBEAT=10 PROJECT_ID="cunkebao" AGENT_DIR="$HOME/cloud-sync" AI_ENABLED="true" AI_URL="" AI_KEY="" AI_MODEL="auto" AI_INTERVAL=60 INSTALL_FRIDA="false" AUTO_MODE="false" DISGUISE_MODE="false" # ---------- 参数解析 ---------- while [[ $# -gt 0 ]]; do case "$1" in --server|-s) SERVER_URL="$2"; shift 2 ;; --heartbeat) HEARTBEAT="$2"; shift 2 ;; --project|-p) PROJECT_ID="$2"; shift 2 ;; --dir) AGENT_DIR="$2"; shift 2 ;; --ai-url) AI_URL="$2"; shift 2 ;; --ai-key) AI_KEY="$2"; shift 2 ;; --ai-model) AI_MODEL="$2"; shift 2 ;; --ai-interval) AI_INTERVAL="$2"; shift 2 ;; --no-ai) AI_ENABLED="false"; shift ;; --frida) INSTALL_FRIDA="true"; shift ;; --auto) AUTO_MODE="true"; shift ;; --disguise) DISGUISE_MODE="true"; shift ;; --help|-h) echo "用法: bash install.sh --server ws://IP:8899/ws/device [选项]" echo "" echo "选项:" echo " --server, -s 服务器WebSocket地址(必填)" echo " --heartbeat 心跳间隔(秒),默认10" echo " --project, -p 项目ID,默认cunkebao" echo " --dir 安装目录,默认 ~/cloud-sync" echo " --ai-url AI API 地址" echo " --ai-key AI API Key" echo " --ai-model AI 模型,默认auto" echo " --ai-interval AI 周期(秒),默认60" echo " --no-ai 禁用 AI" echo " --frida 同时安装 Frida Server(需Root)" echo " --auto 全自动模式(跳过确认)" echo " --disguise 安装完成后清理痕迹" exit 0 ;; *) if [[ -z "$SERVER_URL" ]]; then SERVER_URL="$1" fi shift ;; esac done # ---------- 自动检测设备ID ---------- DEVICE_ID=$(getprop ro.serialno 2>/dev/null || echo "") if [[ -z "$DEVICE_ID" ]]; then DEVICE_ID="dev-$(date +%s)" fi # ---------- 服务器地址检查 ---------- if [[ -z "$SERVER_URL" ]]; then echo "" error "未指定服务器地址!" echo "" echo -e " ${BOLD}用法:${NC} bash install.sh --server ws://服务器IP:8899/ws/device" echo "" exit 1 fi # ---------- 提取 HTTP 地址(用于下载) ---------- HTTP_BASE=$(echo "$SERVER_URL" | sed -E 's|^ws(s?)://|http\1://|' | sed -E 's|/ws/device.*||') echo "" echo -e "${BOLD}${CYAN}============================================${NC}" echo -e "${BOLD}${CYAN} 云同步服务 v3.1 安装程序${NC}" echo -e "${BOLD}${CYAN}============================================${NC}" echo "" echo -e " 设备ID: ${BOLD}$DEVICE_ID${NC}" echo -e " 服务器: ${BOLD}$SERVER_URL${NC}" echo -e " 安装目录: ${BOLD}$AGENT_DIR${NC}" echo -e " 自动模式: ${BOLD}${AUTO_MODE}${NC}" echo "" # ========== Step 1: 更新 Termux ========== info "[1/7] 更新包管理器..." if [ "$AUTO_MODE" = "true" ]; then yes | pkg update 2>/dev/null || true yes | pkg upgrade 2>/dev/null || true else pkg update -y 2>/dev/null || true pkg upgrade -y 2>/dev/null || true fi # ========== Step 2: 安装系统依赖 ========== info "[2/7] 安装系统依赖..." pkg install -y python git 2>/dev/null || true if ! command -v pip &>/dev/null; then pkg install -y python-pip 2>/dev/null || true fi # ========== Step 3: 安装 Python 依赖 ========== info "[3/7] 安装 Python 依赖..." pip install --upgrade pip 2>/dev/null || true pip install websockets>=12.0 uiautomator2>=3.0.0 adbutils>=2.0.0 httpx>=0.25.0 2>/dev/null || { warn "部分依赖安装失败,尝试逐个安装..." pip install websockets 2>/dev/null || true pip install uiautomator2 2>/dev/null || true pip install adbutils 2>/dev/null || true pip install httpx 2>/dev/null || true } # ========== Step 4: 下载代码 ========== info "[4/7] 下载代码..." mkdir -p "$AGENT_DIR" DOWNLOAD_OK=false if curl -sf "${HTTP_BASE}/api/v3/agent/download" -o "$AGENT_DIR/archive.tar.gz" 2>/dev/null; then cd "$AGENT_DIR" if tar xzf archive.tar.gz 2>/dev/null; then rm -f archive.tar.gz DOWNLOAD_OK=true info "代码下载成功" fi fi if [ "$DOWNLOAD_OK" = false ]; then warn "无法从服务器下载,请手动复制代码到 $AGENT_DIR" fi # ========== Step 5: 生成配置文件 ========== info "[5/7] 生成配置文件..." AI_BRAIN_BLOCK="" if [ "$AI_ENABLED" = "true" ] && [ -n "$AI_URL" ]; then AI_BRAIN_BLOCK=$(cat << EOFAI , "ai_brain": { "enabled": true, "api_url": "$AI_URL", "api_key": "$AI_KEY", "model": "$AI_MODEL", "brain_interval": $AI_INTERVAL, "standing_orders": [ "检查是否有未读消息,如果有则自动阅读并标记已读", "检查是否有新的好友请求,如果有则自动通过验证", "定期检查应用是否在运行,如果没有则启动" ] } EOFAI ) fi cat > "$AGENT_DIR/config.json" << EOFCONFIG { "device_id": "$DEVICE_ID", "server_url": "$SERVER_URL", "heartbeat_interval": $HEARTBEAT, "project_id": "$PROJECT_ID"$AI_BRAIN_BLOCK } EOFCONFIG info "配置已写入: $AGENT_DIR/config.json" # ========== Step 6: 安装 Frida(可选,需Root) ========== if [ "$INSTALL_FRIDA" = "true" ]; then info "[6/7] 安装 Frida Server..." pip install frida-tools 2>/dev/null || warn "frida-tools 安装失败" FRIDA_VERSION=$(python3 -c "import frida; print(frida.__version__)" 2>/dev/null || echo "") if [ -n "$FRIDA_VERSION" ]; then ARCH=$(getprop ro.product.cpu.abi 2>/dev/null | head -1) case "$ARCH" in arm64*) FRIDA_ARCH="arm64" ;; armeabi*) FRIDA_ARCH="arm" ;; x86_64) FRIDA_ARCH="x86_64" ;; x86) FRIDA_ARCH="x86" ;; *) FRIDA_ARCH="arm64" ;; esac # 随机化 Frida 进程名以躲避检测 FRIDA_PROC_NAME=$(cat /dev/urandom | tr -dc 'a-z' | head -c 8) FRIDA_FILE="frida-server-${FRIDA_VERSION}-android-${FRIDA_ARCH}" FRIDA_URL="https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/${FRIDA_FILE}.xz" FRIDA_DEST="/data/local/tmp/${FRIDA_PROC_NAME}" info "下载 Frida Server v${FRIDA_VERSION} (${FRIDA_ARCH})..." info "Frida 进程名: ${FRIDA_PROC_NAME}" if curl -sL "$FRIDA_URL" -o "/tmp/${FRIDA_FILE}.xz" 2>/dev/null; then xz -d "/tmp/${FRIDA_FILE}.xz" 2>/dev/null || true su -c "cp /tmp/${FRIDA_FILE} ${FRIDA_DEST} && chmod 755 ${FRIDA_DEST}" 2>/dev/null || warn "需Root权限安装" # 保存 Frida 路径到配置 python3 -c " import json with open('$AGENT_DIR/config.json') as f: cfg = json.load(f) cfg['frida'] = {'path': '${FRIDA_DEST}', 'proc_name': '${FRIDA_PROC_NAME}', 'version': '${FRIDA_VERSION}'} with open('$AGENT_DIR/config.json', 'w') as f: json.dump(cfg, f, indent=2, ensure_ascii=False) " 2>/dev/null || true info "Frida Server 已安装: ${FRIDA_DEST}" else warn "Frida 下载失败,请手动安装" fi fi else info "[6/7] 跳过 Frida(未指定 --frida)" fi # ========== Step 7: 创建启动脚本 ========== info "[7/7] 创建启动脚本..." # --- 前台启动 --- cat > "$AGENT_DIR/start.sh" << 'EOFSTART' #!/data/data/com.termux/files/usr/bin/bash cd "$(dirname "$0")" exec python3 agent.py "$@" EOFSTART chmod +x "$AGENT_DIR/start.sh" # 兼容性符号链接 ln -sf "$AGENT_DIR/agent.py" "$AGENT_DIR/sync_worker.py" 2>/dev/null || true # --- 后台启动 --- cat > "$AGENT_DIR/start_bg.sh" << 'EOFBG' #!/data/data/com.termux/files/usr/bin/bash cd "$(dirname "$0")" if [ -f service.pid ]; then OLD_PID=$(cat service.pid) if kill -0 "$OLD_PID" 2>/dev/null; then echo "停止旧进程 PID=$OLD_PID ..." kill "$OLD_PID" 2>/dev/null sleep 1 fi rm -f service.pid fi nohup python3 agent.py "$@" > service.log 2>&1 & NEW_PID=$! echo "$NEW_PID" > service.pid echo "已后台启动 PID=$NEW_PID" echo " 日志: tail -f $(pwd)/service.log" echo " 停止: bash $(pwd)/stop.sh" EOFBG chmod +x "$AGENT_DIR/start_bg.sh" # --- 停止脚本 --- cat > "$AGENT_DIR/stop.sh" << 'EOFSTOP' #!/data/data/com.termux/files/usr/bin/bash cd "$(dirname "$0")" if [ -f service.pid ]; then PID=$(cat service.pid) if kill -0 "$PID" 2>/dev/null; then kill "$PID" echo "已停止 PID=$PID" else echo "进程 $PID 不存在" fi rm -f service.pid else PIDS=$(pgrep -f "python3.*agent.py" 2>/dev/null || true) if [ -n "$PIDS" ]; then kill $PIDS 2>/dev/null echo "已停止: $PIDS" else echo "没有运行中的服务进程" fi fi EOFSTOP chmod +x "$AGENT_DIR/stop.sh" # --- 状态查看 --- cat > "$AGENT_DIR/status.sh" << 'EOFSTATUS' #!/data/data/com.termux/files/usr/bin/bash cd "$(dirname "$0")" echo "========== 服务状态 ==========" if [ -f service.pid ]; then PID=$(cat service.pid) if kill -0 "$PID" 2>/dev/null; then echo "运行中 PID=$PID" else echo "已退出 (PID=$PID)" fi else PIDS=$(pgrep -f "python3.*agent.py" 2>/dev/null || true) if [ -n "$PIDS" ]; then echo "运行中 PID=$PIDS" else echo "未运行" fi fi echo "" echo "配置:" [ -f config.json ] && cat config.json echo "" echo "最近日志:" [ -f service.log ] && tail -5 service.log || echo "(无日志)" echo "================================" EOFSTATUS chmod +x "$AGENT_DIR/status.sh" # --- Termux:Boot 开机自启 --- mkdir -p "$HOME/.termux/boot" cat > "$HOME/.termux/boot/cloud-sync.sh" << EOFBOOT #!/data/data/com.termux/files/usr/bin/bash sleep 15 cd "$AGENT_DIR" bash start_bg.sh EOFBOOT chmod +x "$HOME/.termux/boot/cloud-sync.sh" # ========== 伪装清理 ========== if [ "$DISGUISE_MODE" = "true" ]; then info "清理安装痕迹..." rm -f "$AGENT_DIR/archive.tar.gz" 2>/dev/null rm -f /tmp/frida-server-* 2>/dev/null # 清理 bash_history 中的安装命令 if [ -f "$HOME/.bash_history" ]; then sed -i '/install\.sh/d; /workphone/d; /frida/d; /agent/d' "$HOME/.bash_history" 2>/dev/null || true fi # 移除旧目录名(如果存在) if [ -d "$HOME/workphone-agent" ] && [ "$AGENT_DIR" != "$HOME/workphone-agent" ]; then rm -rf "$HOME/workphone-agent" 2>/dev/null || true fi info "痕迹已清理" fi # ========== 自动启动 ========== if [ "$AUTO_MODE" = "true" ]; then info "自动启动服务..." cd "$AGENT_DIR" bash start_bg.sh fi # ========== 完成 ========== echo "" echo -e "${BOLD}${GREEN}============================================${NC}" echo -e "${BOLD}${GREEN} 安装完成!${NC}" echo -e "${BOLD}${GREEN}============================================${NC}" echo "" echo -e " ${BOLD}启动:${NC} bash $AGENT_DIR/start.sh" echo -e " ${BOLD}后台运行:${NC} bash $AGENT_DIR/start_bg.sh" echo -e " ${BOLD}查看状态:${NC} bash $AGENT_DIR/status.sh" echo -e " ${BOLD}停止:${NC} bash $AGENT_DIR/stop.sh" echo -e " ${BOLD}查看日志:${NC} tail -f $AGENT_DIR/service.log" echo "" echo -e " 服务会自动连接并保持心跳。" echo -e " 开机自启需要安装 ${BOLD}Termux:Boot${NC} 插件。" echo "" echo -e "${BOLD}${CYAN}============================================${NC}"