#!/bin/sh
# ============================================================================
# iKuai 设备 DNS 劫持 —— 统一无感解毒脚本 (sogou 变种 + 47.238 C2 变种)
# ----------------------------------------------------------------------------
# 目标：一次性检测并清除两类已知 DNS 劫持攻击，绝不触碰客户自有合法配置，
#       对客户完全无感（不重启设备、不断网，只热重载 DNS 规则）。
#
# 覆盖变种：
#   变种 A (C2 反代，真机取证 10.255.42.67 确证)：
#       - dns_reverse_proxy_new / dns_reverse_proxy 指向 C2 IP
#       - dns_config.proxy_force_dns 指向 C2 + forbid_dns_4a=1 + cachemode=2
#       - PREROUTING 裸 DNAT --dport 53 到 C2
#   变种 B (sogou 劫持 + 持久化，clean_2.txt 反推)：
#       - static_route comment='see_you_later' 持久化
#       - 载荷 /etc/mnt/ikuai/.sr /tmp/ikuaidnslocal_* /tmp/.csm_* /tmp/mmmmmm /tmp/cccccc
#       - iptables dns_153 链 / DNSPROXY REDIRECT --to-ports 5300
#       - sogou 域名 hex-string DNS 劫持 (ime.sogou.com/get.sogou.com)
#       - 内存马进程 (deleted exe / bash -s stager)
#
# 设计原则 (与已验证 C2 脚本一致)：
#   1. 只按已知 IOC 指纹精确匹配，绝不按规则类型盲删。
#   2. 一切修改前强制备份 (iptables + config.db + wpa_ppsk.db + 载荷)。
#   3. 检测(--check)与清理(--clean)严格分离；check 绝不写任何东西。
#   4. 幂等；busybox ash 兼容；全过程自记录，产 JSON。
#   5. 清理成功后创建 /etc/log/clean_dns_mark (空文件)，供云端判定。
#
# !! 边界 !! 本脚本只清理，不封堵。攻击者账号(493480/467610)与绑定签名
#   密钥漏洞必须在云端同步处置，否则清完会被重新下发。见交付文档。
#
# 相比 clean_2.txt 的安全化改造 (上会重点)：
#   - 删除 4 条误伤客户的认证清理 (ac_guestssid/ac_wechat_auth/webauth.whiteip)
#   - static_route 只按 comment='see_you_later' 精确删，去掉 gateway LIKE '%$(%'
#   - /dev/null 修复 / kill -9 / 文件删除，仅在确证感染后执行；check 绝不碰
# ============================================================================

set -u

# ---- IOC 指纹 --------------------------------------------------------------
C2_IPS="47.238.113.180 15.235.235.101 210.5.93.254"
SOGOU_DOMAINS="ime.sogou.com get.sogou.com"
BOOT_TAG="see_you_later"
BOOT_FILE="/etc/mnt/ikuai/.sr"
MAL_FILES="/etc/mnt/ikuai/.sr /tmp/ikuaidnslocal_x64 /tmp/ikuaidnslocal_mips /tmp/mmmmmm /tmp/cccccc /tmp/boot_payload.sh /tmp/boot_id /tmp/boot_uname"
MAL_GLOBS="/tmp/.csm_*"

# ---- 运行环境 --------------------------------------------------------------
TS="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)"
HOSTN="$(uname -n 2>/dev/null || echo unknown)"
WORK="/tmp/ikrecover"
BAK="$WORK/backup-$TS"
LOG="$WORK/recover-$TS.log"
REPORT="$WORK/report-$TS.json"
CLEAN_MARK="/etc/log/clean_dns_mark"

DB_CANDIDATES="/etc/mnt/ikuai/config.db /etc/config.db /mnt/ikuai/config.db"
WPA_CANDIDATES="/etc/mnt/ikuai/wpa_ppsk.db"
IK_DB=""
MODE="check"
DRY=0

FOUND_IPT=0; FOUND_DB=0
FOUND_SOGOU_RT=0; FOUND_SOGOU_FILE=0; FOUND_SOGOU_IPT=0; FOUND_SOGOU_PROC=0
CHANGED=0

log() { echo "[$(date '+%H:%M:%S' 2>/dev/null || echo now)] $*" | tee -a "$LOG" 2>/dev/null; }
has_cmd() { command -v "$1" >/dev/null 2>&1; }

