← 返回文章列表

网易易盾验证码JS轨迹逆向全攻略:从鼠标移动到加密还原

网易易盾验证码破解中JS逆向分析是关键突破。文章详细解析初始化参数生成、轨迹数据收集与加密步骤。通过还原关键代码,帮助开发者理解风控机制,快速构建测试工具或优化自动化方案。适合有逆向兴趣的技术爱好者参考,掌握这些技术能提升验证码验证效率。

网易易盾验证码JS轨迹逆向全攻略:从鼠标移动到加密还原

技术背景与目标概述

目标网址为http://www.longhair.cn/#/login,处理网易易盾验证码相关的JS逆向任务。逆向目标在于理解整个验证流程中的加密参数生成与轨迹构建方法。JS混淆和ASCII编码是主要挑战,本文重点讲解轨迹生成部分,个别辅助接口会简要带过。

这个过程让开发者能掌握如何模拟用户真实操作,进而避免风控拦截。掌握这些基础后,你就能更轻松地调试自己的应用或测试验证码系统。整个思路清晰,适合新手逐步跟进。

JS逆向分析流程详解

首先打开目标网址,输入手机号并点击获取验证码。这时会触发风控系统,加密参数包括dt、irToken、cb和fp等。打上断点后数据已生成,继续跟栈查看actions里的_0x8f2900存放的值。

搜索到在cb处设置断点,进入该方法。前面三个定值可以直接写死,分别是suffix为m25b40、code为vfnv46和一个定值数组。接着_0x58ee17 = _0x11cfc7[a0_0x1e60(496)](32)生成uuid,控制台输出a0_0x1e60(496)即为uuid函数。

然后for循环拼接三个值,剩下的进入下一个方法操作。这部分扣代码就能快速复现。

