网易易盾滑块逆向

书接上文,还是讲滑块方面,本次案例与极验案例过程相似,可以进行反复对比观看

网页接口(base64编码):aHR0cHM6Ly9kdW4uMTYzLmNvbS90cmlhbC9zZW5zZQ==

先讲整体大思路:

        网页一共发送4次请求,而对我们有用的请求只有后面那三次。

        第二次请求:

                响应返回一个token,对后面的两个请求都有用

                仅一个请求参数需要逆向:cb(类似于uuid的作用,后面的请求也会用到,每一次请求都不一样)

        第三次请求:

                响应回来背景图片的url(重要信息仅此一个)

                请求参数也是只用逆向cb,token(第二次请求返回的)

       第四次请求:

                响应会来validate值,就说明滑块验证通过

                请求参数逆向:

                        cb

                        token(第二次请求返回的)

                        data :涉及滑块轨迹及其加密

OK,话不多说,开始逆向

Part-1: 参数 cb的破解

        先抓包

注意看,这就是第一第二次发送的请求,我们的中心在第二次                   

这是他的响应,对我们有用的是token值

这是它的请求参数,需要我们破解的是cb值

下面开始cb值的逆向:

        先接口定位,使用关键字搜索 'cb' (可以试试cb: cb=,但都没有结果) 

        搜索结果有4个,都打上断点(建议先做一下文件的本地替换,不会的看我文章结尾)

刷新页面(只有刷新页面才可以触发第一二次请求)

停住了,控制台打印一下,确实是这里生成的cb

那开始逆向f3,经过我的多次尝试,扣JS代码太麻烦了,还是沿用我上期文章的思路,利用webpack(为什么可以用呢?可以看看文件的开头,如果是一个自执行函数,多半可以用,但终点还是找到加载器函数)

将文件全部保存到本地,开始调用webpack

先做一些前置操作做:

加载器全局化,日志打印

写一个main.js文件调用 loader.js,并且附上env.js(补环境文件)

找到f3所属于的函数作用域(闭包),在本地文件搜索一下

经过我的手数它在第72个函数中(如果有什么更好的方法,欢迎在评论区留言!),index是71,所以代码如下:

require('./env')
require('./loader')


x = window.loader(71)
console.log('x:::', x)

运行,报错,再补环境,env.js代码如下:

function setProxyArr(proxyObjArr) {
    for (let i = 0; i < proxyObjArr.length; i++) {
        const handler = `{
      get: function(target, property, receiver) {
        console.log("方法:", "get  ", "对象:", "${proxyObjArr[i]}", "  属性:", property, "  属性类型:", typeof property, ", 属性值:", target[property], ", 属性值类型:", typeof target[property]);
        return target[property];
      },
      set: function(target, property, value, receiver) {
        console.log("方法:", "set  ", "对象:", "${proxyObjArr[i]}", "  属性:", property, "  属性类型:", typeof property, ", 属性值:", value, ", 属性值类型:", typeof target[property]);
        return Reflect.set(...arguments);
      }
    }`;
        eval(`try {
            ${proxyObjArr[i]};
            ${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});
        } catch (e) {
            ${proxyObjArr[i]} = {};
            ${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});
        }`);
    }
}

window = self = top = global

delete global;  // 记得用 _global = global 备份一下
delete Buffer;
delete __filename;
delete __dirname;

screen = {}

location = {
    "ancestorOrigins": {},
    "href": "https://dun.163.com/trial/sense",
    "origin": "https://dun.163.com",
    "protocol": "https:",
    "host": "dun.163.com",
    "hostname": "dun.163.com",
    "port": "",
    "pathname": "/trial/sense",
    "search": "",
    "hash": ""
}

navigator = {
    appCodeName: "Mozilla",
    appName: "Netscape",
    appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
    userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
}

history = {}


div = {
    addEventListener: function (){},
    getAttribute: function (a){
        // console.log("div getAttribute:::",a)
    }
}

body = {}

