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

目录:

  • 每篇前言:
  • 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都有了:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springcloud:1.Eureka详细讲解

Eureka 是 Netflix 开源的一个服务注册和发现工具,被广泛应用于微服务架构中。作为微服务架构中的核心组件之一,Eureka 提供了服务注册、发现和失效剔除等功能,帮助构建弹性、高可用的分布式系统。在现代软件开发领域,使用 Eureka 可以有效地管理和监控服务实例,实现服务之…

Qt Creator在#include第三方库不带.h后缀的文件时,没有智能提示和自动补全

1、问题截图 OSG文件目录下有很多头文件&#xff08;均不带.h后缀&#xff09;&#xff0c;Qt Creator可以识别到OSG目录&#xff0c;但是OSG目录下的所有头文件识别不到 2、原因 找到原因是因为Qt Creator开启了ClanCodeModel插件导致的 3、解决方法 1、在Qt Creator中…

GenAI的“关键一跃”:推理与知识

当前的人工智能领域正通过生成式人工智能&#xff08;GenAI&#xff09;经历一场重大转变。这一转变不仅代表了技术上的飞跃&#xff0c;更标志着人工智能领域的范式转变&#xff0c;引发了有关GenAI的独特特性及其深远影响的关键问题讨论。 植根于计算革命的丰富历史&#xff…

OpenCV人脸检测案例实战

人脸检测是一种计算机视觉技术&#xff0c;旨在识别图像或视频中的人脸。这项技术的基本内容包括使用特定的算法和模型来定位和识别人脸&#xff0c;通常涉及在图像中寻找面部特征&#xff0c;如眼睛、鼻子、嘴巴等&#xff0c;以便准确地确定人脸的位置和边界。人脸检测技术的…

LeetCode JS专栏刷题笔记(一)

一、前言 LeetCode 在前不久出了一个 JavaScript 专栏&#xff0c;这个专栏一个目的是为了非前端工程师学习 JS&#xff0c;另一个是为了前端工程师提升 JS 能力。 因此在这个专栏中&#xff0c;基本不涉及什么具体算法问题&#xff0c;都是一些 JS 的入门语法与常见的 JS 面…

安卓游戏开发之图形渲染技术优劣分析

一、引言 随着移动设备的普及和性能的提升&#xff0c;安卓游戏开发已经成为一个热门领域。在安卓游戏开发中&#xff0c;图形渲染技术是关键的一环。本文将对安卓游戏开发中常用的图形渲染技术进行分析&#xff0c;比较它们的优劣&#xff0c;并探讨它们在不同应用场景下的适用…

从零开始:开发多商户商城APP的技术指南

当下&#xff0c;电子商务正在飞速发展&#xff0c;多商户商城APP的需求也与日俱增。本篇文章&#xff0c;小编将为大家深度详解如何开发多商户商城APP。 1.确定功能需求 在着手开发多商户商城APP之前&#xff0c;首先需要明确功能需求。这包括但不限于&#xff1a; -用户注…

如何在CentOS安装SQL Server数据库并实现无公网ip环境远程连接

文章目录 前言1. 安装sql server2. 局域网测试连接3. 安装cpolar内网穿透4. 将sqlserver映射到公网5. 公网远程连接6.固定连接公网地址7.使用固定公网地址连接 前言 简单几步实现在Linux centos环境下安装部署sql server数据库&#xff0c;并结合cpolar内网穿透工具&#xff0…

MongoDB文档插入

文章目录 MongoDB文档插入对比增删改查文档插入 MongoDB写安全机制非确认式写入 MongoDB文档查询参数说明查询操作符比较查询操作符逻辑查询操作符元素查询操作符数组查询操作符 模糊查询区别:$regex操作符中的option选项 MongoDB游标介绍游标函数手动迭代游标示例游标介绍 Mon…

揭秘智能商品计划管理系统:为何服装企业老板争相引入?

在如今日新月异的商业环境中&#xff0c;服装企业老板们纷纷将目光转向了一种名为“智能商品计划管理系统”的创新工具。这种系统不仅具有高度的自动化和智能化特性&#xff0c;还能显著提升企业的运营效率、减少库存积压&#xff0c;并帮助企业在激烈的市场竞争中占据优势地位…