usage() {
    cat <<EOF
用法: $0 [--check | --clean] [--dry-run]
  --check     只读探测（默认），报告是否被篡改，不做任何修改
  --clean     执行清理（先自动备份，再精确清除两类 IOC）
  --dry-run   与 --clean 连用：只打印将要执行的动作，不真正修改
EOF
}

while [ "$#" -gt 0 ]; do
    case "$1" in
        --check) MODE="check"; shift ;;
        --clean) MODE="clean"; shift ;;
        --dry-run) DRY=1; shift ;;
        -h|--help) usage; exit 0 ;;
        *) echo "未知参数: $1"; usage; exit 1 ;;
    esac
done

mkdir -p "$WORK" /etc/log 2>/dev/null

locate_db() {
    for c in $DB_CANDIDATES; do
        [ -f "$c" ] && { IK_DB="$c"; return 0; }
    done
    return 1
}

hex_domain() {
    echo "$1" | awk -F. '
BEGIN { for (i=0;i<=255;i++) a[sprintf("%c",i)]=i }
{
  for (i=1;i<=NF;i++) {
    label=$i
    printf "%02x ", length(label)
    for (j=1;j<=length(label);j++) printf "%02x ", a[substr(label,j,1)]
  }
  printf "00"
}'
}

# ==== 检测段（只读）========================================================
detect_iptables_c2() {
    IPT_ALL="$(iptables -t nat -S PREROUTING 2>/dev/null | grep -- '--dport 53' | grep -- '-j DNAT')"
    [ -z "$IPT_ALL" ] && return 0
    hits=0
    printf '%s\n' "$IPT_ALL" | while IFS= read -r line; do
        [ -n "$line" ] || continue
        for ip in $C2_IPS; do case "$line" in *"$ip"*) echo "$line" ;; esac; done
    done > "$WORK/.ipt_c2.$$"
    if [ -s "$WORK/.ipt_c2.$$" ]; then
        hits="$(grep -c . "$WORK/.ipt_c2.$$" 2>/dev/null)"
        log "变种A iptables: 命中 $hits 条 C2 DNS 劫持"
        while IFS= read -r l; do [ -n "$l" ] && log "  [恶意] $l"; done < "$WORK/.ipt_c2.$$"
    fi
    rm -f "$WORK/.ipt_c2.$$"
    FOUND_IPT="$hits"
    printf '%s\n' "$IPT_ALL" | while IFS= read -r line; do
        [ -n "$line" ] || continue
        _hit=0
        for ip in $C2_IPS; do case "$line" in *"$ip"*) _hit=1 ;; esac; done
        case "$line" in
            *"--to-destination 127."*|*"REDIRECT"*) : ;;
            *) [ "$_hit" -eq 0 ] && log "  [待复核] 非已知C2的53端口DNAT: $line" ;;
        esac
    done
    return 0
}

detect_db_c2() {
    [ -n "$IK_DB" ] || return 0
    has_cmd sqlite3 || { log "无 sqlite3，跳过 DB 探测"; return 0; }
    total=0; where_c2=""; where_pf=""
    for ip in $C2_IPS; do
        if [ -z "$where_c2" ]; then
            where_c2="dns_addr LIKE '%$ip%'"; where_pf="proxy_force_dns LIKE '%$ip%'"
        else
            where_c2="$where_c2 OR dns_addr LIKE '%$ip%'"; where_pf="$where_pf OR proxy_force_dns LIKE '%$ip%'"
        fi
    done
    for t in dns_reverse_proxy_new dns_reverse_proxy; do
        sqlite3 "$IK_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='$t';" 2>/dev/null | grep -q "$t" || continue
        n="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM $t WHERE $where_c2;" 2>/dev/null)"; [ -n "$n" ] || n=0
        [ "$n" -gt 0 ] && { log "变种A DB $t: 命中 $n 条 C2 反代"; total=$((total + n)); }
    done
    if sqlite3 "$IK_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='dns_config';" 2>/dev/null | grep -q dns_config; then
        n="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM dns_config WHERE $where_pf;" 2>/dev/null)"; [ -n "$n" ] || n=0
        [ "$n" -gt 0 ] && { log "变种A dns_config: $n 条 proxy_force_dns 指向 C2"; total=$((total + n)); }
        n4a="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM dns_config WHERE forbid_dns_4a=1;" 2>/dev/null)"
        ncm="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM dns_config WHERE cachemode=2;" 2>/dev/null)"
        [ -n "$n4a" ] || n4a=0; [ -n "$ncm" ] || ncm=0
        if [ "$n4a" -gt 0 ] || [ "$ncm" -gt 0 ]; then
            if [ "$total" -gt 0 ]; then
                log "  弱指标 forbid_dns_4a=$n4a cachemode=$ncm 与C2同现 → 纳入恢复"
                total=$((total + n4a + ncm))
            else
                log "  弱指标 forbid_dns_4a=$n4a cachemode=$ncm 单独出现 → [待复核] 不自动改"
            fi
        fi
    fi
    FOUND_DB="$total"
    return 0
}