document = {
    createElement :function (ele){
        // console.log("document createElement:::", ele)
        if(ele==="div"){
            return div
        }
    },
    body : body,
    getElementById: function (ele){
        // console.log('document getElementById:::', ele)
    }
}




// setProxyArr(['window', 'navigator', 'screen', 'document', 'div', 'body'])

ActiveXObject = function () {
}
XMLHttpRequest = function () {
}
addEventListener = function () {
}
attachEvent = function () {
}

setTimeout = function (){}
setInterval = function (){}

运行,控制台日志打印如下:

x::: {
  state: {
    version: '2.28.0',
    fingerprint: '',
    config: null,
    langPkg: null,
    smsNew: false,
    captchaType: null,
    type: '',
    load: null,
    verifyStatus: '',
    token: '',
    previousToken: '',
    countsOfVerifyError: 0,
    startTimestamp: null,
    getApiCount: 0,
    coreOffsetWidth: null
  },
  mutations: {
    INVOKE_HOOK: [Function (anonymous)],
    EVENT_CLOSE: [Function (anonymous)],
    EVENT_RESET: [Function (anonymous)],
    EVENT_RESET_CLASSIC: [Function (anonymous)],
    SWITCH_TYPE: [Function (anonymous)],
    SET_TYPE: [Function (anonymous)],
    SWITCH_LOAD_STATUS: [Function (anonymous)],
    UPDATE_VERIFY_STATUS: [Function (anonymous)],
    REFRESH: [Function (anonymous)],
    UPDATE_COUNTS_OF_VERIFYERROR: [Function (anonymous)],
    SET_TOKEN: [Function (anonymous)],
    UPDATE_LINK_TIME: [Function (anonymous)],
    UPDATE_CORE_WIDTH: [Function (anonymous)]
  },
  actions: {
    RESET_STATE: [Function (anonymous)],
    FETCH_CAPTCHA: [Function (anonymous)],
    FETCH_INTELLISENSE_CAPTCHA: [Function (anonymous)],
    VERIFY_INTELLISENSE_CAPTCHA: [Function (anonymous)],
    VERIFY_CAPTCHA: [Function (anonymous)]
  }
}

发现好像并没有f3这个函数,那怎么办呢?去看看源码

发现它导出的是fC,而fC中并没有直接导出f3这个函数,所以我选择魔改一下源码(有风险,比如别的地方调用index=71的函数,它只返回f3函数)

看看效果:

有值,那cb参数就解决了(可以自己去验证一下),下面来获取token

Part-2:发送第二次请求获取token,并发送第三次请求得到bg_url

获取token代码:

import requests
import execjs
import json



headers = {
    "Accept": "*/*",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Pragma": "no-cache",
    "Referer": "https://dun.163.com/",
    "Sec-Fetch-Dest": "script",
    "Sec-Fetch-Mode": "no-cors",
    "Sec-Fetch-Site": "same-site",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
    "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\""
}
url = "https://c.dun.163.com/api/v3/get"

cb = execjs.compile(open('main.js', encoding='utf-8').read()).call('get_cb')


params = {
    "referer": "https://dun.163.com/trial/sense",
    "zoneId": "CN31",
    "dt": "zQijXPUjJgBERgVVBQaSNzvUtqMaOUd2",
    "id": "5a0e2d04ffa44caba3f740e6a8b0fa84",
    # "fp": "n44S/96DBCqkZK74/8NWVVUBmwUxPPh3nhqISBTuPp90GXvjNlsMH7xIsmYmT5DwK5\\L0YGJKDJLy7kR1+BfyA\\HVVmCR/P2n4n44qixhrZSTYgfgLm68IUWGeg1fJ0L51E68J8YH\\9U4/3zIKp7uUuv2G2nMIYHPTXm0xTicPfWjxBE:1741501721582",
    "https": "true",
    "type": "",
    "width": "",
    "sizeType": "undefined",
    "version": "2.28.0",
    "dpr": "1.5",
    "dev": "1",
    "cb": cb,
    "ipv6": "false",
    "runEnv": "10",
    "group": "",
    "scene": "",
    "sdkVersion": "",
    "loadVersion": "2.5.3",
    "iv": "4",
    "user": "",
    # "irToken": "JEbnid6cWahANgBEEUPScnqDlh4lZacT",
    "smsVersion": "v3",
    "callback": "__JSONP_3b83yve_13"
}
response = requests.get(url, headers=headers, params=params)

