如何让脚本滑动更拟人(滑动验证对抗实战)

逆袭的小飞棍
17
·
4 个回应

最近做阿里系的产品自动化脚本时候,可能由于长时间频繁操作,以及系统环境的不安全,被软件检测出风险,直接弹出验证框,要求滑动验证。
这个滑动验证看起来不复杂,就是简单的一个拖动按钮,从左到右滑动到底就能验证通过。

初步尝试

我初步尝试先获取滑块的中心坐标,再获取滑条右端的坐标。以上代码都很顺利地完成了目标。最后用swipe方法直接一拖,没错滑块动了起来,从左到右拉到了底,但结果是验证不通过。
我猜测是滑块验证加入了拟人的检测,这样直接拉肯定是行不通的。

二次尝试

我对swipe函数的两个参数分别加入了随机数,让他看起来不那么平直。但想法是好的,但由于swipe这个函数的局限性,只在起点和终点加入随机数,其最终的滑动效果依旧是一条直线。
当然我没有想的那么简单,我使用了gestrues方法,对整条滑动路径取了5000个采样点,每个采样点分别加入了随机数。
看起来一切都很完美,但是最后还是没能通过验证。
我于是猜测,滑块对手势路径的连贯性有一定的要求,简单的随机数虽然看上去路径毫无规律,但实际上相邻两个采样点间会出现跳跃断层,导致整个手势路径凹凸不平跳跃起伏。很有可能是这样被检测出来的。

三次尝试

我于是引入了三角函数,输入起点和终点,设定波幅和周期(不能超出滑块框),整个路径会像波浪一样连贯地上下起伏。最后还是不行。

最后成功

考虑到正弦波还是相对有规律和简单的,我最终引入贝塞尔曲线,而且是高阶贝塞尔。
以下是贝塞尔曲线的计算函数,大家收好。

function CreateBezierPoints(anchorpoints, pointsAmount) {
    let last = anchorpoints[anchorpoints.length - 1]
    var points = [];
    for (var i = 0; i < pointsAmount; i++) {
        var point = MultiPointBezier(anchorpoints, i / pointsAmount);
        points.push(point);
    }
    return points;
}

function MultiPointBezier(points, t) {
    var len = points.length;
    var x = 0, y = 0;
    var erxiangshi = function (start, end) {
        var cs = 1, bcs = 1;
        while (end > 0) {
            cs *= start;
            bcs *= end;
            start--;
            end--;
        }
        return (cs / bcs);
    };
    for (var i = 0; i < len; i++) {
        var point = points[i];
        x += point[0] * Math.pow((1 - t), (len - 1 - i)) * Math.pow(t, i) * (erxiangshi(len - 1, i));
        y += point[1] * Math.pow((1 - t), (len - 1 - i)) * Math.pow(t, i) * (erxiangshi(len - 1, i));
    }
    return [x, y];
}

具体在脚本中应用如下:

function 滑块验证() {
    try {
        if (textContains('请拖动下方滑块完成验证').exists()) {
            msg('正在滑动验证!')

            var 滑块 = idContains('nc_1_n1z').clickable().findOnce().bounds()
            var 滑块框 = text('向右滑动验证').findOnce().bounds()
            var gesturesAry = 路径拟真([[滑块.centerX(), 滑块.centerY()], [滑块框.right, 滑块.centerY()]], 1000, 5000)
            //console.log(gesturesAry);
            if (滑块 != null && 滑块框 != null) {
                gestures(gesturesAry)
            }
        }
    } catch (err) { console.log(err); }
}

function 路径拟真(anchorpoints, dur, pointsAmount) {

    let last = anchorpoints[anchorpoints.length - 1]
    var points = [0, dur];
    for (var i = 0; i < pointsAmount; i++) {
        var point = MultiPointBezier(anchorpoints, i / pointsAmount);
        points.push(point);
    }
    return points;
}

这下子,阿里系某软件的滑块验证框也直接干掉了,很顺利地从左拉到右,直接通过验证。

以上是我过验证的方法,欢迎大家分享经验。
(懒得用Markdown详细排版了,图片也懒得插,大家将就着看)

发布于 2023-01-25
更新于 2023-01-25
好文章,需要你的鼓励