detect_sogou_route() {
    [ -n "$IK_DB" ] || return 0
    has_cmd sqlite3 || return 0
    sqlite3 "$IK_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='static_route';" 2>/dev/null | grep -q static_route || return 0
    n="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM static_route WHERE comment='$BOOT_TAG';" 2>/dev/null)"; [ -n "$n" ] || n=0
    [ "$n" -gt 0 ] && log "变种B static_route: 命中 $n 条 '$BOOT_TAG' 持久化"
    FOUND_SOGOU_RT="$n"
    return 0
}

detect_sogou_files() {
    n=0
    for f in $MAL_FILES; do [ -e "$f" ] && { n=$((n + 1)); log "变种B 载荷: $f"; }; done
    for g in $MAL_GLOBS; do for f in $g; do [ -e "$f" ] && { n=$((n + 1)); log "变种B 载荷: $f"; }; done; done
    FOUND_SOGOU_FILE="$n"
    return 0
}

detect_sogou_iptables() {
    n=0
    # 攻击者独有指纹（82 干净基线验证：dns_153 与 5300 均不存在）。
    # 注意：裸 'DNSPROXY' 是 iKuai 官方预建空链名（-N DNSPROXY），绝不能当攻击指纹，
    #       否则全员误报。攻击者只是借 DNSPROXY 注释伪装，真正特征是自建 dns_153 链 + 5300。
    if iptables -t nat -S 2>/dev/null | grep -E 'dns_153|-j dns_153|--to-ports 5300' >/dev/null 2>&1; then
        n=$((n + 1)); log "变种B iptables: 命中 dns_153/--to-ports 5300 劫持链"
    fi
    for d in $SOGOU_DOMAINS; do
        h="$(hex_domain "$d")"
        if iptables -t nat -S PREROUTING 2>/dev/null | grep -F "$h" >/dev/null 2>&1; then
            n=$((n + 1)); log "变种B iptables: 命中 sogou 劫持 ($d)"
        fi
    done
    FOUND_SOGOU_IPT="$n"
    return 0
}

detect_sogou_proc() {
    n=0
    for d in /proc/[0-9]*; do
        pid=${d#/proc/}
        [ -d "$d" ] || continue
        exe=$(readlink "/proc/$pid/exe" 2>/dev/null || true)
        cmdline=$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true)
        case "$exe" in *'(deleted)'*|/tmp/mmmmmm|/tmp/cccccc|/memfd:*) n=$((n + 1)); log "变种B 可疑进程: pid=$pid exe=$exe" ;; esac
        case "$cmdline" in *'/tmp/ikuaidns'*|'/bin/bash -s -- '*|'/bin/bash -s --') n=$((n + 1)); log "变种B 可疑进程: pid=$pid cmd=$cmdline" ;; esac
    done
    FOUND_SOGOU_PROC="$n"
    return 0
}

# ==== 备份 =================================================================
do_backup() {
    mkdir -p "$BAK" 2>/dev/null
    iptables-save > "$BAK/iptables-save.txt" 2>/dev/null || true
    iptables -t nat -S > "$BAK/nat-rules.txt" 2>/dev/null || true
    [ -n "$IK_DB" ] && [ -f "$IK_DB" ] && cp "$IK_DB" "$BAK/config.db.bak" 2>/dev/null && log "已备份 config.db"
    for w in $WPA_CANDIDATES; do [ -f "$w" ] && cp "$w" "$BAK/$(basename "$w").bak" 2>/dev/null; done
    for f in $MAL_FILES; do [ -e "$f" ] && cp -a "$f" "$BAK/" 2>/dev/null; done
    for g in $MAL_GLOBS; do for f in $g; do [ -e "$f" ] && cp -a "$f" "$BAK/" 2>/dev/null; done; done
    log "备份完成 → $BAK"
}