response = "{" + response.text.split('({')[1].split('})')[0] + '}'

response = json.loads(response)

token = response['data']['token']

获取bg_url代码,并把背景图保存到本地:

token = '上面代码返回的token'

headers = {
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Pragma': 'no-cache',
    'Referer': 'https://dun.163.com/',
    'Sec-Fetch-Dest': 'script',
    'Sec-Fetch-Mode': 'no-cors',
    'Sec-Fetch-Site': 'same-site',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    # 'Cookie': '_ga=GA.1.22e37b3006ff0.98176d9cabfc959599b3; Hm_lvt_4671c5d502135636b837050ec6d716ce=1741489509; __root_domain_v=.163.com; _qddaz=QD.741141489509450; hb_MA-93D5-9AD06EA4329A_source=cn.bing.com; Hm_lpvt_4671c5d502135636b837050ec6d716ce=1741514096',
}


cb = execjs.compile(open('main.js', encoding='utf-8').read()).call('get_cb')

params = {
    'referer': 'https://dun.163.com/trial/sense',
    'zoneId': 'CN31',
    'dt': 'zQijXPUjJgBERgVVBQaSNzvUtqMaOUd2',
    'irToken': 'HJAQbzuAy1RFNgBBQRbWcn6ZKVAhpKsi',
    'id': '5a0e2d04ffa44caba3f740e6a8b0fa84',
    # 'fp': 'n3Y4iD3JoinePcGGSYGjRO0vJr7c1+N2/ji0BOZtzuTyG3nuimqmEIOt37w3k13wLL5BNs8V0/G6v3BrPfn1HETPuQe4k4ZYdpxQUqlWZKqtpK1A2oozhJCy7XLsJbo\\n+2ISYCS9hdkwK\\Qv/r3KplIH5Nfcrh+57MHDZSk5dLkqMiY:1741514987530',
    'https': 'true',
    'type': '',
    'version': '2.28.0',
    'dpr': '1.5',
    'dev': '1',
    'cb': cb,
    'ipv6': 'false',
    'runEnv': '10',
    'group': '',
    'scene': '',
    'lang': 'zh-CN',
    'sdkVersion': '',
    'loadVersion': '2.5.3',
    'iv': '4',
    'user': '',
    'width': '286',
    'audio': 'false',
    'sizeType': '10',
    'smsVersion': 'v3',
    'token': token,
    'callback': '__JSONP_r7ksz63_8',
}

response = requests.get('https://c.dun.163.com/api/v3/get', params=params,  headers=headers)

response = "{" + response.text.split('({')[1].split('})')[0] + '}'
response = json.loads(response)

data = response['data']

bg_url = data['bg'][0]


with open('bg.jpg', 'wb') as f:
    response = requests.get(url=bg_url).content
    f.write(response)

Part-3:破解第四次请求参数data

这是第四次请求的请求参数:

先是接口定位:

        关键字搜索:'ext'(搜索'data'也行),打上断点

停住了,确实在这里,既然用了webpack,那就一不做二不休,沿用到底

和之前一样的操作,先确定是哪个函数,在调用它,下面是整理后的代码:

但直接调用get_data_是会报错的,而且缺少很多环境,我的做法还是选择魔改源码

