逆向05 点点网站

image

#访问页面
#'aHR0cHM6Ly9hcHAuZGlhbmRpYW4uY29tLw==' # https://app.diandian.com/
#API
#'aHR0cHM6Ly9hcGkuZGthbmRpYW4uY29tL3BjL2FwcC92MS91c2VyL2Zhdm9yaXRlL2FwcA=='

# 'https://api.dkandian.com/pc/app/v1/user/favorite/app'

第一张
image
第二张:点击上图中的anonymous跳转到下面的图,途中的send函数其实就是我们想要的,但是但是但是,会有很多的请求都走这send,我们该如何找到目标请求呢,方法有很多,可以一步一步的倒,直到目标请求,还可以XHR,我们下面使用的是XHR
image
第三张:XHR
image
image
通过异步前面的步骤分析,前面的k都是已经加密的了,异步之后的步骤,我们猜测是一个拦截器,接下来我们分析一下是不是拦截器吧
image

分析拦截器
image

image

image

onRequest: function(t) {
	this.interceptors.request.use((function(e) {
		return t(e) || e // 这里有个t函数,我们进去看看
			}
			))
		},

image
image

进去这个M函数
image

OK 接下来该扣js代码了
image

.........
// Object(y.a)其实就是一个封装 Object没有啥意义,直接看y.a就可以了
// 获取 r, path, {参数}, get等参数【打断点,悬浮就有了】
, o = Object(y.a)(r, path, {
 s: n.s,
 k: n.k,
 l: n.l,
d: n.d,
sort: n.sort,
num: n.num
}, "get");

参数---放在自己写的函数中 这个与扣的代码就不会存在变量的冲突

function test(){
    r = {
        "app_id": "y21ulux1r7mwra1",
        "country_id": 75,
        "market_id": 1,
        "device_id": 1,
        "start_time": 1721577600,
        "end_time": 1721664000,
        "k": "SUtER2wAXV5aWkhKREdsAF5fWVxISkJFDWQcLD9eDzstJmtQPwIFJyo/EQMfd10POjoAMyYbFHcsPjwPND5MFRpLGx0nAQwrJQcXdyIQAkM9KzgWOgBYOSIGFzs4CQdTLiEOBTATOEITdRseJgRBSjIJGx4uAzRVNRIWQgtbBx86LUAdJQoTdyAoLzY3ACMUHXU9ASoUKhUxIy17JAMaHj8uIDcGYykiIz4tHDoJPXgjPzweNzhFRg5gIR4lGyIgNwk5QDg7PAU1HRY8PXMuCzUuEy8xB29zJCg0KjASTT4NZyI9OwIbOyI2Z2g+LB0hKUodARlkXTk/LR8ZIBwQZgwRWQkvPzwqHUlQITUWECs9FwdXKjgaCi8SMAUPYFVUFF5JDxkFJgAaXgAbChtEWHgXQVhdWk1CQUJpAFhBS0pRHhFYeBdBRhtdVw8GFSweDggbAwoTARVxUBgZ"
    }

    path = '/v1/user/favorite/app'


    data = {
        s: '36df3fb834976f662a885efe622d10f3',
        k: '546eea8d15acbd96',
        l: '6f5eb1db7cc41c15',
        d: 0,
        sort: 'dd',
        num: 10
    }
    console.log(h(r, path, data, 'get')) // 下面的图的函数调用
}


test()

** 进去y.a**
image

 console.log(h(r, path, data, 'get')) // 上面代码中对函数调用----哪里报错解决哪里

错误1:
image

定位分析1----其中的t是参数
image
定位分析1----其中的c()(t) 还是上一步的t参数,,也就是这个函数没有啥作用就是t参数而异
image

那么我们就直接可以将代码

var n = t; // 平替之后的
// var n = c()(t); // 源代码

错误2:
image
根据 if (!_()(n))我们知道肯定是一个布尔值啊
去验证
image
那么我们就直接可以将代码