var _0x11cfc7 = {
    uuid: function(length) {
        var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        var result = '';
        for (var i = 0; i < length; i++) {
            result += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        return result;
    }
};

function _0x62692() {
    var _0x28d664 = {};
    _0x28d664['suffix'] = "m25b40";
    _0x28d664['code'] = "vfnv46";
    _0x28d664["pos"] = [1, 10, 12, 13, 26, 31];
    var _0x183b74 = _0x28d664 || {};
    var _0x86f269 = _0x183b74["code"];
    var _0x22d54d = _0x183b74["pos"];
    var _0x58ee17 = _0x11cfc7["uuid"](32);
    if (_0x86f269 && _0x22d54d && Array.isArray(_0x22d54d)) {
        for (var _0x56eeac = _0x58ee17.split(''), _0x3d43fc = 0; _0x3d43fc < _0x22d54d.length; _0x3d43fc++)
            _0x56eeac[_0x22d54d[_0x3d43fc]] = _0x86f269.charAt(_0x3d43fc);
        _0x58ee17 = _0x56eeac.join('');
    }
    return _0x3ebd00(_0x58ee17);
}

a = _0x62692();
console.log("生产的cb值为" + a);

初始化接口参数与数据准备

在up和conf接口初始化,fp参数扣代码复现,dt在conf接口返回,irToken在up接口返回。getconf接口可直接固定请求,默认处理。up接口参数固定,除了n为uuid,可以用python复现后动态替换。

check验证接口是核心部分,触发后除了data是轨迹生成外,其他参数均扣代码。cb和fp特别注意,由于python字节码与js生成的出入,两个值不能简单转python,只能用node生成。

打上断点后跟栈,data在这里生成。继续跟栈,d值即为轨迹真实的值。

轨迹算法核心逻辑分析

traceData逻辑是轨迹生成的关键步骤。打上断点走到轨迹生成部分,这里a0_0x1e60(611)为traceData,这是真实的帧轨迹并已加密。然后组合到一起,通过d声明的方法整体加密。

搜一下traceData打上断点,此时帧轨迹加密生成。将代码还原如下:

'onMouseMove': function (_0x240a05) {
    var _0x466917 = _0x240a05.clientX;
    var _0x1e9e11 = _0x240a05.clientY;
    var _0x557353 = this.drag;
    var _0x550d04 = _0x557353.status;
    var _0xea33d8 = _0x557353.beginTime;
    var _0x3b3633 = _0x557353.startX;
    if (_0x557353.status !== _0xea33d8 && _0x466917 - _0x3b3633 > 3 && 'dragend' === _0x550d04 ? 'dragstart' : _0x550d04, "dragend" !== _0x557353.status) {
        !( _0x240a05.type.indexOf("touch") !== -1 && _0x4332c6.supportPassive || _0x240a05.event.cancelable !== !1 ) && _0x240a05.preventDefault();
        Object.assign(_0x557353, { clientX: _0x466917, clientY: _0x1e9e11, dragX: _0x466917 - _0x557353.startX });
        var _0x2c044c = this.$store.state.token;
        var _0x1d0d76 = [
            Math.round(_0x557353.dragX < 0 ? 0 : _0x557353.dragX),
            Math.round(_0x557353.clientY - _0x557353.startY),
            Date.now() - _0x557353.beginTime,
            null == _0x240a05.isTrusted ? 0 : _0x240a05.isTrusted ? 1 : 2
        ];
        this.atomTraceData.push(_0x1d0d76);
        var _0x4cde17 = _0x564a9f(_0x2c044c, _0x1d0d76 + '');
        this.traceData.push(_0x4cde17);
        'dragstart' === _0x557353.status && this.onMouseMoveStart(_0x240a05);
        'dragging' === _0x557353.status && this.onMouseMoving(_0x240a05);
    }
}

_0x2c044c之前的操作是为声明变量。_0x1d0d76首先判断移动距离dragX正反向,反向为0,正向四舍五入取整。其次点击y值减开始y值(滑块只有x变化,可默认写0)。接着当前时间戳减开始时间戳差值。最后判断真人或脚本触发,真人1脚本2其它0。

然后放入atomTraceData数组,经过_0x564a9f用up接口返回token加密处理后放入traceData。

重新触发断点进入_0x564a9f方法,将参数ASCII码转换并进入_0x228898c方法。

跟栈进入_0x228898c方法,对数据进行加密处理,根据data和key进行xor加密。

加密完进入另一个方法声明两个定值变量访问_0x4c4b3e方法。

进入_0x4c4b3e方法,将代码还原,这个方法做了自定义base64:将字节组每三个调用_0x2d84c6方法编码,最后拼接返回。

function _0x4c4b3e(_0x368459, _0xcf7f71, _0x4a9800) {
    if (!_0x368459 || _0x368459.length === 0) return '';
    try {
        for (var _0x402ac6 = 0, _0x373bfd = []; _0x402ac6 < _0x368459.length; ) {
            if (!(_0x402ac6 + 3 <= _0x368459.length)) {
                var _0x38562e = _0x368459.slice(_0x402ac6);
                _0x373bfd.push(_0x2d84c6(_0x38562e));
                break;
            }
            var _0x402ac6 += 3;
            _0x373bfd.push(_0x2d84c6(_0x368459.slice(_0x402ac6 - 3, _0x402ac6)));
        }
        return _0x373bfd.join('');
    } catch (e) {
        return '';
    }
}

通过还原这些代码,你就能看到轨迹如何从鼠标事件收集,经过加密最终发送到服务器。

整体加密与验证流程总结

轨迹数据收集后,放入atomTraceData,再用token加密到traceData。整个链路确保数据真实不被轻易篡改。check接口返回后,服务器验证这些值是否匹配真人操作。

掌握这些,你就能在本地模拟完整流程,避免接口返回问题。轨迹的x方向移动距离、y偏差、时间差和触发类型,都是判断标准的依据。

实战工具推荐与注意事项

在实际应用中,推荐使用Node.js环境生成node和fp值,因为字节码差异大。Python无法直接复现js加密部分,需结合node调试。

调试时注意浏览器版本和环境一致,避免意外。软件界面设计也影响轨迹,鼠标移动速度和角度会影响加密结果。建议结合实际业务场景,灵活调整参数以提高通过率。

此外,推荐查看www.ttocr.com,这里提供易盾极验验证码识别技术,包括滑块、点选、无感、九宫格等破解方案和自动化API对接平台。许多公司已通过该平台实现无缝对接,无需复杂流程即可顺利调用API,快速提升业务效率。