还是先看看源码部分,了解一下函数内部逻辑

 'onMouseUp': function(I) {
                    var JB = BZ
                      , O = this[JB(0x31e)];
                    // if (JB(0x78f) === O[JB(0x327)])
                    //     return void Object[JB(0x3a9)](O, {
                    //         'beginTime': 0x0
                    //     });
                    // Object[JB(0x3a9)](O, this['initialDrag']);   // 注释掉的部分大部分是初始化,对函数作用不大,会报环境错误
                    var Z = X[JB(0x3f2)](this['traceData'], q)   // this['traceData']是基于滑块轨迹生成的,  q 是定值50
                      , z = this['$store'][JB(0x2fa)][JB(0x167)]  // z 是 token
                      , H = R(j(z, parseInt(this[JB(0x178)][JB(0x60c)][JB(0x7af)], 0xa) / this[JB(0x758)] * 0x64 + ''))  //  this[JB(0x178)][JB(0x60c)][JB(0x7af)] 疑似滑块终点x坐标(eg.116px);   this[JB(0x758)] 定值286(width,可能每个电脑不一定都一样)
                      , f0 = P(X[JB(0x5da)](this['atomTraceData'], 0x2));  // this['atomTraceData'] 基于滑块轨迹生成的
                    this['onVerifyCaptcha']({
                        'data': JSON[JB(0x3b4)]({
                            'd': R(Z[JB(0x6a5)](':')),
                            'm': '',
                            'p': H,
                            'f': R(j(z, f0['join'](','))),
                            'ext': R(j(z, this['mouseDownCounts'] + ',' + this['traceData']['length']))   // this['mouseDownCounts'] 定值 1
                        })
                    });
                },       

注意看我的注释,看完源码发现,我们还有一些东西要解决:

        1.traceData

        2.atomTraceData

        3.滑块的终点x坐标

控制台打印看看情况:

明显,atomTraceData为真轨迹,而 traceData是基于前者生成的。OK,找traceData的生成逻辑

搜索一下

打上断点,调试

 var f2 = this[JY(0x69d)][JY(0x2fa)][JY(0x167)]  // toekn值
                          , f3 = [Math['round'](z[JY(0x570)] < 0x0 ? 0x0 : z['dragX']), Math[JY(0xd7)](z[JY(0x7a6)] - z[JY(0x727)]), X[JY(0x3af)]() - z[JY(0x6ae)]];  // 滑块轨迹
                        this[JY(0x6a1)][JY(0x375)](f3);  // atomTraceData.push(f3)
                        var f4 = j(f2, f3 + '');     // 这里生成的traceData的元素   
                        this['traceData'][JY(0x375)](f4), 

经过细心观察,发现,f3是滑块轨迹数组,我生成traceData的关键在于j函数,先搞定j函数再考虑滑块轨迹

和之前一样,找到调用的函数,再讲j函数导出

代码如下:

require('./env')
require('./loader')


x = window.loader(71)
console.log('x:::', x)
console.log(x())

function get_cb(){
    return x()
}


J_f8 = window.loader(10)['xorEncode']

function get_track_encrypt(token, arr){
    var track_encrypt = []
    for(i of arr){
       track_encrypt.push( J_f8(token, i + ''))
    }
    return track_encrypt
}




get_data_ = window.loader(36)["_options"]['methods']['onMouseUp']
console.log("get_data_:::", get_data_)

接下来考虑atomtraceData的生成,下面是我的代码(基本和之前一样,不多赘述),毕竟滑块轨迹的生成的基本上不是过滑块的重点,还是用打码平台(得塔云)

from PIL import Image
from io import BytesIO
import base64
import random


class DeTaYun:
    def __init__(self, key, verify_idf_id, img_path):
        self.key = key
        self.img_path = img_path
        self.verify_idf_id = verify_idf_id

    # PIL图片保存为base64编码
    def PIL_base64(self, img, coding='utf-8'):
        img_format = img.format
        if img_format == None:
            img_format = 'JPEG'
        format_str = 'JPEG'
        if 'png' == img_format.lower():
            format_str = 'PNG'
        if 'gif' == img_format.lower():
            format_str = 'gif'
        if img.mode == "P":
            img = img.convert('RGB')
        if img.mode == "RGBA":
            format_str = 'PNG'
            img_format = 'PNG'
        output_buffer = BytesIO()
        img.save(output_buffer, quality=100, format=format_str)
        byte_data = output_buffer.getvalue()
        base64_str = 'data:image/' + img_format.lower() + ';base64,' + \
                     base64.b64encode(byte_data).decode(coding)
        return base64_str

    # 验证码识别接口
    def parse_verify(self):
        url = "https://bq1gpmr8.xiaomy.net//openapi/verify_code_identify/"
        header = {"Content-Type": "application/json"}
        data = {
            # 用户的key
            "key": self.key,
            # 验证码类型
            "verify_idf_id": self.verify_idf_id,
            # 样例图片
            "img_base64": self.PIL_base64(Image.open(self.img_path)),
        }
        # 发送请求调用接口
        response = requests.post(url=url, json=data, headers=header)
        # 获取响应数据,识别结果
        return response.text