// if (!_()(n)) {
if (true) {

错误3:
image

这里有个知识点【短路运算】
如果逻辑与运算符左边的值布尔转换后为false,那么返回左边的值

源码分析
m()(n[d])是个false所有后面的都不走
image
"post" === e是个false所有后面的都不走

那么我们就直接可以将代码

//直接去掉
 for (var d in n)
       //m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
       //"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
        r.push(n[d]);

错误4:
image

悬浮进去看看

            function _(e, n, o) {
                var d = "";
                n = t.from(n, "utf8"),
                o = t.from(o, "utf8");
                var c = Object(r.createDecipheriv)("aes-128-cbc", n, o);
                return d += c.update(e, "hex", "utf8"),
                d += c.final("utf8")
            }

有没有很熟悉---AES算法

那么我们就直接可以将代码copy改写

// n = 和 o= 就是AES的key和iv 所以我们不要
crypo = require("crypto")

function aes_crypt(e, n, o) {
    var d = "";
    var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
    return d += c.update(e, "hex", "utf8"),
    d += c.final("utf8")
}


Object(aes_crypt)(s, d, f), k);
// Object(l.b)(s, d, f), k);

错误5:
image
首县分析这个报错,应该就是base64转换啊
验证:
image
观察下面的值是不是一样呢
image
那么我们就直接可以将代码

return btoa(y)
//return t.from(y).toString("base64")

js代码总--不是最终版本

crypo = require("crypto")

function aes_crypt(e, n, o) {
    var d = "";
    var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
    return d += c.update(e, "hex", "utf8"),
    d += c.final("utf8")
}



function h(e, path, n, r) {
    var s = n.s
      , d = n.k
      , f = n.l
      , v = n.d
      , h = n.sort
      , k = n.num
      , y = function(content, t, e) {
        for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
            a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
        return a.join("")
    }(function(s, t, path, e) {
        return [s, t, e, path].join("(&&)")
    }(function(t, e) {
        var n = t;
        // var n = c()(t);
        // if (!_()(n)) {
        if (true) {
            var r = [];
            for (var d in n)
                //m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
                //"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
                r.push(n[d]);
            return r.sort(),
            r.join("")
        }
    }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(aes_crypt)(s, d, f), k);
// }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(l.b)(s, d, f), k);
    return btoa(y)
}

// 测试代码
function test(){
    r = {
        "app_id": "y21ulux1r7mwra1",
        "country_id": 75,
        "market_id": 1,
        "device_id": 1,
        "start_time": 1721577600,
        "end_time": 1721664000,
    }

    path = '/v1/user/favorite/app'


    data = {
        s: '36df3fb834976f662a885efe622d10f3',
        k: '546eea8d15acbd96',
        l: '6f5eb1db7cc41c15',
        d: 0,
        sort: 'dd',
        num: 10
    }
    console.log(h(r, path, data, 'get'))
}

test()
// SUtER2wAXV5aWkhKREdsAF5fWVxISkJFJwNZHAEZAEsHRzNGGghcRF5cXEFuB11RWVlLQ0ZYeBdBDQlEXlxcXygARxweCQpVExEoXhoAGQlXGwUA

接下来使用python代码来实现

import requests
import execjs
import time
cookies = {
    'deviceid': 'b9647b5f290aa89e8fbad94669e9e6f',
    '_ga': 'GA1.1.1071716589.1721633816',
    'Qs_lvt_404253': '1721633812%2C1721701819',
    '_ga_GVCWL6PNZ2': 'GS1.1.1721720339.3.1.1721722286.0.0.0',
    'Qs_pv_404253': '1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
}

headers = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    # 'Cookie': 'deviceid=b9647b5f290aa89e8fbad94669e9e6f; _ga=GA1.1.1071716589.1721633816; Qs_lvt_404253=1721633812%2C1721701819; _ga_GVCWL6PNZ2=GS1.1.1721720339.3.1.1721722286.0.0.0; Qs_pv_404253=1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
    'Origin': 'https://app.diandian.com',
    'Referer': 'https://app.diandian.com/',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
    'language': 'zh',
    'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"macOS"',
}

