JS逆向进阶篇【去哪儿旅行登录】【中篇-滑动轨迹破解补浏览器环境破参数】

news2025/3/13 23:56:41

目录:

  • 每篇前言:
  • 0、整体分析
  • 1、逆向轨迹snapshot
    • (1)分析:
    • (2)Python轨迹生成:
    • (3)AES加密:
    • (4)轨迹+加密:
    • (5)整体请求:
  • 2、逆向提交sendLoginCode
      • (1)页面中测试js是否可用:
      • (2)构造浏览器环境执行:
      • 本部分代码整合:
  • 3、短信登录

每篇前言:

  • 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者

  • 🔥🔥本文已收录于爬虫进阶+实战系列教程专栏:《爬虫进阶+实战系列教程》
  • 🔥🔥热门专栏推荐:《Python全栈系列教程》、《爬虫从入门到精通系列教程》、《爬虫进阶+实战系列教程》、《Scrapy框架从入门到实战》、《Flask框架从入门到实战》、《Django框架从入门到实战》、《Tornado框架从入门到实战》、《前端系列教程》。
  • 📝​📝本专栏面向广大程序猿,为的是大家都做到Python全栈技术从入门到精通,穿插有很多实战优化点。
  • 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
  • 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!

在这里插入图片描述

0、整体分析

手动过滑动校验后,分析请求:
在这里插入图片描述
发现滑完滑块后,内部会发两个请求,这两个请求发送成功之后才会发送短信验证码,所以先来看看这俩请求。
而第一个请求的response中的cst的值又是第二个请求的参数,所以逐个分析~

1、逆向轨迹snapshot

(1)分析:

关键参数是data:
在这里插入图片描述
打断点:
在这里插入图片描述
在这里插入图片描述
往上找r:

在这里插入图片描述
简单分析可知是从上一个请求传来的:
在这里插入图片描述
往上找a:
在这里插入图片描述
在这里插入图片描述
分析上图,关键是sliderInfo哪里来的,最终a的值是经过AES加密。
sliderInfo数据结构如下图,其中有多个值:
在这里插入图片描述
当前js文件中搜索sliderInfo,共有七处有,都是给sliderInfo里添加值,此部分js代码如下:

var $ = function(e) {
                function u(e) {
                    var t;
                    !function(e, t) {
                        if (!(e instanceof t))
                            throw new TypeError("Cannot call a class as a function")
                    }(this, u),
                    W(U(t = o.call(this, e)), "onMouseDown", function(e) {
                        if (!t.state.requestSuccess) {
                            e.stopPropagation && e.stopPropagation();
                            var n = (e.changedTouches || e.touches || [e])[0];
                            t.sliderInfo.startTime = Date.now(),
                            t.btn.style.transition = "",
                            t.bg.style.transition = "";
                            e = e || window.event;
                            t.downX = n.clientX;
                            var r = U(t);
                            t.setState({
                                downX: n.clientX
                            }),
                            document.addEventListener(r.move, r.onMouseMove, {
                                passive: !1
                            }),
                            document.addEventListener(r.up, r.onMouseUp, !1)
                        }
                    }),
                    W(U(t), "onMouseMove", function(e) {
                        var n = t.state.downX
                          , r = t.props
                          , i = r.onFinished
                          , s = r.resCookies;
                        e.preventDefault && e.preventDefault();
                        var o = (e.changedTouches || e.touches || [e])[0]
                          , u = (e = e || window.event,
                        o.clientX - n);
                        if (t.state.requestSuccess || t.handleTouchMove(e, u),
                        u > t.distance ? u = t.distance : u < 0 && (u = 0),
                        t.btn.style.left = u + "px",
                        t.bg.style.width = u + "px",
                        t.btn.style.borderRadius = "0 8px 8px 0",
                        u >= t.distance && !t.flag && (t.flag = !0)) {
                            t.sliderInfo.endTime = Date.now();
                            var a = t.encryption()
                              , f = U(t);
                            c.ajax({
                                url: V,
                                type: "POST",
                                dataType: "JSON",
                                data: {
                                    data: a,
                                    orca: 2,
                                    appCode: t.props.appCode,
                                    cs: X()
                                },
                                success: function(e) {
                                    var t, n, r = {};
                                    try {
                                        r = JSON.parse(e)
                                    } catch (e) {}
                                    !0 === s && function(e) {
                                        for (var t in e)
                                            if (e.hasOwnProperty(t)) {
                                                var n = e[t];
                                                "object" === H(n) ? M.a.set(t, n.value, D(D({}, B), n.option)) : M.a.set(t, n, B)
                                            }
                                    }((null === (n = r.data) || void 0 === n ? void 0 : n.vcd) || {});
                                    null !== (t = r.data) && void 0 !== t && t.cst ? (u = f.distance,
                                    f.text.innerHTML = "验证码发送",
                                    f.text.style.color = "#fff",
                                    f.iconfont.innerHTML = "&#xea55;",
                                    f.iconfont.style.color = "#00AE44",
                                    f.btn.style.border = "1px solid #00AE44",
                                    f.bg.style.backgroundColor = "#00AE44",
                                    f.setState({
                                        requestSuccess: !0
                                    }),
                                    f.btn.removeEventListener(f.start, f.onMouseDown, !1),
                                    i && i({
                                        result: !0,
                                        cst: r.data.cst
                                    })) : (u = f.distance,
                                    f.text.innerHTML = "验证失败, 请重试",
                                    f.text.style.color = "#fff",
                                    f.iconfont.innerHTML = "&#xea52;",
                                    f.iconfont.style.color = "#C92222",
                                    f.btn.style.border = "1px solid #C92222",
                                    f.bg.style.backgroundColor = "#C92222",
                                    f.setState({
                                        requestSuccess: !1
                                    }),
                                    i && i({
                                        result: !1,
                                        cst: ""
                                    }))
                                },
                                error: function(e) {
                                    u = 0,
                                    i && i({
                                        result: !1,
                                        cst: ""
                                    })
                                }
                            }),
                            document.removeEventListener(t.move, t.onMouseMove)
                        }
                    }),
                    W(U(t), "onMouseUp", function(e) {
                        t.flag || (t.btn.style.left = 0,
                        t.btn.style.borderRadius = "8px",
                        t.bg.style.width = 0,
                        t.btn.style.transition = "left 1s ease",
                        t.bg.style.transition = "width 1s ease",
                        document.removeEventListener(t.move, t.onMouseMove),
                        document.removeEventListener(t.up, t.onMouseDown))
                    }),
                    W(U(t), "handleTouchMove", A(function(e, n) {
                        var r = U(t)
                          , i = Date.now() % 1e5
                          , s = (e.changedTouches || e.touches || [e])[0]
                          , o = s.clientX.toFixed(2)
                          , u = s.clientY.toFixed(2)
                          , a = n.toFixed(2)
                          , f = "".concat(i, ";").concat(o, ";").concat(u, ";").concat(a);
                        t.sliderInfo.track.push(f),
                        window.addEventListener("deviceorientation", function(e) {
                            r.sliderInfo.deviceMotion.push(e)
                        }, !1)
                    }, 20)),
                    t.state = {
                        downX: 0,
                        requestSuccess: !1
                    },
                    t.sliderInfo = {
                        openTime: 0,
                        startTime: 0,
                        endTime: 0,
                        userAgent: window.navigator.userAgent,
                        uid: h("QN1"),
                        track: [],
                        acc: [],
                        ori: [],
                        deviceMotion: []
                    },
                    t.distance = 0;
                    var n = "pc" === X();
                    return t.start = n ? "mousedown" : "touchstart",
                    t.move = n ? "mousemove" : "touchmove",
                    t.end = n ? "mouseup" : "touchend",
                    t
                }
                !function(e, t) {
                    if ("function" != typeof t && null !== t)
                        throw new TypeError("Super expression must either be null or a function");
                    e.prototype = Object.create(t && t.prototype, {
                        constructor: {
                            value: e,
                            writable: !0,
                            configurable: !0
                        }
                    }),
                    t && I(e, t)
                }(u, e);
                var t, n, r, o = q(u);
                return t = u,
                (n = [{
                    key: "getDom",
                    value: function() {
                        var e = this.drag
                          , t = this.btn;
                        this.distance = e.offsetWidth - t.offsetWidth
                    }
                }, {
                    key: "componentDidMount",
                    value: function() {
                        this.sliderInfo.openTime = Date.now(),
                        this.getDom(),
                        this.btn.addEventListener(this.start, this.onMouseDown, !1)
                    }
                }, {
                    key: "prohibitMouse",
                    value: function() {}
                }, {
                    key: "encryption",
                    value: function() {
                        var e = JSON.stringify(this.sliderInfo);
                        return d.AES.encrypt(d.enc.Utf8.parse(e), d.enc.Utf8.parse("227V2xYeHTARSh1R"), {
                            mode: d.mode.ECB,
                            padding: d.pad.Pkcs7
                        }).toString()
                    }
                }, {
                    key: "init",
                    value: function() {
                        this.setState({
                            requestSuccess: !1
                        }),
                        this.text.innerHTML = "请按住滑块, 拖到最右边",
                        this.text.style.color = "#000",
                        this.iconfont.innerHTML = "&#xe68f;",
                        this.btn.style.left = 0,
                        this.bg.style.width = 0,
                        this.btn.style.borderRadius = "8px",
                        this.btn.style.border = "1px solid #00AE44",
                        this.iconfont.style.color = "#000",
                        this.btn.style.transition = "left 1s ease",
                        this.bg.style.transition = "width 1s ease",
                        this.flag = !1
                    }
                }, {
                    key: "render",
                    value: function() {
                        var e = this
                          , t = this.props.diyWidth || ("pc" == X() ? "484px" : "290px");
                        return i.a.createElement("div", {
                            className: s.drag,
                            ref: function(t) {
                                return e.drag = t
                            },
                            style: {
                                width: t
                            }
                        }, i.a.createElement("div", {
                            className: s.bg,
                            ref: function(t) {
                                return e.bg = t
                            }
                        }), i.a.createElement("div", {
                            className: s.text,
                            onselectstart: "return false",
                            ref: function(t) {
                                return e.text = t
                            }
                        }, "请按住滑块, 拖到最右边"), i.a.createElement("div", {
                            className: s.btn,
                            ref: function(t) {
                                return e.btn = t
                            },
                            onClick: function() {
                                return e.init()
                            }
                        }, i.a.createElement("i", {
                            ref: function(t) {
                                return e.iconfont = t
                            },
                            className: s.iconfont
                        }, "")))
                    }
                }]) && F(t.prototype, n),
                r && F(t, r),
                u
            }