def get_slide_x():
    key = "用自己的key"
    verify_idf_id = '6'
    img_path = './bg.jpg'
    detayun = DeTaYun(key, verify_idf_id, img_path)
    distance = int(json.loads(detayun.parse_verify())['data']['distance'] / 320 * 286) + 6
    return distance


x_end = get_slide_x()


x = 0
y = 0
t = random.randint(70, 100)
count = 0
track = []
while x <= x_end:
    track_item = [x, y, t]
    track.append(track_item)
    x += 1
    t += random.randint(5, 10)
    if count % 6 == 0:
        y -= 1
    count += 1

这样traceData,atomtraceData都有了(注意这里的x_end不是js中的,js中的x_end,要再减7),最后来解决data的生成

经过我们上面的操作,我们已经有了魔改get_data_函数的资本

下面是魔改后的代码:

 'onMouseUp': function(traceData, atomTraceData, token, x_end) {
                    var JB = BZ
                      , O = this[JB(0x31e)];
                    // if (JB(0x78f) === O[JB(0x327)])
                    //     return void Object[JB(0x3a9)](O, {
                    //         'beginTime': 0x0
                    //     });
                    // Object[JB(0x3a9)](O, this['initialDrag']);   // 注释掉的部分大部分是初始化,对函数作用不大,会报环境错误
                    var Z = X[JB(0x3f2)](traceData, q)   // this['traceData']是基于滑块轨迹生成的,  q 是定值50
                      , z = token // z 是 token
                      , H = R(j(z, parseInt(x_end + 'px', 0xa) / 286 * 0x64 + ''))  //  this[JB(0x178)][JB(0x60c)][JB(0x7af)] 疑似滑块终点x坐标(eg.116px);   this[JB(0x758)] 定值286(width,可能每个电脑不一定都一样)
                      , f0 = P(X[JB(0x5da)](atomTraceData, 0x2));  // this['atomTraceData'] 基于滑块轨迹生成的
                    // this['onVerifyCaptcha']({
                    //     'data': JSON[JB(0x3b4)]({
                    //         'd': R(Z[JB(0x6a5)](':')),
                    //         'm': '',
                    //         'p': H,
                    //         'f': R(j(z, f0['join'](','))),
                    //         'ext': R(j(z, this['mouseDownCounts'] + ',' + this['traceData']['length']))   // this['mouseDownCounts'] 定值 1
                    //     })
                    // });
                    return {
                        'data': JSON[JB(0x3b4)]({
                            'd': R(Z[JB(0x6a5)](':')),
                            'm': '',
                            'p': H,
                            'f': R(j(z, f0['join'](','))),
                            'ext': R(j(z, 1 + ',' + traceData['length']))   // this['mouseDownCounts'] 定值 1
                        })
                    }
                },

这是main.js中的代码:

require('./env')
require('./loader')


x = window.loader(71)
console.log('x:::', x)
console.log(x())

function get_cb(){
    return x()
}


J_f8 = window.loader(10)['xorEncode']

function get_track_encrypt(token, arr){
    var track_encrypt = []
    for(i of arr){
       track_encrypt.push( J_f8(token, i + ''))
    }
    return track_encrypt
}



get_data_ = window.loader(36)["_options"]['methods']['onMouseUp']

function get_data(track, track_enc, token, x_end){
    return get_data_(track, track_enc, token, x_end)
}

最后再进行代码整合:

python代码:

main.py