# ==== 清理段（仅确证后执行）================================================
clean_iptables_c2() {
    [ "$FOUND_IPT" -gt 0 ] || return 0
    iptables -t nat -S PREROUTING 2>/dev/null | grep -- '--dport 53' | grep -- '-j DNAT' > "$WORK/.ipt_all.$$"
    while IFS= read -r line; do
        [ -n "$line" ] || continue
        _hit=0
        for ip in $C2_IPS; do case "$line" in *"$ip"*) _hit=1 ;; esac; done
        [ "$_hit" -eq 1 ] || continue
        del_cmd="$(echo "$line" | sed 's/^-A /-D /')"
        if [ "$DRY" -eq 1 ]; then
            log "  [dry-run] iptables -t nat $del_cmd"
        else
            iptables -t nat $del_cmd 2>>"$LOG" && { log "  [已删] iptables -t nat $del_cmd"; CHANGED=$((CHANGED + 1)); }
        fi
    done < "$WORK/.ipt_all.$$"
    rm -f "$WORK/.ipt_all.$$"
}

clean_db_c2() {
    [ "$FOUND_DB" -gt 0 ] || return 0
    [ -n "$IK_DB" ] || return 0
    has_cmd sqlite3 || return 0
    where_c2=""; where_pf=""
    for ip in $C2_IPS; do
        if [ -z "$where_c2" ]; then
            where_c2="dns_addr LIKE '%$ip%'"; where_pf="proxy_force_dns LIKE '%$ip%'"
        else
            where_c2="$where_c2 OR dns_addr LIKE '%$ip%'"; where_pf="$where_pf OR proxy_force_dns LIKE '%$ip%'"
        fi
    done
    for t in dns_reverse_proxy_new dns_reverse_proxy; do
        sqlite3 "$IK_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='$t';" 2>/dev/null | grep -q "$t" || continue
        if [ "$DRY" -eq 1 ]; then
            log "  [dry-run] DELETE FROM $t WHERE $where_c2;"
        else
            n="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM $t WHERE $where_c2;" 2>/dev/null)"; [ -n "$n" ] || n=0
            [ "$n" -gt 0 ] && sqlite3 "$IK_DB" "DELETE FROM $t WHERE $where_c2;" 2>>"$LOG" && { log "  [已清] $t 删 $n 行"; CHANGED=$((CHANGED + n)); }
        fi
    done
    if sqlite3 "$IK_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='dns_config';" 2>/dev/null | grep -q dns_config; then
        if [ "$DRY" -eq 1 ]; then
            log "  [dry-run] UPDATE dns_config 恢复弱指标后清 proxy_force_dns"
        else
            n="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM dns_config WHERE $where_pf;" 2>/dev/null)"; [ -n "$n" ] || n=0
            if [ "$n" -gt 0 ]; then
                sqlite3 "$IK_DB" "UPDATE dns_config SET forbid_dns_4a=0, cachemode=0 WHERE ($where_pf) AND (forbid_dns_4a=1 OR cachemode=2);" 2>>"$LOG" && log "  [已清] 恢复 forbid_dns_4a=0,cachemode=0"
                sqlite3 "$IK_DB" "UPDATE dns_config SET proxy_force_dns='' WHERE $where_pf;" 2>>"$LOG" && { log "  [已清] 清空 $n 条 proxy_force_dns"; CHANGED=$((CHANGED + n)); }
            fi
        fi
    fi
}

clean_sogou_route() {
    [ "$FOUND_SOGOU_RT" -gt 0 ] || return 0
    [ -n "$IK_DB" ] || return 0
    has_cmd sqlite3 || return 0
    if [ "$DRY" -eq 1 ]; then
        log "  [dry-run] DELETE FROM static_route WHERE comment='$BOOT_TAG';"
    else
        n="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM static_route WHERE comment='$BOOT_TAG';" 2>/dev/null)"; [ -n "$n" ] || n=0
        [ "$n" -gt 0 ] && sqlite3 "$IK_DB" "DELETE FROM static_route WHERE comment='$BOOT_TAG';" 2>>"$LOG" && { log "  [已清] static_route 删 $n 条"; CHANGED=$((CHANGED + n)); }
        [ -x /usr/ikuai/script/static_rt.sh ] && /usr/ikuai/script/static_rt.sh boot >/dev/null 2>&1 || true
    fi
}

