167 lines
7.7 KiB
Bash
Executable File
167 lines
7.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# 工作手机 · 无 USB 无线主控一键脚本(WiFi adb + 设备本机 stealth Frida + WS Agent)
|
||
#
|
||
# 解决:USB 线材/接口物理不稳反复掉线。改用 WiFi adb 传输,u2/frida 全走无线;
|
||
# WS 身份仍用逻辑 device_id(SDK/hub 设备身份不变)。
|
||
#
|
||
# 真源:开发文档/10、项目管理/工作日志.md 2026-05-31 15:58 · 真机铁律 §〇.八 无线主控
|
||
#
|
||
# 用法:
|
||
# bash wireless_master_oneclick.sh [USB_SERIAL] [SDK_HOST:PORT] [WIFI_PORT]
|
||
# - USB_SERIAL : 首次开 tcpip 用的 USB 序列(默认 xgfe65eimrrofyws)
|
||
# - SDK_HOST : SDK 地址(默认 127.0.0.1:8899)
|
||
# - WIFI_PORT : adb tcpip 端口(默认 5555)
|
||
#
|
||
# 前置:设备已 Root、已装 frida(phantom_frida_config.json 指向 stealth 二进制),
|
||
# Mac 与设备同一 WiFi。USB 仅首次开 tcpip 时短暂连接,之后可拔线。
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
set -uo pipefail
|
||
|
||
USB_SERIAL="${1:-xgfe65eimrrofyws}"
|
||
SDK_HOST="${2:-127.0.0.1:8899}"
|
||
WIFI_PORT="${3:-5555}"
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
AGENT_DIR="$(cd "${SCRIPT_DIR}/../agent" && pwd)"
|
||
PHANTOM_CFG="${SCRIPT_DIR}/anti_detect/phantom_frida_config.json"
|
||
DEVICE_ID="${USB_SERIAL}" # 逻辑 device_id(WS 身份),全程不变
|
||
export ANDROID_ADB_SERVER_PORT="${ANDROID_ADB_SERVER_PORT:-5038}"
|
||
|
||
adb() {
|
||
command adb -P "${ANDROID_ADB_SERVER_PORT}" "$@"
|
||
}
|
||
|
||
log(){ echo "[$(date +%H:%M:%S)] $*"; }
|
||
fatal(){ echo "[FATAL] $*" >&2; exit 1; }
|
||
|
||
# ── 1. 经 USB 开 tcpip 并取设备 WiFi IP ──────────────────────────────────────
|
||
log "① 经 USB(${USB_SERIAL}) 开启 adb tcpip ${WIFI_PORT} 并取 WiFi IP"
|
||
WIFI_IP="$(adb -s "${USB_SERIAL}" shell ip route 2>/dev/null | grep -oE 'src [0-9.]+' | awk '{print $2}' | head -1)"
|
||
if [[ -z "${WIFI_IP}" ]]; then
|
||
# 设备可能已是 WiFi adb,尝试从已连接条目取
|
||
WIFI_IP="$(adb devices | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:'"${WIFI_PORT}"'' | head -1 | cut -d: -f1)"
|
||
fi
|
||
[[ -n "${WIFI_IP}" ]] || fatal "无法获取设备 WiFi IP(确认设备已连 WiFi 且 USB 可见,或已 adb connect)"
|
||
log " 设备 WiFi IP=${WIFI_IP}"
|
||
adb -s "${USB_SERIAL}" tcpip "${WIFI_PORT}" >/dev/null 2>&1 || true
|
||
sleep 3
|
||
|
||
# ── 2. adb connect WiFi + 稳定性校验 ────────────────────────────────────────
|
||
WIFI_SERIAL="${WIFI_IP}:${WIFI_PORT}"
|
||
log "② adb connect ${WIFI_SERIAL}"
|
||
adb connect "${WIFI_SERIAL}" >/dev/null 2>&1
|
||
sleep 2
|
||
OK=0
|
||
for i in 1 2 3 4; do
|
||
[[ "$(adb -s "${WIFI_SERIAL}" shell echo ok 2>/dev/null | tr -d '\r')" == "ok" ]] && OK=$((OK+1))
|
||
sleep 1
|
||
done
|
||
log " WiFi adb 稳定 ${OK}/4"
|
||
[[ "${OK}" -ge 3 ]] || fatal "WiFi adb 不稳定(${OK}/4),请检查同网/路由"
|
||
|
||
# ── 3. 启动设备本机 stealth frida-server(按 phantom 配置端口/二进制)──────────
|
||
FRIDA_PORT="$(python3 -c "import json;print(json.load(open('${PHANTOM_CFG}'))['listen_port'])" 2>/dev/null || echo 27042)"
|
||
FRIDA_BIN="$(python3 -c "import json;print(json.load(open('${PHANTOM_CFG}'))['binary_path'])" 2>/dev/null || echo /data/local/tmp/frida-server-16)"
|
||
FRIDA_BASE="$(basename "${FRIDA_BIN}")"
|
||
log "③ 重启本机 stealth frida ${FRIDA_BIN} @ ${FRIDA_PORT}(setsid 脱离会话)"
|
||
adb -s "${WIFI_SERIAL}" shell "su -c 'pkill -f ${FRIDA_BASE} 2>/dev/null; pkill -f frida-server 2>/dev/null; true'" >/dev/null 2>&1 || true
|
||
sleep 1
|
||
adb -s "${WIFI_SERIAL}" shell "su -c 'setsid ${FRIDA_BIN} -l 0.0.0.0:${FRIDA_PORT} </dev/null >/dev/null 2>&1 &'" >/dev/null 2>&1
|
||
sleep 4
|
||
adb -s "${WIFI_SERIAL}" shell "su -c 'ps -A | grep ${FRIDA_BASE}'" 2>/dev/null | head -1 \
|
||
|| fatal "frida 进程未确认"
|
||
adb -s "${WIFI_SERIAL}" forward "tcp:${FRIDA_PORT}" "tcp:${FRIDA_PORT}" >/dev/null
|
||
|
||
# ── 4. 确保微信运行(温和 am start,不 frida-spawn)─────────────────────────
|
||
if [[ -z "$(adb -s "${WIFI_SERIAL}" shell pidof com.tencent.mm 2>/dev/null | tr -d '\r')" ]]; then
|
||
log "④ 拉起微信(am start,禁 frida-spawn)"
|
||
adb -s "${WIFI_SERIAL}" shell am start -n com.tencent.mm/.ui.LauncherUI >/dev/null 2>&1 || true
|
||
sleep 5
|
||
fi
|
||
|
||
# ── 5. 启动 Agent(WP_DEVICE_SERIAL=WiFi 序列,device_id=逻辑身份)───────────
|
||
log "⑤ 启动 Agent:device_id=${DEVICE_ID}(WS身份) / adb_serial=${WIFI_SERIAL}(u2/frida传输)"
|
||
pkill -f "agent.py -d ${DEVICE_ID}" 2>/dev/null || true
|
||
sleep 2
|
||
WIRELESS_LOG="${SCRIPT_DIR}/../logs/wireless_agent.log"
|
||
: > "${WIRELESS_LOG}"
|
||
AGENT_PID="$(
|
||
cd "${AGENT_DIR}"
|
||
export WP_DEVICE_SERIAL="${WIFI_SERIAL}"
|
||
export WP_FRIDA_MODE=remote
|
||
export WP_FRIDA_PORT="${FRIDA_PORT}"
|
||
export WORKPHONE_AGENT_LOG="${WIRELESS_LOG}"
|
||
export WORKPHONE_WS_URL="ws://${SDK_HOST}/ws/device"
|
||
export WORKPHONE_DEVICE_ID="${DEVICE_ID}"
|
||
python3 - <<'PY'
|
||
import os
|
||
import subprocess
|
||
import sys
|
||
|
||
cmd = [
|
||
sys.executable,
|
||
"agent.py",
|
||
"-d",
|
||
os.environ["WORKPHONE_DEVICE_ID"],
|
||
"-s",
|
||
os.environ["WORKPHONE_WS_URL"],
|
||
"--heartbeat",
|
||
"10",
|
||
]
|
||
with open(os.environ["WORKPHONE_AGENT_LOG"], "ab", buffering=0) as log:
|
||
proc = subprocess.Popen(
|
||
cmd,
|
||
cwd=os.getcwd(),
|
||
env=os.environ.copy(),
|
||
stdin=subprocess.DEVNULL,
|
||
stdout=log,
|
||
stderr=subprocess.STDOUT,
|
||
start_new_session=True,
|
||
close_fds=True,
|
||
)
|
||
print(proc.pid)
|
||
PY
|
||
)"
|
||
echo "${AGENT_PID}" > "${SCRIPT_DIR}/../logs/wireless_agent.pid"
|
||
log " Agent pid=${AGENT_PID}(日志 ${WIRELESS_LOG})"
|
||
|
||
for _i in $(seq 1 45); do
|
||
if ! kill -0 "${AGENT_PID}" 2>/dev/null; then
|
||
tail -80 "${WIRELESS_LOG}" >&2 || true
|
||
fatal "Agent 启动后退出"
|
||
fi
|
||
if grep -q "RPC ping: pong" "${WIRELESS_LOG}" 2>/dev/null && \
|
||
grep -q "服务器确认注册" "${WIRELESS_LOG}" 2>/dev/null; then
|
||
log " Agent WS + Frida RPC 已就绪"
|
||
break
|
||
fi
|
||
sleep 2
|
||
done
|
||
|
||
# ── 6. 验证无线 Hook 链路 ───────────────────────────────────────────────────
|
||
log "⑥ 验证无线 Hook(get_profile)"
|
||
RESP="$(curl -s -m 45 -X POST "http://${SDK_HOST}/api/v3/hook/execute" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{\"device_id\":\"${DEVICE_ID}\",\"platform\":\"wechat\",\"action\":\"get_profile\",\"params\":{},\"hook_only\":true}")"
|
||
echo "${RESP}" | head -c 300; echo
|
||
OK="$(echo "${RESP}" | python3 -c 'import json,sys
|
||
try:
|
||
d=json.load(sys.stdin)
|
||
print(bool((d.get("data") or {}).get("success") or d.get("success")))
|
||
except Exception:
|
||
print(False)' 2>/dev/null || echo False)"
|
||
CH="$(echo "${RESP}" | python3 -c 'import json,sys
|
||
try:
|
||
d=json.load(sys.stdin)
|
||
print(d.get("channel_used") or (d.get("data") or {}).get("channel") or "")
|
||
except Exception:
|
||
print("")' 2>/dev/null || true)"
|
||
if [[ "${OK}" == "True" ]] && echo "${CH}" | grep -Eqi 'frida|hook'; then
|
||
log "✅ 无 USB 无线主控就绪:WiFi adb + 本机 stealth frida + WS + Hook"
|
||
log " 现在可拔掉 USB 线,控制/取材料经 WiFi 无线进行。"
|
||
else
|
||
tail -80 "${WIRELESS_LOG}" >&2 || true
|
||
fatal "Hook 未确认成功(frida attach / 微信运行 / 端口转发)"
|
||
fi
|
||
log "USB 掉线无影响;如换网/IP 变化,重跑本脚本即可。"
|