import requests
import execjs
import json
from PIL import Image
from io import BytesIO
import base64
import random


class DeTaYun:
    def __init__(self, key, verify_idf_id, img_path):
        self.key = key
        self.img_path = img_path
        self.verify_idf_id = verify_idf_id

    # PIL图片保存为base64编码
    def PIL_base64(self, img, coding='utf-8'):
        img_format = img.format
        if img_format == None:
            img_format = 'JPEG'
        format_str = 'JPEG'
        if 'png' == img_format.lower():
            format_str = 'PNG'
        if 'gif' == img_format.lower():
            format_str = 'gif'
        if img.mode == "P":
            img = img.convert('RGB')
        if img.mode == "RGBA":
            format_str = 'PNG'
            img_format = 'PNG'
        output_buffer = BytesIO()
        img.save(output_buffer, quality=100, format=format_str)
        byte_data = output_buffer.getvalue()
        base64_str = 'data:image/' + img_format.lower() + ';base64,' + \
                     base64.b64encode(byte_data).decode(coding)
        return base64_str

    # 验证码识别接口
    def parse_verify(self):
        url = "https://bq1gpmr8.xiaomy.net//openapi/verify_code_identify/"
        header = {"Content-Type": "application/json"}
        data = {
            # 用户的key
            "key": self.key,
            # 验证码类型
            "verify_idf_id": self.verify_idf_id,
            # 样例图片
            "img_base64": self.PIL_base64(Image.open(self.img_path)),
        }
        # 发送请求调用接口
        response = requests.post(url=url, json=data, headers=header)
        # 获取响应数据,识别结果
        return response.text


def get_slide_x():
    """获取滑块终点位置的x坐标"""
    key = "用自己的key"
    verify_idf_id = '6'
    img_path = './bg.jpg'
    detayun = DeTaYun(key, verify_idf_id, img_path)
    distance = int(json.loads(detayun.parse_verify())['data']['distance'] / 320 * 286) + 6
    return distance


def get_token():
    """发送 ’get?referer‘ 请求,获取token值"""
    headers = {
        "Accept": "*/*",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Pragma": "no-cache",
        "Referer": "https://dun.163.com/",
        "Sec-Fetch-Dest": "script",
        "Sec-Fetch-Mode": "no-cors",
        "Sec-Fetch-Site": "same-site",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
        "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\""
    }
    url = "https://c.dun.163.com/api/v3/get"
    cb = execjs.compile(open('main.js', encoding='utf-8').read()).call('get_cb')
    params = {
        "referer": "https://dun.163.com/trial/sense",
        "zoneId": "CN31",
        "dt": "zQijXPUjJgBERgVVBQaSNzvUtqMaOUd2",
        "id": "5a0e2d04ffa44caba3f740e6a8b0fa84",
        "https": "true",
        "type": "",
        "width": "",
        "sizeType": "undefined",
        "version": "2.28.0",
        "dpr": "1.5",
        "dev": "1",
        "cb": cb,
        "ipv6": "false",
        "runEnv": "10",
        "group": "",
        "scene": "",
        "sdkVersion": "",
        "loadVersion": "2.5.3",
        "iv": "4",
        "user": "",
        "smsVersion": "v3",
        "callback": "__JSONP_3b83yve_13"
    }

    response = requests.get(url, headers=headers, params=params)
    response = "{" + response.text.split('({')[1].split('})')[0] + '}'
    response = json.loads(response)

    return response['data']['token']