clean_sogou_files() {
    [ "$FOUND_SOGOU_FILE" -gt 0 ] || return 0
    if [ "$DRY" -eq 1 ]; then
        log "  [dry-run] rm -f $MAL_FILES $MAL_GLOBS"
    else
        for f in $MAL_FILES; do [ -e "$f" ] && rm -f "$f" 2>/dev/null && { log "  [已删] $f"; CHANGED=$((CHANGED + 1)); }; done
        for g in $MAL_GLOBS; do for f in $g; do [ -e "$f" ] && rm -f "$f" 2>/dev/null && { log "  [已删] $f"; CHANGED=$((CHANGED + 1)); }; done; done
    fi
}

clean_sogou_iptables() {
    [ "$FOUND_SOGOU_IPT" -gt 0 ] || return 0
    if [ "$DRY" -eq 1 ]; then
        log "  [dry-run] 删除 dns_153/DNSPROXY 链 + sogou hex 规则"
        return 0
    fi
    for d in $SOGOU_DOMAINS; do
        h="$(hex_domain "$d")"
        while iptables -w -t nat -D PREROUTING -p udp --dport 53 -m string --hex-string "|$h|" --algo bm -j REDIRECT --to-port 54 2>/dev/null; do CHANGED=$((CHANGED + 1)); done
    done
    while iptables -t nat -D PREROUTING -p udp -m udp --dport 53 -m conntrack --ctstate NEW -m comment --comment DNSPROXY -j REDIRECT --to-ports 5300 2>/dev/null; do CHANGED=$((CHANGED + 1)); done
    while iptables -t nat -D PREROUTING -p udp --dport 53 -j dns_153 2>/dev/null; do CHANGED=$((CHANGED + 1)); done
    while iptables -D INPUT -p udp -m udp --dport 5300 -m comment --comment DNSPROXY -j ACCEPT 2>/dev/null; do :; done
    iptables -t nat -F dns_153 2>/dev/null || true
    iptables -t nat -X dns_153 2>/dev/null || true
    log "  [已清] 变种B iptables 劫持链"
}

clean_sogou_proc() {
    [ "$FOUND_SOGOU_PROC" -gt 0 ] || return 0
    if [ "$DRY" -eq 1 ]; then
        log "  [dry-run] kill 可疑内存马进程"
        return 0
    fi
    for d in /proc/[0-9]*; do
        pid=${d#/proc/}
        [ -d "$d" ] || continue
        [ "$pid" = "$$" ] && continue
        exe=$(readlink "/proc/$pid/exe" 2>/dev/null || true)
        cmdline=$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true)
        killit=0
        case "$exe" in *'(deleted)'*|/tmp/mmmmmm|/tmp/cccccc|/memfd:*) killit=1 ;; esac
        case "$cmdline" in *'/tmp/ikuaidns'*|'/bin/bash -s -- '*|'/bin/bash -s --') killit=1 ;; esac
        if [ "$killit" = "1" ]; then
            log "  [已杀] pid=$pid exe=$exe cmd=$cmdline"
            kill -9 "$pid" 2>/dev/null || true
            CHANGED=$((CHANGED + 1))
        fi
    done
    pid="$(cat /var/run/ikdnsx.hosts.pid 2>/dev/null || true)"
    [ -n "$pid" ] && kill -9 "$pid" 2>/dev/null || true
    rm -f /var/run/ikdnsx.hosts.pid /tmp/iktmp/ikdnsx.status /tmp/hosts_ikuai8 2>/dev/null || true
}

reload_dns() {
    [ "$DRY" -eq 1 ] && { log "  [dry-run] 跳过 dns.sh 重载"; return 0; }
    if [ -x /usr/ikuai/script/dns.sh ]; then
        # dns.sh 无 restart 命令（82 实测：unknown command restart）。
        # 真实命令集为 boot/init/start/stop/save/updatedb。
        # boot 会 init → 从 config.db 重建 DNS 规则并启动 ikdnsx，是清理后正确的重载方式。
        if /usr/ikuai/script/dns.sh boot >>"$LOG" 2>&1; then
            log "已从 config.db 重建 DNS 规则（dns.sh boot）"
        else
            log "dns.sh boot 返回非零：ikdnsx 通常仍在运行（清理不中断 DNS），规则将在下次配置变更后同步，请人工抽查一台确认"
        fi
    else
        log "未找到 dns.sh，DNS 运行态将在下次配置变更后从 DB 重建"
    fi
}