xilinx除法器的使用

平台&#xff1a;Vivado2018.3. 芯片&#xff1a;xcku115-flva1517-2-i (active) 最近学习使用了xilinx除法器&#xff0c;在使用过程中出现了很多次除法器的结果和我预计的结果不一致&#xff0c;特此记录学习一下。 参考文件&#xff1a;pg151.下载地址 pg151-div-gen.pdf …

简单了解一下加密算法

1.1单向散列算法 单向散列函数算法也称 Hash(哈希)算法&#xff0c;是一种将任意长度的消息压缩到某一固定长度(消 息摘要)的函数(该过程不可逆)。Hash 函数可用于数字签名、消息的完整性检测、消息起源的认 证检测等。常见的散列算法有MD5 、SHA 、RIPE-MD 、HAVAL 、N-Hash等…

【Pygame手册03/20】用 pygame 模块draw绘制形状

目录 一、说明二、画图函数2.1 接口draw下的函数2.2 pygame.draw.rect()2.3 pygame.draw.polygon()2.4 pygame.draw.circle()2.5 pygame.draw.ellipse()2.6 pygame.draw.arc()2.7 pygame.draw.line ()2.8 pygame.draw.lines()2.9 pygame.draw.aaline()2.10 pygame.draw.aaline…

【EI会议征稿通知】2024年通信安全与信息处理国际学术会议(CSIP 2024)

2024年通信安全与信息处理国际学术会议&#xff08;CSIP 2024) 2024 International Conference on Communication Security and Information Processing 随着全球信息化的深入发展&#xff0c;通信安全与信息处理已成为当今社会关注的热点问题。为了加强国际间的学术交流与合…

Java之获取Nginx代理之后的客户端IP

Java之获取Nginx代理之后的客户端IP Nginx代理接口之后&#xff0c;后台获取的IP地址都是127.0.0.1&#xff0c;解决办法是需要配置Nginx搭配后台获取的方法&#xff0c;获得设备的真实地址。我们想要获取的就是nginx代理日志中的这个IP nginx配置 首先在nginx代理的对应lo…

opencv安装介绍以及基本图像处理详解

文章目录 一、什么是OpenCV &#xff1f;二. OpenCV 安装1. 下载地址2.安装命令&#xff1a;pip install opencv-python 三、图像基础1. 基本概念2. 坐标系3. 基本操作&#xff08;彩色图片&#xff09;&#xff08;1&#xff09;读取图片&#xff1a;cv2.imread( )&#xff08…

ThreadLocal(3):ThreadLocal的内部结构

下面介绍ThreadLocal的内部结构&#xff0c;探究它能够实现线程数据隔离的原理。 1 常见的误解 ​如果我们不去看源代码的话&#xff0c;可能会猜测ThreadLocal是这样子设计的&#xff1a;每个ThreadLocal都创建一个Map&#xff0c;然后用线程作为Map的key&#xff0c;要存储…

this的指向问题总结

this一般会出现在函数里面&#xff0c;但是一般情况下只有在函数被调用执行时&#xff0c;才能确定this指向哪个对象。一般情况下this是指调用函数的对象。 1.在全局作用域下或者普通函数中this的指向一般都是window对象 window.fn&#xff08;&#xff09;&#xff0c;普通函…

前端实现鼠标点击箭头旋转180度

效果&#xff1a; <div click"showChecklist" class"checkCLass cur pr-20px pl-20px pa flex ai-center"><span>{{ checkListStatus() }}</span><p class"trangle"></p></div> 下面是三角形状的样式 .tr…

qt对stl模型显示的封装

我一直都想把vtk显示这一块做成一个封装的静态lib&#xff0c;然后别的类只需要我暴露出的头文件和lib文件就可以了&#xff0c;这次我实现的是对一个放stl文件的文件夹下的stl文件做显示&#xff0c;用的是vs2017qt,实现的主要效果如下&#xff1a; 因为qt自身带的标题栏显示…