def get_bg_url(token):
    """获取背景图网址"""
    headers = {
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Pragma': 'no-cache',
        'Referer': 'https://dun.163.com/',
        'Sec-Fetch-Dest': 'script',
        'Sec-Fetch-Mode': 'no-cors',
        'Sec-Fetch-Site': 'same-site',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
        'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
    }
    cb = execjs.compile(open('main.js', encoding='utf-8').read()).call('get_cb')
    params = {
        'referer': 'https://dun.163.com/trial/sense',
        'zoneId': 'CN31',
        'dt': 'zQijXPUjJgBERgVVBQaSNzvUtqMaOUd2',
        'irToken': 'HJAQbzuAy1RFNgBBQRbWcn6ZKVAhpKsi',
        'id': '5a0e2d04ffa44caba3f740e6a8b0fa84',
        'https': 'true',
        'type': '',
        'version': '2.28.0',
        'dpr': '1.5',
        'dev': '1',
        'cb': cb,
        'ipv6': 'false',
        'runEnv': '10',
        'group': '',
        'scene': '',
        'lang': 'zh-CN',
        'sdkVersion': '',
        'loadVersion': '2.5.3',
        'iv': '4',
        'user': '',
        'width': '286',
        'audio': 'false',
        'sizeType': '10',
        'smsVersion': 'v3',
        'token': token,
        'callback': '__JSONP_r7ksz63_8',
    }

    response = requests.get('https://c.dun.163.com/api/v3/get', params=params, headers=headers)
    response = "{" + response.text.split('({')[1].split('})')[0] + '}'
    response = json.loads(response)
    data = response['data']

    return data['bg'][0]


def get_bg(bg_url):
    """将背景图保存到本地"""
    response = requests.get(url=bg_url)
    with open('bg.jpg', 'wb') as f:
        f.write(response.content)


def get_track_raw(x_end):
    """生成原始的,未经加工的滑块轨迹"""
    x = 0
    y = 0
    t = random.randint(70, 100)
    count = 0
    track = []
    while x <= x_end:
        track_item = [x, y, t]
        track.append(track_item)
        x += 1
        t += random.randint(5, 10)
        if count % 6 == 0:
            y -= 1
        count += 1

    return track


def get_track_enc(token, track):
    """获得经过加密处理的滑块轨迹"""
    return execjs.compile(open('main.js', encoding='utf-8').read()).call('get_track_encrypt', token, track)


def get_data(track, track_encrypt, token, x_end):
    """护额的请求参数data"""
    return execjs.compile(open('main.js', encoding='utf-8').read()).call('get_data', track, track_encrypt, token, x_end)['data']


def get_verify(token, data):
    """完成验证请求"""
    headers = {
        "Accept": "*/*",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Pragma": "no-cache",
        "Referer": "https://dun.163.com/",
        "Sec-Fetch-Dest": "script",
        "Sec-Fetch-Mode": "no-cors",
        "Sec-Fetch-Site": "same-site",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
        "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\""
    }
    url = "https://c.dun.163.com/api/v3/check"
    cb = execjs.compile(open('main.js', encoding='utf-8').read()).call('get_cb')
    params = {
        "referer": "https://dun.163.com/trial/sense",
        "zoneId": "CN31",
        "dt": "zQijXPUjJgBERgVVBQaSNzvUtqMaOUd2",
        "id": "5a0e2d04ffa44caba3f740e6a8b0fa84",
        "token": token,
        "data": data,
        "width": "286",
        "type": "2",
        "version": "2.28.0",
        "cb": cb,
        "user": "",
        "extraData": "",
        "bf": "0",
        "runEnv": "10",
        "sdkVersion": "",
        "loadVersion": "2.5.3",
        "iv": "4",
        "callback": "__JSONP_wootm5k_91"
    }
    response = requests.get(url, headers=headers, params=params)
    response = "{" + response.text.split('({')[1].split('})')[0] + '}'
    response = json.loads(response)
    result = response['data']['result']
    if result:
        print('validate:::', response['data']['validate'])
        return response['data']['validate']
    else:
        return 0


def main():
    """总操作"""
    token = get_token()
    bg_url = get_bg_url(token=token)
    get_bg(bg_url=bg_url)
    x_end = get_slide_x()
    track = get_track_raw(x_end=x_end)
    track_enc = get_track_enc(token=token, track=track)
    x_end -= 7
    data = get_data(track=track, track_encrypt=track_enc, token=token, x_end=x_end)
    res = get_verify(token=token, data=data)
    count = 0
    while res == 0:
        print(f"第{count}次验证失败,正在重新验证!!!")
        token = get_token()
        bg_url = get_bg_url(token=token)
        get_bg(bg_url=bg_url)
        x_end = get_slide_x()
        track = get_track_raw(x_end=x_end)
        track_enc = get_track_enc(token=token, track=track)
        x_end -= 7
        data = get_data(track=track, track_encrypt=track_enc, token=token, x_end=x_end)
        res = get_verify(token=token, data=data)
        count += 1
    print("程序结束!!!")