verify() {
    remain=0
    r="$(iptables -t nat -S PREROUTING 2>/dev/null | grep -- '--dport 53' | grep -- '-j DNAT' | grep -cE "$(echo $C2_IPS | tr ' ' '|')" 2>/dev/null)"
    [ -n "$r" ] && remain=$((remain + r))
    if [ -n "$IK_DB" ] && has_cmd sqlite3; then
        for ip in $C2_IPS; do
            for t in dns_reverse_proxy_new dns_reverse_proxy; do
                sqlite3 "$IK_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='$t';" 2>/dev/null | grep -q "$t" || continue
                c="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM $t WHERE dns_addr LIKE '%$ip%';" 2>/dev/null)"
                [ -n "$c" ] && remain=$((remain + c))
            done
        done
        c="$(sqlite3 "$IK_DB" "SELECT COUNT(*) FROM static_route WHERE comment='$BOOT_TAG';" 2>/dev/null)"
        [ -n "$c" ] && remain=$((remain + c))
    fi
    for f in $MAL_FILES; do [ -e "$f" ] && remain=$((remain + 1)); done
    iptables -t nat -S 2>/dev/null | grep -E 'dns_153|--to-ports 5300' >/dev/null 2>&1 && remain=$((remain + 1))
    log "复核: 残留 IOC = $remain"
    [ "$remain" -eq 0 ] && return 0
    return 1
}

write_report() {
    status="$1"; msg="${2:-}"
    cat > "$REPORT" <<EOF
{
  "host": "$HOSTN",
  "timestamp": "$TS",
  "mode": "$MODE",
  "dry_run": $DRY,
  "status": "$status",
  "config_db": "${IK_DB:-not_found}",
  "variant_a_c2": { "iptables": $FOUND_IPT, "db_rows": $FOUND_DB },
  "variant_b_sogou": { "routes": $FOUND_SOGOU_RT, "files": $FOUND_SOGOU_FILE, "iptables": $FOUND_SOGOU_IPT, "procs": $FOUND_SOGOU_PROC },
  "cleaned_entries": $CHANGED,
  "backup_dir": "$BAK",
  "clean_mark": "$CLEAN_MARK",
  "message": "$msg"
}
EOF
    log "结论已写入 $REPORT (status=$status)"
}

# ==== 主流程 ===============================================================
log "=== iKuai 统一解毒 [$HOSTN] mode=$MODE dry_run=$DRY ==="
locate_db && log "配置库: $IK_DB" || log "未定位到 config.db（DB 阶段跳过）"

detect_iptables_c2
detect_db_c2
detect_sogou_route
detect_sogou_files
detect_sogou_iptables
detect_sogou_proc

TOTAL_A=$((FOUND_IPT + FOUND_DB))
TOTAL_B=$((FOUND_SOGOU_RT + FOUND_SOGOU_FILE + FOUND_SOGOU_IPT + FOUND_SOGOU_PROC))
TOTAL=$((TOTAL_A + TOTAL_B))

if [ "$TOTAL" -eq 0 ]; then
    log "未发现任何已知 IOC，设备干净。"
    write_report "clean" "no known IOC found"
    exit 0
fi

log "发现篡改：变种A=$TOTAL_A (ipt=$FOUND_IPT db=$FOUND_DB), 变种B=$TOTAL_B (rt=$FOUND_SOGOU_RT file=$FOUND_SOGOU_FILE ipt=$FOUND_SOGOU_IPT proc=$FOUND_SOGOU_PROC)"

if [ "$MODE" = "check" ]; then
    write_report "infected" "detected but not cleaned (check mode)"
    log "check 模式：仅报告，未修改。清理请加 --clean"
    exit 2
fi

do_backup
clean_iptables_c2
clean_db_c2
clean_sogou_route
clean_sogou_files
clean_sogou_iptables
clean_sogou_proc
reload_dns

if [ "$DRY" -eq 1 ]; then
    write_report "dry_run" "dry-run complete, nothing changed"
    log "=== dry-run 完成，未做任何修改 ==="
    exit 0
fi

if verify; then
    : > "$CLEAN_MARK" 2>/dev/null && log "已创建云端标记: $CLEAN_MARK"
    write_report "recovered" "cleaned $CHANGED entries, verified clean"
    log "=== 解毒完成：清除 $CHANGED 条，复核通过，已打标记 ==="
    exit 0
else
    write_report "partial" "cleaned $CHANGED entries but residue remains, manual review needed"
    log "=== 警告：仍有残留，需人工复核（备份 $BAK），未打标记 ==="
    exit 3
fi