这部分代码就是滑动轨迹相关信息处理部分,和上篇文章中模拟实现的是一样的!

  • startTime是开始滑动时间戳在这里插入图片描述

  • endTime是滑动结束时间戳:
    在这里插入图片描述

  • openTime猜测是检测打开网站的时间戳:
    在这里插入图片描述

  • track里是生成的轨迹信息:
    在这里插入图片描述

  • uid就是从cookie中获取QN1的值

  • deviceMotion值是不定个数的{"isTrusted": true},直接Python构造即可,这个不用分析;
    在这里插入图片描述

下面用Python实现:

(2)Python轨迹生成:

import random
import time


def get_slider_info():
    slider_list = []
	
	# 起始点位置可随意指定,因为浏览器大小不定~
    client_x = 300
    client_y = 500
    
    start_time = int(int(time.time() * 1000) % 1e5)
    
    width = random.randint(419, 431)  # 滑动总长度
    for slide_distance in range(3, width, 26):
        if width - slide_distance <= 26:
            slide_distance = width
        start_time += random.randint(10, 1000)
        i = start_time
        o = f"{client_x + slide_distance}.00"
        u = f"{client_y + random.randint(-5, 5)}.00"
        a = f"{slide_distance}.00"
        f = f"{i};{o};{u};{a}"
        slider_list.append(f)

    return slider_list


def run():
    stdlib_list = get_slider_info()
    print(stdlib_list)


if __name__ == '__main__':
    run()