params = {
    'app_id': 'y21ulux1r7mwra1',
    'country_id': '75',
    'market_id': '1',
    'device_id': '1',
    'start_time': int(time.time()),  #'1721577600', 
    'end_time': int(time.time())+40000, #'1721664000',
    #'k': 'SUtER2wAXV5aWkhKREdsAF5fWVxISkJFJwNZHAEZAEsHRzNGGghcRF5cXEFuB11RWVlMQkxYeBdBDQlEXlxcXygARxweCQpVExEoXhoAGQlXGwUA',
}

k = execjs.compile(open("05diandian.js").read()).call("test", params)

params['k'] = k
response = requests.get('https://api.diandian.com/pc/app/v1/user/favorite/app', params=params, cookies=cookies, headers=headers)

print(response.text)

crypo = require("crypto")

function aes_crypt(e, n, o) {
    var d = "";
    var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
    return d += c.update(e, "hex", "utf8"),
    d += c.final("utf8")
}



function h(e, path, n, r) {
    var s = n.s
      , d = n.k
      , f = n.l
      , v = n.d
      , h = n.sort
      , k = n.num
      , y = function(content, t, e) {
        for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
            a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
        return a.join("")
    }(function(s, t, path, e) {
        return [s, t, e, path].join("(&&)")
    }(function(t, e) {
        var n = t;
        // var n = c()(t);
        // if (!_()(n)) {
        if (true) {
            var r = [];
            for (var d in n)
                //m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
                //"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
                r.push(n[d]);
            return r.sort(),
            r.join("")
        }
    }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(aes_crypt)(s, d, f), k);
// }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(l.b)(s, d, f), k);
    return btoa(y)
}


function test(r){
    // r = {
    //     "app_id": "y21ulux1r7mwra1",
    //     "country_id": 75,
    //     "market_id": 1,
    //     "device_id": 1,
    //     "start_time": 1721577600,
    //     "end_time": 1721664000,
    //     // "k": "SUtER2wAXV5aWkhKREdsAF5fWVxISkJFDWQcLD9eDzstJmtQPwIFJyo/EQMfd10POjoAMyYbFHcsPjwPND5MFRpLGx0nAQwrJQcXdyIQAkM9KzgWOgBYOSIGFzs4CQdTLiEOBTATOEITdRseJgRBSjIJGx4uAzRVNRIWQgtbBx86LUAdJQoTdyAoLzY3ACMUHXU9ASoUKhUxIy17JAMaHj8uIDcGYykiIz4tHDoJPXgjPzweNzhFRg5gIR4lGyIgNwk5QDg7PAU1HRY8PXMuCzUuEy8xB29zJCg0KjASTT4NZyI9OwIbOyI2Z2g+LB0hKUodARlkXTk/LR8ZIBwQZgwRWQkvPzwqHUlQITUWECs9FwdXKjgaCi8SMAUPYFVUFF5JDxkFJgAaXgAbChtEWHgXQVhdWk1CQUJpAFhBS0pRHhFYeBdBRhtdVw8GFSweDggbAwoTARVxUBgZ"
    // }
    path = '/v1/user/favorite/app'
    data = {
        s: '36df3fb834976f662a885efe622d10f3',
        k: '546eea8d15acbd96',
        l: '6f5eb1db7cc41c15',
        d: 0,
        sort: 'dd',
        num: 10
    }
    return h(r, path, data, 'get')
}

接下来-在js中有一些参数是写死的,我们需要把他写活,该怎么办呢

// 下面数据是只要刷新网页就会变化的
    data = {
        s: '7414336790206813ee0bcdc951079953',
        k: '546eea8d15acbd96',
        l: '6f5eb1db7cc41c15',
        d: 0,
        sort: 'dd',
        num: 10
    }

**思路一:简单版 **
我们拿到对应的数据在全局搜索--如果有,证明是有一个请求的返回值,我们就可以直接去拿了
image

# 获取数据
res = requests.get('https://app.diandian.com/', headers=headers, cookies=cookies)

repg = r"u:\{.*?\}"
match = re.search(repg, res.text).group()[2:-5] + "}"
match = match.replace('s:','"s":').replace('k:','"k":').replace('l:','"l":')
d = json.loads(match)

.......

# 传递数据
k = execjs.compile(open("05diandian.js").read()).call("test", params, d)
// 观察n 和赋值
function test(r, n){
    path = '/v1/user/favorite/app'
    data = {
        s: n.s,
        k: n.k,
        l: n.l,
        d: 0,
        sort: 'dd',
        num: 10
    }
    return h(r, path, data, 'get')
}

最终代码
python

import requests
import execjs
import time
import re
import json
cookies = {
    'deviceid': 'b9647b5f290aa89e8fbad94669e9e6f',
    '_ga': 'GA1.1.1071716589.1721633816',
    'Qs_lvt_404253': '1721633812%2C1721701819',
    '_ga_GVCWL6PNZ2': 'GS1.1.1721720339.3.1.1721722286.0.0.0',
    'Qs_pv_404253': '1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
}

headers = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    # 'Cookie': 'deviceid=b9647b5f290aa89e8fbad94669e9e6f; _ga=GA1.1.1071716589.1721633816; Qs_lvt_404253=1721633812%2C1721701819; _ga_GVCWL6PNZ2=GS1.1.1721720339.3.1.1721722286.0.0.0; Qs_pv_404253=1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
    'Origin': 'https://app.diandian.com',
    'Referer': 'https://app.diandian.com/',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
    'language': 'zh',
    'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"macOS"',
}