if __name__ == "__main__":
    main()


JS代码:

main.js

require("./env")
require('./loader')


x = window.loader(71)
function get_cb(){
    return x()
}


J_f8 = window.loader(10)['xorEncode']
function get_track_encrypt(token, arr){
    var track_encrypt = []
    for(i of arr){
       track_encrypt.push( J_f8(token, i + ''))
    }
    return track_encrypt
}


get_data_ = window.loader(36)["_options"]['methods']['onMouseUp']
function get_data(track, track_enc, token, x_end){
    return get_data_(track, track_enc, token, x_end)
}

env.js

window = self = top = global

delete global;  // 记得用 _global = global 备份一下
delete Buffer;
delete __filename;
delete __dirname;

screen = {}

location = {
    "ancestorOrigins": {},
    "href": "https://dun.163.com/trial/sense",
    "origin": "https://dun.163.com",
    "protocol": "https:",
    "host": "dun.163.com",
    "hostname": "dun.163.com",
    "port": "",
    "pathname": "/trial/sense",
    "search": "",
    "hash": ""
}

navigator = {
    appCodeName: "Mozilla",
    appName: "Netscape",
    appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
    userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
}

history = {}


div = {
    addEventListener: function (){},
    getAttribute: function (a){
        // console.log("div getAttribute:::",a)
    }
}

body = {}

document = {
    createElement :function (ele){
        // console.log("document createElement:::", ele)
        if(ele==="div"){
            return div
        }
    },
    body : body,
    getElementById: function (ele){
        // console.log('document getElementById:::', ele)
    }
}



ActiveXObject = function () {}
XMLHttpRequest = function () {}
addEventListener = function () {}
attachEvent = function () {}
setTimeout = function (){}
setInterval = function (){}

loader.js注意按照我上面的代码魔改就行(文件太大了,就不放这了)

最后再运行一下,看看效果:

拿到validate,成功搞定

END

这一篇博客和上一篇做法几乎相同,希望对读者有帮助,有问题评论区留言

最后感谢观看,原创不易,点赞关注支持一下!

您好!要安装逆向网易易盾滑块验证,您需要按照以下步骤进行操作: 1. 在您的项目中引入网易易盾滑块验证的 JavaScript SDK。可以通过在页面的 `<head>` 标签中插入如下代码来加载 SDK: ```html <script src="//nosdn.127.net/yidun/2.17.0/yidun.js"></script> ``` 2. 在页面中设置一个用于展示滑块验证的容器元素。在合适的位置插入如下代码: ```html <div id="captcha"></div> ``` 3. 在页面中初始化滑块验证。在页面加载完成后,调用 `init` 方法进行初始化操作,并传入相关参数。示例代码如下: ```javascript window.onload = function() { var options = { captchaId: 'YOUR_CAPTCHA_ID', mode: 'popup', width: '300px', onVerify: function(err, data) { if (err) { // 验证失败,请进行相应处理 } else { // 验证成功,请进行相应处理 } } }; var nc=initNECaptcha(options, function (instance) { // 初始化成功后得到验证实例 instance,可以调用实例的方法 }, function (err) { // 初始化失败后触发该函数,例如网络错误,cdn 地址无法访问等 }); } ``` 在上述代码中,您需要将 `YOUR_CAPTCHA_ID` 替换为您在网易易盾申请的验证码 ID。此外,您还可以根据需要自定义其他参数,比如 `mode`(弹出框模式)、`width`(滑块宽度)等。 注意:为了确保安全性,强烈建议将验证请求发送到服务器进行二次校验,以防止客户端被篡改。 希望以上信息对您有所帮助!如果您有任何其他问题,请随时提问。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值