在这里插入图片描述

(3)AES加密:

安装三方库pycryptodome:

pip install pycryptodome
import base64
import binascii
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

data_str = ''
key_string = ""
key = binascii.a2b_hex(key_string)

aes = AES.new(
    key=key,
    mode=AES.MODE_ECB
)
raw = pad(data_str.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
res = base64.b64encode(aes_bytes)
print(res)

(4)轨迹+加密:

import base64
import binascii
import json
import random
import time

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


def get_slider_list():
    slider_list = []

    client_x = 300
    client_y = 500
    start_time = int(int(time.time() * 1000) % 1e5)

    width = random.randint(419, 431)
    for slide_distance in range(3, width, 26):
        if width - slide_distance <= 26:
            slide_distance = width
        start_time += random.randint(10, 1000)
        i = start_time
        o = f"{client_x + slide_distance}.00"
        u = f"{client_y + random.randint(-5, 5)}.00"
        a = f"{slide_distance}.00"
        f = f"{i};{o};{u};{a}"
        slider_list.append(f)

    return slider_list


def aes_encrypt(data_str):
    key_string = ""
    key = binascii.a2b_hex(key_string)

    aes = AES.new(
        key=key,
        mode=AES.MODE_ECB
    )
    raw = pad(data_str.encode('utf-8'), 16)
    aes_bytes = aes.encrypt(raw)
    res_str = base64.b64encode(aes_bytes).decode('utf-8')
    return res_str


def run():
    cookie_qn1 = ""
    slider_list = get_slider_list()
    slider_info = {
        "openTime": int((time.time() - random.randint(500, 3000)) * 1000),
        "startTime": int((time.time() - random.uniform(2, 4)) * 1000),
        "endTime": int((time.time() - random.uniform(0, 1)) * 1000),
        "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
        "uid": cookie_qn1,
        "track": slider_list,
        "acc": [],
        "ori": [],
        "deviceMotion": [{"isTrusted": True} for _ in range(random.randint(10, 100))]
    }
    # separators参数的作用:不加的话data_str里是有空格的,而JS中json序列化的结果json串没有空格!
    data_str = json.dumps(slider_info, separators=(',', ";"))
    data = aes_encrypt(data_str)

    r = {
        "appCode": "register_pc",
        "CS": "pc",
        "data": data,
        "orca": 2
    }
    print(r)


if __name__ == '__main__':
    run()

(5)整体请求:

import base64
import binascii
import json
import random
import time

import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


def get_slider_list():
    slider_list = []

    client_x = 300
    client_y = 500
    start_time = int(int(time.time() * 1000) % 1e5)

    width = random.randint(419, 431)
    for slide_distance in range(3, width, 26):
        if width - slide_distance <= 26:
            slide_distance = width
        start_time += random.randint(10, 1000)
        i = start_time
        o = f"{client_x + slide_distance}.00"
        u = f"{client_y + random.randint(-5, 5)}.00"
        a = f"{slide_distance}.00"
        f = f"{i};{o};{u};{a}"
        slider_list.append(f)

    return slider_list


def aes_encrypt(data_str):
    # ori_key = "227V2xYeHTARSh1R"
    # key_string = ""
    # for char in ori_key:
    #     ascii_value = ord(char)
    #     key_string += str(ascii_value)
    key_string = "32323756327859654854415253683152"
    key = binascii.a2b_hex(key_string)

    aes = AES.new(
        key=key,
        mode=AES.MODE_ECB
    )
    raw = pad(data_str.encode('utf-8'), 16)
    aes_bytes = aes.encrypt(raw)
    res_str = base64.b64encode(aes_bytes).decode('utf-8')
    return res_str


def run():
    res = requests.get("https://user.qunar.com/passport/login.jsp")
    cookie_dict = res.cookies.get_dict()
    cookie_qn1 = cookie_dict['QN1']

    slider_list = get_slider_list()
    slider_info = {
        "openTime": int((time.time() - random.randint(500, 3000)) * 1000),
        "startTime": int((time.time() - random.uniform(2, 4)) * 1000),
        "endTime": int((time.time() - random.uniform(0, 1)) * 1000),
        "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
        "uid": cookie_qn1,
        "track": slider_list,
        "acc": [],
        "ori": [],
        "deviceMotion": [{"isTrusted": True} for _ in range(random.randint(10, 100))]
    }
    # separators参数的作用:不加的话data_str里是有空格的,而JS中json序列化的结果没有空格!
    data_str = json.dumps(slider_info, separators=(',', ";"))
    data = aes_encrypt(data_str)

    r = {
        "appCode": "register_pc",
        "CS": "pc",
        "data": data,
        "orca": 2
    }

    res = requests.post(
        url="https://vercode.qunar.com/inner/captcha/snapshot",
        json=r,
        cookies=cookie_dict
    )
    print(res.text)


if __name__ == '__main__':
    run()

在这里插入图片描述

2、逆向提交sendLoginCode

slideToken已搞定,关键参数:bella
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
碰到形如调用window.Bella()这种函数实现加密的情况,逆向思路就不再是一点点扣,而是:

  • 找到放这个函数的js文件,把整个js文件都拿过来
  • 通过window.Bella()调用,一点点补环境,修改直到正常生成!

实操流程,分为两大步:

  1. 需要将对应js文件放到一个HTML页面中运行,通过浏览器测试,如果能正常,再来第二步
  2. 构造浏览器环境去运行。

对应js文件:
在这里插入图片描述

(1)页面中测试js是否可用:

sdk.js里就是上述整个js文件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="sdk.js"></script>
<script>
    var bella = window.Bella({sliderToken: "0d3e90cdc732af482e4b04ffd0c2e123"}, {v: 2})
    console.log(bella)
</script>
</body>
</html>

浏览器打开这个页面,F12看console:
在这里插入图片描述
然后cv这个bella,发送请求测试是否成功,结果是OK的!

(2)构造浏览器环境执行:

这次使用subprocess库来使用node执行js代码:

import subprocess

res = subprocess.check_output('node sdk.js', shell=True)
data_str = res.decode('utf-8')
print(data_str)

报错:
在这里插入图片描述
缺少window,直接将上篇的基础浏览器环境代码拿来放到sdk.js文件中,注意将相应值更改为当前网站对应的值:

const jsdom = require("jsdom");
const {JSDOM} = jsdom;

const html = '<!DOCTYPE html><p>Hello world</p>';
const dom = new JSDOM(html, {
    url: "https://user.qunar.com/passport/login.jsp",
    referer: "https://www.qunar.com",
    contentType: "text/html"
});

document = dom.window.document;

window = global;
Object.assign(global, {
    location: {
        hash: "",
        host: "user.qunar.com",
        hostname: "user.qunar.com",
        href: "https://user.qunar.com/passport/login.jsp",
        origin: "https://user.qunar.com",
        pathname: "/passport/login.jsp",
        port: "",
        protocol: "https:",
        search: "",
    },
    navigator: {
        appCodeName: "Mozilla",
        appName: "Netscape",
        appVersion: "5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
        cookieEnabled: true,
        deviceMemory: 8,
        doNotTrack: null,
        hardwareConcurrency: 4,
        language: "zh-CN",
        languages: ["zh-CN", "zh"],
        maxTouchPoints: 0,
        onLine: true,
        platform: "MacIntel",
        product: "Gecko",
        productSub: "20030107",
        userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
        vendor: "Google Inc.",
        vendorSub: "",
        webdriver: false
    }
});

再次运行,报错:
在这里插入图片描述
知识补给:

在 JavaScript 中,ActiveXObject(‘Microsoft.XMLHTTP’) 用于创建一个用于发送异步 HTTP 请求的对象。这是一种在旧版本的 Internet Explorer 浏览器中创建 XMLHTTP 对象的方法,用于实现 Ajax(Asynchronous JavaScript and XML)。

定位到JS中对应位置:
在这里插入图片描述
可知这个if判断在检测不到window.XMLHttpRequest的时候才会执行这个玩意,上篇文章讲过如何补XMLHttpRequest,所以直接补这个:

XMLHttpRequest = function() {
	return {
		open: function(){},
		setRequestHeader: function(){},
		send: function(){}
	}
}
window.XMLHttpRequest = XMLHttpRequest;

再运行,就发现会卡在这,这时候该怎么办呢?
在这里插入图片描述
可以尝试找一下window.Bella关键字,如果我们需要的window.Bella的所有加密逻辑在导致上述问题的代码逻辑之上,那直接将window.Bella这之后的代码给断掉,不就解决了吗!
在这里插入图片描述
在这里插入图片描述
再次运行:
在这里插入图片描述
将slideToken通过参数形式传递:

        var bella = window.Bella({slideToken: process.argv[2]}, {v: 2});
        console.log(bella);

        process.exit();     // 主动让js程序退出
import subprocess

res = subprocess.check_output('node sdk.js "0d3e90cdc732af482e4b04ffd0c2e123"', shell=True)
data_str = res.decode('utf-8')
print(data_str)

本部分代码整合:

import base64
import binascii
import json
import random
import time

import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


def get_slider_list():
    slider_list = []

    client_x = 300
    client_y = 500
    start_time = int(int(time.time() * 1000) % 1e5)

    width = random.randint(419, 431)
    for slide_distance in range(3, width, 26):
        if width - slide_distance <= 26:
            slide_distance = width
        start_time += random.randint(10, 1000)
        i = start_time
        o = f"{client_x + slide_distance}.00"
        u = f"{client_y + random.randint(-5, 5)}.00"
        a = f"{slide_distance}.00"
        f = f"{i};{o};{u};{a}"
        slider_list.append(f)

    return slider_list


def aes_encrypt(data_str):
    # ori_key = "227V2xYeHTARSh1R"
    # key_string = ""
    # for char in ori_key:
    #     ascii_value = ord(char)
    #     key_string += str(ascii_value)
    key_string = "32323756327859654854415253683152"
    key = binascii.a2b_hex(key_string)

    aes = AES.new(
        key=key,
        mode=AES.MODE_ECB
    )
    raw = pad(data_str.encode('utf-8'), 16)
    aes_bytes = aes.encrypt(raw)
    res_str = base64.b64encode(aes_bytes).decode('utf-8')
    return res_str


def run():
    res = requests.get("https://user.qunar.com/passport/login.jsp")
    cookie_dict = res.cookies.get_dict()
    cookie_qn1 = cookie_dict['QN1']

    slider_list = get_slider_list()
    slider_info = {
        "openTime": int((time.time() - random.randint(500, 3000)) * 1000),
        "startTime": int((time.time() - random.uniform(2, 4)) * 1000),
        "endTime": int((time.time() - random.uniform(0, 1)) * 1000),
        "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
        "uid": cookie_qn1,
        "track": slider_list,
        "acc": [],
        "ori": [],
        "deviceMotion": [{"isTrusted": True} for _ in range(random.randint(10, 100))]
    }
    # separators参数的作用:不加的话data_str里是有空格的,而JS中json序列化的结果没有空格!
    data_str = json.dumps(slider_info, separators=(',', ";"))
    data = aes_encrypt(data_str)

    r = {
        "appCode": "register_pc",
        "CS": "pc",
        "data": data,
        "orca": 2
    }

    res = requests.post(
        url="https://vercode.qunar.com/inner/captcha/snapshot",
        json=r,
        cookies=cookie_dict
    )
    res_dict = res.json()
    slide_token = res_dict['data']['cst']
    cookie_dict.update(res.cookies.get_dict())

    import subprocess

    res = subprocess.check_output(f'node sdk.js "{slide_token}"', shell=True)
    bella_string = res.decode('utf-8').strip()

    res = requests.post(
        url="https://user.qunar.com/weblogin/sendLoginCode",
        data={
            "usersource": "",
            "source": "",
            "ret": "",
            "business": "",
            "pid": "",
            "originChannel": "",
            "activityCode": "",
            "origin": "",
            "mobile": "手机号",
            "prenum": "86",
            "loginSource": "1",
            "slideToken": slide_token,
            "smsType": "0",
            "appcode": "register_pc",
            "bella": bella_string,
            "captchaType": ""
        },
        cookies=cookie_dict
    )
    print(res.text)


if __name__ == '__main__':
    run()

3、短信登录

发送短信的payload都有了:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1458433.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java EE初阶二十】关于http(一)

1. 初识http HTTP 最新的版本应该是 HTTP/3.0&#xff0c;目前大规模使用的版本 HTTP/1.1&#xff1b; 下面来简单说明一下使用 HTTP 协议的场景: 1、浏览器打开网站 (基本上) 2、手机 APP 访问对应的服务器 (大概率) 前面的 TCP与UDP 和http不同&#xff0c;HTTP 的报文格式&a…

Java实现自动化pdf打水印小项目 使用技术pdfbox、Documents4j

文章目录 前言源码获取一、需求说明二、 调研pdf处理工具word处理工具 三、技术栈选择四、功能实现实现效果详细功能介绍详细代码实现项目目录WordUtilsMain类实现部分&#xff1a;第一部分Main类实现部分&#xff1a;第二部分Main类实现部分&#xff1a;第三部分 资料获取 前言…

如何保护文件夹数据?怎么加密文件夹数据?

文件夹是电脑储存、管理数据的重要工具&#xff0c;为了避免文件夹数据泄露&#xff0c;我们需要加密保护文件夹。那么&#xff0c;怎么加密文件夹呢&#xff1f;下面我们就来了解一下。 如何避免文件夹数据泄露&#xff1f; 保护文件夹数据安全的方法有很多&#xff0c;例如…

QT-地形3D

QT-地形3D 一、 演示效果二、关键程序三、下载链接 一、 演示效果 二、关键程序 #include "ShaderProgram.h"namespace t3d::core {void ShaderProgram::init() {initializeOpenGLFunctions();loadShaders(); }void ShaderProgram::addShader(const QString &fil…

C++-带你初步走进继承(1)

1.继承的概念及定义 1.1继承的概念 继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段&#xff0c;它允许程序员在 保 持原有类特性的基础上进行扩展 &#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承 呈现了面向对象 …

在线SM3 HMAC加密工具

在线HMAC加密工具提供一站式服务&#xff0c;支持MD5至SHA512、RIPEMD160及SM3等多种哈希算法&#xff0c;用户可便捷选择算法并生成安全的HMAC散列值&#xff0c;确保消息完整性与验证来源。适用于开发调试、网络安全测试及敏感数据处理场景。 在线HMAC加密 - BTool在线工具软…

OpenAI视频生成模型Sora的全面解析:从ViViT、Diffusion Transformer到NaViT、VideoPoet

前言 真没想到&#xff0c;距离视频生成上一轮的集中爆发(详见《Sora之前的视频生成发展史&#xff1a;从Gen2、Emu Video到PixelDance、SVD、Pika 1.0》)才过去三个月&#xff0c;没想OpenAI一出手&#xff0c;该领域又直接变天了 自打2.16日OpenAI发布sora以来(其开发团队包…

基于数字双输入的超宽带(0.7-3.1GHz)Doherty功率放大器设计-从理论到ADS版图

基于数字双输入的超宽带(0.7-3.1GHz)Doherty功率放大器设计-从理论到ADS版图 参考论文: 高效连续型射频功率放大器研究 假期就要倒计时啦&#xff0c;估计是寒假假期的最后一个博客&#xff0c;希望各位龙年工作顺利&#xff0c;学业有成。 全部工程下载&#xff1a;基于数字…

企业总部与分部通过DSVPN实现互联

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle OC…

云上业务一键性能调优,应用程序性能诊断工具 Btune 上线

- 01 - 终于等来了预算&#xff0c;这就把服务迁移到最新的 CPU 平台上去&#xff0c;这样前端的同事立马就能感受我们带来的速度提升了。可是…… 这些性能指标怎么回事&#xff1f;不仅没有全面提升&#xff0c;有些反而下降了。不应该这样啊&#xff0c;这可怎么办&#xf…

【软考中级备考笔记】计算机体系结构

计算机体系结构 2月19日 – 天气&#xff1a;阴转小雪 1. 冯诺依曼计算机体系结构 冯诺依曼将计算机分为了五大部分&#xff0c;分别是&#xff1a; 控制器&#xff1a;主要负责协调指令到执行运算器&#xff1a;负责算数和逻辑运算存储器&#xff1a;负责存储在指令执行过程…

vue封装el-table表格组件

先上效果图&#xff1a; 本文包含了具名插槽、作用域插槽、jsx语法三种&#xff1a; Render.vue&#xff08;很重要&#xff0c;必须有&#xff09;: <script> export default {name: "FreeRender",functional: true,props: {scope:Object,render: Functio…

Gitlab操作流程

阶段1-构建账户信息 1.1 管理员分配账户 方式1-推荐 企业正常使用gitlab时&#xff0c;一般由项目经理(超级管理员)手动创建开发者账户信息&#xff0c;然后将账户发送给开发者&#xff0c;以便登录使用&#xff1b; 流程如下&#xff1a; 点击创建用户按钮&#xff1b; 创…

自动驾驶中之定位总结

1 前言2 典型的单个定位方式2.1 基于通信的定位方法2.1.1 GNSS 全球卫星导航系统2.1.1.1 gnss的优点与缺点2.1.1.2 gnss定位技术2.1.1.2.1 RTK定位技术2.1.1.2.2 PPP定位技术 2.1.1.2 gnss定位技术总结 2.1.2 车联网定位 2.1 基于航位推算的定位方法2.1.1 惯性测试单元定位IMU2…

docker安装一系列镜像

启动docker systemctl start docker docker 启动已经停止的容器 docker start idOrName PS&#xff1a;idOrName为容器的id或者名称 1、安装mysql镜像 拉取mysql5.7的镜像 docker pull mysql:5.7 查看镜像 docker images 启动mysql #启动mysql docker run --name mysql…

PostgreSQL技术内幕(十三)探究MPP数据库分布式查询分发Dispatcher

Dispatcher&#xff08;分布式查询分发器&#xff09;是MPP数据库的核心组件&#xff0c;所有的查询任务都要经过其进行分发&#xff0c;起着沟通用户到协调者&#xff08;Coordinator&#xff0c;即QD&#xff09;和执行调度的关键作用。 在这次的直播中&#xff0c;我们为大…

Opencv中的RNG-随机绘图

在OpenCV中&#xff0c;RNG是一个随机数生成器类&#xff0c;用于生成各种类型的随机数&#xff0c;包括均匀分布或高斯分布的整数和浮点数。RNG类的实例化时可以接受一个无符号整数作为种子值&#xff0c;这个种子值决定了随机数生成序列的起点&#xff0c;相同的种子值将产生…

分布式id实战

目录 常用方式 特征 潜在问题 信息安全 高性能 UUID 雪花算法 数据库生成 美团Leaf方案 Leaf-segment 数据库方案 Leaf-snowflake 方案 常用方式 uuid雪花算法数据库主键 特征 全局唯一趋势递增信息安全 潜在问题 信息安全 如果id连续递增, 容易被爬虫, 批量下…

【动态规划】【字符串】2167移除所有载有违禁货物车厢所需的最少时间

作者推荐 【深度优先搜索】【树】【有向图】【推荐】685. 冗余连接 II 本文涉及知识点 动态规划汇总 LeetCode2167移除所有载有违禁货物车厢所需的最少时间 给你一个下标从 0 开始的二进制字符串 s &#xff0c;表示一个列车车厢序列。s[i] ‘0’ 表示第 i 节车厢 不 含违…

自动化上位机开发C#100例:如何用面向对象的方式封装雷赛运动控制卡EtherCAT总线卡(C#代码)

自动化上位机开发C#100例:雷赛运动控制卡EtherCAT总线卡C#封装类 文章目录 LTDMC.dll下载LTDMC.cs LTDMC.dll C#调用封装下载ICard.cs 运动控制卡接口Card.cs 运动控制卡抽象类CardLTDMC.cs 雷赛运动控制卡EtherCAT总线卡实现类CardList.cs 总线卡列表封装 LTDMC.dll下载 最新…