res = requests.get('https://app.diandian.com/', headers=headers, cookies=cookies)

repg = r"u:\{.*?\}"
match = re.search(repg, res.text).group()[2:-5] + "}"
match = match.replace('s:','"s":').replace('k:','"k":').replace('l:','"l":')
d = json.loads(match)



params = {
    'app_id': 'y21ulux1r7mwra1',
    'country_id': '75',
    'market_id': '1',
    'device_id': '1',
    'start_time': int(time.time()),  #'1721577600', 
    'end_time': int(time.time())+40000, #'1721664000',
    #'k': 'SUtER2wAXV5aWkhKREdsAF5fWVxISkJFJwNZHAEZAEsHRzNGGghcRF5cXEFuB11RWVlMQkxYeBdBDQlEXlxcXygARxweCQpVExEoXhoAGQlXGwUA',
}

k = execjs.compile(open("05diandian.js").read()).call("test", params, d)


params['k'] = k
response = requests.get('https://api.diandian.com/pc/app/v1/user/favorite/app', params=params, cookies=cookies, headers=headers)

print(response.text)

js

crypo = require("crypto")

function aes_crypt(e, n, o) {
    var d = "";
    var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
    return d += c.update(e, "hex", "utf8"),
    d += c.final("utf8")
}



function h(e, path, n, r) {
    var s = n.s
      , d = n.k
      , f = n.l
      , v = n.d
      , h = n.sort
      , k = n.num
      , y = function(content, t, e) {
        for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
            a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
        return a.join("")
    }(function(s, t, path, e) {
        return [s, t, e, path].join("(&&)")
    }(function(t, e) {
        var n = t;
        // var n = c()(t);
        // if (!_()(n)) {
        if (true) {
            var r = [];
            for (var d in n)
                //m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
                //"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
                r.push(n[d]);
            return r.sort(),
            r.join("")
        }
    }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(aes_crypt)(s, d, f), k);
// }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(l.b)(s, d, f), k);
    return btoa(y)
}


function test(r, n){
    path = '/v1/user/favorite/app'
    data = {
        s: n.s,
        k: n.k,
        l: n.l,
        d: 0,
        sort: 'dd',
        num: 10
    }
    return h(r, path, data, 'get')
}

思路二:是在思路一中搜索不到的话

按照图的顺序
image

image
在这里你可能会说 我咋知道这个 n 就是我要找的呢?
image
然后往回倒-哪里调用的M
image

image

image
接下来就看e.store 是哪里来的
image

倒完之后
image

image

最终找到了

window.__NUXT__ && window.__NUXT__.state && r.replaceState(window.__NUXT__.state),

image

搜索window.__NUXT__.在全局那个地方
image
image

看完之后一张图 又回到了思路一中,也就是说:我们思路一走不通的时候 就来直接走思路二

posted @ 2024-07-23 16:22  流年中渲染了微笑  阅读(1)  评论(0)    收藏  举报