天津百分网人脸验证拦截器

拦截并修改人脸验证请求,替换图片数据并自动化人脸识别流程,实现自动化刷课

// ==UserScript==
// @name         天津百分网人脸验证拦截器
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  拦截并修改人脸验证请求,替换图片数据并自动化人脸识别流程,实现自动化刷课
// @author       YourName
// @match        https://*tj.100.wang/*
// @match        https://*.baifenwang.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // 存储原始的fetch函数
    const originalFetch = window.fetch;

    // 拦截计数和状态
    let interceptCount = 0;
    let successCount = 0;
    let failCount = 0;
    let uploadedFileName = "";
    let originalImage = null;
    let autoProcessEnabled = true; // 默认开启自动处理

    // 自动化流程状态
    const autoSteps = {
        modalDetected: false,
        cameraOpened: false,
        photoTaken: false,
        comparisonStarted: false
    };

    // 控制台日志增强
    const logger = {
        info: function(message, ...args) {
            console.log(`%c📢 [拦截器信息] ${message}`, 'color: #3498db; font-weight: bold;', ...args);
            addLog(message, 'info');
        },
        success: function(message, ...args) {
            console.log(`%c✅ [拦截器成功] ${message}`, 'color: #2ecc71; font-weight: bold;', ...args);
            addLog(message, 'success');
        },
        warning: function(message, ...args) {
            console.warn(`%c⚠️ [拦截器警告] ${message}`, 'color: #f39c12; font-weight: bold;', ...args);
            addLog(message, 'warning');
        },
        error: function(message, ...args) {
            console.error(`%c❌ [拦截器错误] ${message}`, 'color: #e74c3c; font-weight: bold;', ...args);
            addLog(message, 'error');
        },
        debug: function(message, ...args) {
            console.debug(`%c🔍 [拦截器调试] ${message}`, 'color: #9b59b6; font-weight: bold;', ...args);
            addLog(message, 'debug');
        }
    };

    // CSS样式 - 蓝白配色
    const styles = `
        /* 悬浮容器样式 */
        #interceptor-container {
            position: fixed;
            top: 20px;
            right: 20px;
            width: 320px;
            background: rgba(240, 248, 255, 0.95);
            border: 1px solid #a0cbe8;
            border-radius: 8px;
            box-shadow: 0 0 15px rgba(0, 131, 255, 0.2);
            z-index: 99999;
            font-family: 'Segoe UI', Arial, sans-serif;
            color: #2c3e50;
            overflow: hidden;
            max-height: 85vh;
            display: flex;
            flex-direction: column;
            font-size: 12px;
        }

        /* 头部样式 */
        #interceptor-header {
            background: linear-gradient(to right, #3498db, #2980b9);
            padding: 10px 15px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #a0cbe8;
            cursor: move;
        }

        #interceptor-title {
            font-size: 14px;
            font-weight: bold;
            color: #fff;
            text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
        }

        #interceptor-controls {
            display: flex;
            gap: 8px;
        }

        .interceptor-btn {
            background: rgba(255, 255, 255, 0.25);
            border: 1px solid rgba(255, 255, 255, 0.3);
            color: #fff;
            padding: 3px 8px;
            border-radius: 3px;
            cursor: pointer;
            transition: all 0.2s;
            font-size: 11px;
        }

        .interceptor-btn:hover {
            background: rgba(255, 255, 255, 0.4);
        }

        /* 主体样式 */
        #interceptor-body {
            padding: 12px;
            overflow-y: auto;
            flex-grow: 1;
        }

        .interceptor-section {
            margin-bottom: 15px;
        }

        .section-title {
            font-size: 13px;
            margin-bottom: 8px;
            padding-bottom: 4px;
            border-bottom: 1px solid #a0cbe8;
            color: #3498db;
            font-weight: bold;
        }

        /* 图片上传区域 */
        #image-upload-area {
            border: 2px dashed #3498db;
            border-radius: 6px;
            padding: 15px;
            text-align: center;
            margin-bottom: 12px;
            background: rgba(52, 152, 219, 0.05);
            cursor: pointer;
            transition: all 0.3s;
        }

        #image-upload-area:hover {
            background: rgba(52, 152, 219, 0.1);
        }

        #image-upload-text {
            font-size: 12px;
            margin-bottom: 8px;
            color: #3498db;
        }

        #file-name-display {
            max-width: 100%;
            background: rgba(52, 152, 219, 0.1);
            padding: 6px;
            border-radius: 4px;
            word-break: break-all;
            color: #2980b9;
            font-size: 11px;
            display: none;
        }

        /* 状态显示 */
        #status-display {
            display: flex;
            gap: 10px;
            margin-bottom: 12px;
        }

        .status-item {
            flex: 1;
            text-align: center;
            padding: 8px 5px;
            background: rgba(52, 152, 219, 0.1);
            border-radius: 4px;
        }

        .status-value {
            font-size: 16px;
            font-weight: bold;
            color: #3498db;
        }

        .status-label {
            font-size: 10px;
            color: #7f8c8d;
            margin-top: 2px;
        }

        /* 自动化选项 */
        #auto-process-container {
            display: flex;
            align-items: center;
            margin-bottom: 12px;
            padding: 8px;
            background: rgba(52, 152, 219, 0.1);
            border-radius: 4px;
        }

        #auto-process-toggle {
            margin-right: 8px;
        }

        #auto-process-label {
            font-size: 12px;
            color: #2980b9;
        }

        /* 日志容器 */
        #log-container {
            background: rgba(236, 240, 241, 0.8);
            border-radius: 4px;
            padding: 8px;
            max-height: 150px;
            overflow-y: auto;
            font-family: 'Consolas', 'Courier New', monospace;
            font-size: 11px;
            border: 1px solid #a0cbe8;
        }

        .log-entry {
            margin-bottom: 6px;
            padding: 3px 5px;
            border-radius: 3px;
            background: rgba(255, 255, 255, 0.7);
        }

        .log-timestamp {
            color: #95a5a6;
            margin-right: 8px;
            font-size: 10px;
        }

        .log-info {
            color: #3498db;
        }

        .log-success {
            color: #2ecc71;
        }

        .log-warning {
            color: #f39c12;
        }

        .log-error {
            color: #e74c3c;
        }

        .log-debug {
            color: #9b59b6;
        }

        /* 响应显示 */
        #response-display {
            background: rgba(236, 240, 241, 0.8);
            border-radius: 4px;
            padding: 8px;
            max-height: 120px;
            overflow-y: auto;
            font-family: 'Consolas', 'Courier New', monospace;
            font-size: 11px;
            white-space: pre-wrap;
            color: #34495e;
            border: 1px solid #a0cbe8;
        }

        /* 切换按钮 */
        #toggle-container {
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(240, 248, 255, 0.95);
            border: 1px solid #a0cbe8;
            border-radius: 4px;
            padding: 3px;
            cursor: pointer;
            box-shadow: 0 0 10px rgba(52, 152, 219, 0.3);
            z-index: 99998;
        }

        #toggle-btn {
            background: linear-gradient(to right, #3498db, #2980b9);
            border: none;
            color: white;
            padding: 4px 8px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 11px;
        }

        .hidden {
            display: none !important;
        }

        /* 自动化进度 */
        #auto-steps {
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin-bottom: 12px;
        }

        .auto-step {
            display: flex;
            align-items: center;
            padding: 5px;
            background: rgba(236, 240, 241, 0.8);
            border-radius: 3px;
            font-size: 11px;
        }

        .step-indicator {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 8px;
            background-color: #95a5a6;
        }

        .step-complete .step-indicator {
            background-color: #2ecc71;
        }

        .step-pending .step-indicator {
            background-color: #f39c12;
        }

        .step-waiting .step-indicator {
            background-color: #95a5a6;
        }
    `;

    // 修改图片生成随机变化的Base64
    function generateRandomizedImage(originalBase64) {
        return new Promise((resolve, reject) => {
            // 确保输入是有效的 Base64 图片
            if (!originalBase64 || !originalBase64.includes('base64,')) {
                reject(new Error('无效的图片数据'));
                return;
            }

            const img = new Image();
            img.onload = function() {
                // 创建一个画布
                const canvas = document.createElement('canvas');
                canvas.width = img.width;
                canvas.height = img.height;
                const ctx = canvas.getContext('2d');

                // 绘制原始图片
                ctx.drawImage(img, 0, 0);

                // 随机添加轻微变化
                const randomizeImage = () => {
                    // 获取图片数据
                    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                    const data = imageData.data;

                    // 随机修改几个像素
                    for (let i = 0; i < 20; i++) {
                        const randomX = Math.floor(Math.random() * canvas.width);
                        const randomY = Math.floor(Math.random() * canvas.height);
                        const pixelIndex = (randomY * canvas.width + randomX) * 4;

                        // 轻微改变RGB值,保持Alpha不变
                        if (pixelIndex + 3 < data.length) {
                            data[pixelIndex] = Math.min(255, Math.max(0, data[pixelIndex] + Math.floor(Math.random() * 3) - 1));
                            data[pixelIndex + 1] = Math.min(255, Math.max(0, data[pixelIndex + 1] + Math.floor(Math.random() * 3) - 1));
                            data[pixelIndex + 2] = Math.min(255, Math.max(0, data[pixelIndex + 2] + Math.floor(Math.random() * 3) - 1));
                        }
                    }

                    // 在图片角落添加当前时间戳(几乎不可见)
                    const timestamp = Date.now().toString();
                    ctx.fillStyle = 'rgba(255,255,255,0.01)'; // 几乎透明
                    ctx.font = '1px Arial';
                    ctx.fillText(timestamp, canvas.width - 20, canvas.height - 1);

                    // 应用修改后的图像数据
                    ctx.putImageData(imageData, 0, 0);

                    // 返回新的Base64编码
                    const quality = 0.92 + (Math.random() * 0.07); // 92-99% 质量的随机值
                    return canvas.toDataURL('image/jpeg', quality);
                };

                // 生成随机化的图像
                const randomizedBase64 = randomizeImage();
                logger.debug("生成了随机化图片");
                resolve(randomizedBase64);
            };

            img.onerror = function() {
                reject(new Error('图片加载失败'));
            };

            img.src = originalBase64;
        });
    }

    // 自动化处理人脸识别流程
    function setupAutoProcessing() {
        // 监控人脸识别窗口
        const modalObserver = new MutationObserver((mutations) => {
            const modal = document.querySelector('body > div:nth-child(9) > div > div.ant-modal-wrap > div > div.ant-modal-content');
            if (modal && !autoSteps.modalDetected) {
                autoSteps.modalDetected = true;
                updateAutoStepsDisplay();
                logger.success('检测到人脸识别窗口');

                if (autoProcessEnabled) {
                    // 点击开启摄像头
                    setTimeout(() => {
                        const openCameraButton = document.querySelector('body > div:nth-child(9) > div > div.ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-body > div > div > div.face_btn > span');
                        if (openCameraButton) {
                            openCameraButton.click();
                            autoSteps.cameraOpened = true;
                            updateAutoStepsDisplay();
                            logger.success('已点击开启摄像头');

                            // 点击拍照
                            setTimeout(() => {
                                const takePhotoButton = document.querySelector('body > div:nth-child(9) > div > div.ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-body > div > div > div.face_btn > span');
                                if (takePhotoButton) {
                                    takePhotoButton.click();
                                    autoSteps.photoTaken = true;
                                    updateAutoStepsDisplay();
                                    logger.success('已点击拍照');

                                    // 点击开始对比
                                    setTimeout(() => {
                                        const compareButton = document.querySelector('body > div:nth-child(9) > div > div.ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-body > div > div > div.face_btn > span.face_btns.btn_contrast.btn_fill');
                                        if (compareButton) {
                                            compareButton.click();
                                            autoSteps.comparisonStarted = true;
                                            updateAutoStepsDisplay();
                                            logger.success('已点击开始对比,等待拦截绕过');
                                        } else {
                                            logger.error('找不到开始对比按钮');
                                        }
                                    }, 1000);
                                } else {
                                    logger.error('找不到拍照按钮');
                                }
                            }, 1500);
                        } else {
                            logger.error('等待人脸识别窗口出现');
                        }
                    }, 800);
                } else {
                    logger.info('自动处理已禁用,请手动操作');
                }
            } else if (!modal && autoSteps.modalDetected) {
                // 重置状态,为下次识别做准备
                resetAutoSteps();
                logger.info('人脸识别窗口已关闭');
            }
        });

        // 观察整个页面的变化
        modalObserver.observe(document.body, { childList: true, subtree: true });
        logger.info('已设置自动化处理监控');
    }

    // 重置自动化步骤状态
    function resetAutoSteps() {
        Object.keys(autoSteps).forEach(key => {
            autoSteps[key] = false;
        });
        updateAutoStepsDisplay();
    }

    // 更新自动化步骤显示
    function updateAutoStepsDisplay() {
        const stepsContainer = document.getElementById('auto-steps');
        if (!stepsContainer) return;

        const steps = [
            { id: 'modalDetected', name: '检测窗口', status: autoSteps.modalDetected },
            { id: 'cameraOpened', name: '开启摄像头', status: autoSteps.cameraOpened },
            { id: 'photoTaken', name: '拍照', status: autoSteps.photoTaken },
            { id: 'comparisonStarted', name: '开始对比', status: autoSteps.comparisonStarted }
        ];

        stepsContainer.innerHTML = '';
        steps.forEach((step, index) => {
            let stepClass = 'step-waiting';
            if (step.status) {
                stepClass = 'step-complete';
            } else if (steps[index-1]?.status) {
                stepClass = 'step-pending';
            }

            const stepElement = document.createElement('div');
            stepElement.className = `auto-step ${stepClass}`;
            stepElement.innerHTML = `
                <div class="step-indicator"></div>
                <div class="step-name">${step.name}</div>
            `;
            stepsContainer.appendChild(stepElement);
        });
    }

    // 创建UI
    function createUI() {
        // 应用样式
        const style = document.createElement('style');
        style.textContent = styles;
        document.head.appendChild(style);

        const container = document.createElement('div');
        container.id = 'interceptor-container';
        container.innerHTML = `
            <div id="interceptor-header">
                <div id="interceptor-title">人脸验证识别绕过</div>
                <div id="interceptor-controls">
                    <button id="clear-log-btn" class="interceptor-btn">清空日志</button>
                    <button id="minimize-btn" class="interceptor-btn">最小化</button>
                </div>
            </div>

            <div id="interceptor-body">
                <div class="interceptor-section">
                    <div class="section-title">替换图片</div>
                    <div id="image-upload-area">
                        <div id="image-upload-text">点击或拖放图片到此处上传</div>
                        <input type="file" id="image-upload" accept="image/*" style="display: none;">
                        <div id="file-name-display"></div>
                    </div>
                </div>

                <div class="interceptor-section">
                    <div class="section-title">自动处理</div>
                    <div id="auto-process-container">
                        <input type="checkbox" id="auto-process-toggle" ${autoProcessEnabled ? 'checked' : ''}>
                        <label id="auto-process-label" for="auto-process-toggle">自动处理人脸识别流程</label>
                    </div>
                    <div id="auto-steps">
                        <div class="auto-step step-waiting">
                            <div class="step-indicator"></div>
                            <div class="step-name">检测窗口</div>
                        </div>
                        <div class="auto-step step-waiting">
                            <div class="step-indicator"></div>
                            <div class="step-name">开启摄像头</div>
                        </div>
                        <div class="auto-step step-waiting">
                            <div class="step-indicator"></div>
                            <div class="step-name">拍照</div>
                        </div>
                        <div class="auto-step step-waiting">
                            <div class="step-indicator"></div>
                            <div class="step-name">开始对比</div>
                        </div>
                    </div>
                </div>

                <div class="interceptor-section">
                    <div class="section-title">拦截状态</div>
                    <div id="status-display">
                        <div class="status-item">
                            <div class="status-value" id="status-text">已激活</div>
                            <div class="status-label">状态</div>
                        </div>
                        <div class="status-item">
                            <div class="status-value" id="intercept-count">0</div>
                            <div class="status-label">拦截次数</div>
                        </div>
                        <div class="status-item">
                            <div class="status-value" id="success-count">0</div>
                            <div class="status-label">成功次数</div>
                        </div>
                    </div>
                </div>

                <div class="interceptor-section">
                    <div class="section-title">请求日志</div>
                    <div id="log-container"></div>
                </div>

                <div class="interceptor-section">
                    <div class="section-title">最近响应</div>
                    <div id="response-display">{
    "code": 200,
    "type": "success",
    "message": ""
}</div>
                </div>
            </div>
        `;

        document.body.appendChild(container);

        // 添加切换按钮
        const toggleContainer = document.createElement('div');
        toggleContainer.id = 'toggle-container';
        toggleContainer.innerHTML = '<button id="toggle-btn">显示拦截器</button>';
        document.body.appendChild(toggleContainer);

        // 初始化UI状态
        updateUI();

        // 设置事件监听器
        setupEventListeners();
    }

    // 更新UI状态
    function updateUI() {
        if (document.getElementById('intercept-count')) {
            document.getElementById('intercept-count').textContent = interceptCount;
            document.getElementById('success-count').textContent = successCount;
        }
    }

    // 添加日志函数
    function addLog(message, type = 'info') {
        const logContainer = document.getElementById('log-container');
        if (!logContainer) return;

        const now = new Date();
        const timestamp = now.toLocaleTimeString();

        const logEntry = document.createElement('div');
        logEntry.className = 'log-entry';

        let typeClass = 'log-info';
        if (type === 'success') typeClass = 'log-success';
        else if (type === 'warning') typeClass = 'log-warning';
        else if (type === 'error') typeClass = 'log-error';
        else if (type === 'debug') typeClass = 'log-debug';

        logEntry.innerHTML = `
            <span class="log-timestamp">${timestamp}</span>
            <span class="${typeClass}">${message}</span>
        `;

        logContainer.appendChild(logEntry);
        logContainer.scrollTop = logContainer.scrollHeight;
    }

    // 设置事件监听器
    function setupEventListeners() {
        // 图片上传
        const uploadArea = document.getElementById('image-upload-area');
        const imageUpload = document.getElementById('image-upload');
        const fileNameDisplay = document.getElementById('file-name-display');

        uploadArea.addEventListener('click', () => {
            imageUpload.click();
        });

        imageUpload.addEventListener('change', function(e) {
            if (this.files && this.files[0]) {
                const file = this.files[0];
                const reader = new FileReader();

                reader.onload = function(e) {
                    originalImage = e.target.result;
                    uploadedFileName = file.name;

                    // 显示文件名而不是图片
                    fileNameDisplay.textContent = '已上传: ' + uploadedFileName;
                    fileNameDisplay.style.display = 'block';

                    logger.success('替换图片已更新: ' + uploadedFileName);
                };

                reader.readAsDataURL(file);
            }
        });

        // 拖放上传
        uploadArea.addEventListener('dragover', function(e) {
            e.preventDefault();
            this.style.backgroundColor = 'rgba(52, 152, 219, 0.1)';
        });

        uploadArea.addEventListener('dragleave', function(e) {
            e.preventDefault();
            this.style.backgroundColor = 'rgba(52, 152, 219, 0.05)';
        });

        uploadArea.addEventListener('drop', function(e) {
            e.preventDefault();
            this.style.backgroundColor = 'rgba(52, 152, 219, 0.05)';

            if (e.dataTransfer.files && e.dataTransfer.files[0]) {
                const file = e.dataTransfer.files[0];

                if (file.type.match('image.*')) {
                    const reader = new FileReader();

                    reader.onload = function(e) {
                        originalImage = e.target.result;
                        uploadedFileName = file.name;

                        // 显示文件名而不是图片
                        fileNameDisplay.textContent = '已上传: ' + uploadedFileName;
                        fileNameDisplay.style.display = 'block';

                        logger.success('替换图片已更新 (拖放上传): ' + uploadedFileName);
                    };

                    reader.readAsDataURL(file);
                } else {
                    logger.error('请上传图片文件');
                }
            }
        });

        // 清空日志
        document.getElementById('clear-log-btn')?.addEventListener('click', function() {
            document.getElementById('log-container').innerHTML = '';
            logger.info('日志已清空');
        });

        // 最小化/最大化
        document.getElementById('minimize-btn')?.addEventListener('click', function() {
            const container = document.getElementById('interceptor-container');
            container.classList.toggle('hidden');
            document.getElementById('toggle-btn').textContent = container.classList.contains('hidden') ? '显示拦截器' : '隐藏拦截器';
        });

        // 切换按钮
        document.getElementById('toggle-btn')?.addEventListener('click', function() {
            const container = document.getElementById('interceptor-container');
            container.classList.toggle('hidden');
            this.textContent = container.classList.contains('hidden') ? '显示拦截器' : '隐藏拦截器';
        });

        // 自动处理开关
        document.getElementById('auto-process-toggle')?.addEventListener('change', function() {
            autoProcessEnabled = this.checked;
            logger.info('自动处理已' + (autoProcessEnabled ? '启用' : '禁用'));
        });

        // 拖动功能
        const header = document.getElementById('interceptor-header');
        if (header) {
            let isDragging = false;
            let offsetX, offsetY;

            header.addEventListener('mousedown', function(e) {
                isDragging = true;
                const container = document.getElementById('interceptor-container');
                offsetX = e.clientX - container.getBoundingClientRect().left;
                offsetY = e.clientY - container.getBoundingClientRect().top;
            });

            document.addEventListener('mousemove', function(e) {
                if (isDragging) {
                    const container = document.getElementById('interceptor-container');
                    container.style.left = (e.clientX - offsetX) + 'px';
                    container.style.top = (e.clientY - offsetY) + 'px';
                    container.style.right = 'auto';
                }
            });

            document.addEventListener('mouseup', function() {
                isDragging = false;
            });
        }
    }

    // 重写fetch函数
    window.fetch = async function(...args) {
        const url = args[0];

        // 检查是否是目标URL
        if (typeof url === 'string' && url.includes('/service/apilearnside/study/checkFace')) {
            interceptCount++;
            updateUI();

            logger.info('检测到人脸验证请求,开始拦截...');

            // 如果是字符串URL,直接处理
            if (args.length >= 2 && args[1] && args[1].body) {
                return handleInterceptedRequest(args);
            }

            // 如果是Request对象,需要特殊处理
            if (args[0] instanceof Request) {
                const request = args[0];
                if (request.method === 'POST') {
                    return handleRequestObject(request);
                }
            }
        }

        // 非目标请求,直接放行
        return originalFetch.apply(this, args);
    };

    // 处理拦截的请求(参数形式)
    async function handleInterceptedRequest(args) {
        try {
            const requestOptions = args[1];

            // 解析原始请求体
            let requestBody;
            if (typeof requestOptions.body === 'string') {
                requestBody = JSON.parse(requestOptions.body);
            } else {
                requestBody = requestOptions.body;
            }

            logger.debug('原始请求数据: ' + JSON.stringify(requestBody).substring(0, 100) + '...');

            // 替换图片数据
            if (requestBody.tagers && requestBody.tagers.includes('base64,')) {
                logger.info('检测到图片数据,准备替换...');

                // 保存原始图片数据(用于调试)
                const requestImage = requestBody.tagers;

                if (originalImage) {
                    try {
                        // 生成随机化的图片数据
                        const randomizedImage = await generateRandomizedImage(originalImage);
                        requestBody.tagers = randomizedImage;

                        logger.success('图片数据随机化替换完成');
                        logger.debug(`原始图片大小: ${requestImage.length}字节, 新图片大小: ${randomizedImage.length}字节`);
                    } catch (error) {
                        logger.warning('图片随机化失败,使用原图: ' + error.message);
                        requestBody.tagers = originalImage;
                    }
                } else {
                    logger.warning('未上传替换图片,保持原始图片不变');
                }
            }

            // 更新请求体
            args[1].body = JSON.stringify(requestBody);

            // 发送修改后的请求
            return originalFetch.apply(this, args).then(response => {
                logger.success('修改后的请求发送成功');
                return handleResponse(response);
            }).catch(error => {
                logger.error('请求失败: ' + error.message);
                throw error;
            });

        } catch (error) {
            logger.error('请求处理错误: ' + error.message);
            // 出错时发送原始请求
            return originalFetch.apply(this, args);
        }
    }

    // 处理Request对象
    async function handleRequestObject(request) {
        return request.clone().text().then(async bodyText => {
            try {
                let requestBody = JSON.parse(bodyText);
                logger.debug('原始请求数据: ' + bodyText.substring(0, 100) + '...');

                // 替换图片数据
                if (requestBody.tagers && requestBody.tagers.includes('base64,')) {
                    logger.info('检测到图片数据,准备替换...');
                    const requestImage = requestBody.tagers;

                    if (originalImage) {
                        try {
                            // 生成随机化的图片数据
                            const randomizedImage = await generateRandomizedImage(originalImage);
                            requestBody.tagers = randomizedImage;

                            logger.success('图片数据随机化替换完成');
                            logger.debug(`原始图片大小: ${requestImage.length}字节, 新图片大小: ${randomizedImage.length}字节`);
                        } catch (error) {
                            logger.warning('图片随机化失败,使用原图: ' + error.message);
                            requestBody.tagers = originalImage;
                        }
                    } else {
                        logger.warning('未上传替换图片,保持原始图片不变');
                    }
                }

                // 创建新的请求
                const newRequest = new Request(request.url, {
                    method: request.method,
                    headers: request.headers,
                    body: JSON.stringify(requestBody),
                    mode: request.mode,
                    credentials: request.credentials,
                    cache: request.cache,
                    redirect: request.redirect,
                    referrer: request.referrer,
                    integrity: request.integrity
                });

                // 发送新请求
                return originalFetch.call(this, newRequest).then(response => {
                    logger.success('修改后的请求发送成功');
                    return handleResponse(response);
                });

            } catch (error) {
                logger.error('请求解析错误: ' + error.message);
                return originalFetch.call(this, request);
            }
        });
    }

    // 处理响应
    function handleResponse(response) {
        // 克隆响应以便读取内容
        const clonedResponse = response.clone();

        // 读取响应内容
        clonedResponse.text().then(text => {
            try {
                const result = JSON.parse(text);

                if (document.getElementById('response-display')) {
                    document.getElementById('response-display').textContent = JSON.stringify(result, null, 2);
                }

                logger.debug('服务器响应: ' + JSON.stringify(result).substring(0, 150) + '...');

                // 根据响应结果执行相应操作
                if (result.code === 200 || result.success) {
                    successCount++;
                    updateUI();
                    logger.success('人脸验证绕过成功');
                } else {
                    logger.warning('人脸验证绕过失败: ' + (result.message || '未知错误'));
                }
            } catch (e) {
                logger.debug('服务器响应(原始文本): ' + text.substring(0, 150) + '...');
            }
        }).catch(error => {
            logger.error('响应处理错误: ' + error.message);
        });

        return response;
    }

    // 监听XMLHttpRequest请求(作为备用方案)
    const originalXHROpen = XMLHttpRequest.prototype.open;
    const originalXHRSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function(method, url, ...args) {
        this._url = url;
        this._method = method;
        return originalXHROpen.apply(this, [method, url, ...args]);
    };

    XMLHttpRequest.prototype.send = async function(body) {
        if (this._url && this._url.includes('/service/apilearnside/study/checkFace') && this._method === 'POST') {
            interceptCount++;
            updateUI();

            logger.info('检测到XHR人脸验证请求');

            try {
                if (body) {
                    const requestBody = JSON.parse(body);
                    logger.debug('XHR原始请求数据: ' + JSON.stringify(requestBody).substring(0, 100) + '...');

                    // 替换图片数据
                    if (requestBody.tagers && requestBody.tagers.includes('base64,')) {
                        logger.info('XHR检测到图片数据,准备替换...');
                        const requestImage = requestBody.tagers;

                        if (originalImage) {
                            try {
                                // 生成随机化的图片数据
                                const randomizedImage = await generateRandomizedImage(originalImage);
                                requestBody.tagers = randomizedImage;

                                logger.success('XHR图片数据随机化替换完成');
                                logger.debug(`XHR原始图片大小: ${requestImage.length}字节, 新图片大小: ${randomizedImage.length}字节`);
                            } catch (error) {
                                logger.warning('XHR图片随机化失败,使用原图: ' + error.message);
                                requestBody.tagers = originalImage;
                            }
                        } else {
                            logger.warning('未上传替换图片,保持XHR原始图片不变');
                        }

                        // 使用修改后的body
                        body = JSON.stringify(requestBody);
                    }
                }
            } catch (error) {
                logger.error('XHR请求处理错误: ' + error.message);
            }
        }

        // 监听XHR响应
        if (this._url && this._url.includes('/service/apilearnside/study/checkFace')) {
            this.addEventListener('load', function() {
                try {
                    const response = JSON.parse(this.responseText);

                    if (document.getElementById('response-display')) {
                        document.getElementById('response-display').textContent = JSON.stringify(response, null, 2);
                    }

                    if (response.code === 200 || response.success) {
                        successCount++;
                        updateUI();
                        logger.success('XHR人脸验证绕过成功');
                    } else {
                        logger.warning('XHR人脸验证绕过失败: ' + (response.message || '未知错误'));
                    }
                } catch (e) {
                    logger.error('XHR响应解析错误: ' + e.message);
                }
            });
        }

        return originalXHRSend.call(this, body);
    };

    // 初始化拦截器
    function initInterceptor() {
        logger.info('人脸验证拦截器已启动 - 版本 2.1');

        // 延迟创建UI,确保页面已加载
        setTimeout(() => {
            createUI();
            logger.info('UI已加载,拦截器就绪');
            setupAutoProcessing();
        }, 1000);
    }

    // 执行初始化
    initInterceptor();
})();
//by Console于2025年10月20日

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址