目标值

tl请求中的headers

tl请求的payload

一共五个值需要分析

X-Kpsdk-Ct: 07iChv9SxCLnT7OemaEKTzDEKaFind2jkzzK27UsTFDAsf3txKvUwB4CSN90iFA4VGY8XBtzl5qx8wBIEHz7GfdpYCNSARh6p9OcYOFGu6RcYBHEpoCAzFda8bHUf3wcJAGIAqxkrZBTQsdrntc6GD8xRTXAytJ
X-Kpsdk-Dt: 111bfw75y34x02cnx2ez4l4x6b1x5d
X-Kpsdk-Im: CiQ1ZTA2Y2QzNy1iZGFlLTQ2NTEtYTBhMy0zNDVkZjY1YjJjNzg
X-Kpsdk-V: j-0.0.0

payload: Bxß>6C@{‡“Â1#Հ‚½gè

请求流程

fp?x-kpsdk-v=j-0.0.0

method:GET
url: https://api.nike.com/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/fp?x-kpsdk-v=j-0.0.0
response: 429

响应中返回 ips.js 链接,ips.js链接中有x-kpsdk-vx-kpsdk-im

ips.js

method:GET
url: https://api.nike.com/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08Qg5binjfx6YVwZmPu8936KnheNmp9z3H42P9MGtKP3OkjFUaKy78PjU523S3FE3JKfqlBWrHhyF96TH7ghQxH4ZKvxR5OxXU5O1MZCuHmN8SoioQRepPfQvk23Y9MEN6Z4yVqNaC19hcJN2&x-kpsdk-v=j-0.0.0&x-kpsdk-im=CiQ1ZGNkZTZhZC0xMjg5LTQ3MDUtYTY2My05NGM5Yjk2NTU3NjA
response: 200

响应用于生成payloadX-Kpsdk-CtX-Kpsdk-Dt,是我们需要逆向的主要文件

2d206a39-8ed7-437e-a3be-862e0f06eea3/tl

"""核心请求"""

cookies = {           # cookies有akamai
	'_abck': 'xxxxxx',
	'bm_sz': 'xxxxxx'
}

headers = {
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Content-Type': 'application/octet-stream',
    'Origin': 'https://api.nike.com',
    'Referer': 'https://api.nike.com/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/fp?x-kpsdk-v=j-0.0.0',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',,
    'x-kpsdk-ct': '07jjjkZdFYduVyLRdmpSSNbaFEb7gEPdLO9qEK2GhzxmATbL5FZylEoQaEjucSZg3cErKqvzsomznrTQIoz408MUKYH11Hae80eaAcAT4uwROJvsaei0Z7I8c5AlokjtSf7kf946Mw2h7xrrMphWJUEOHSJPRnI',
    'x-kpsdk-dt': '11q9w02paw59y35x41f5w73w6eky2n',
    'x-kpsdk-im': 'CiQ1ZGNkZTZhZC0xMjg5LTQ3MDUtYTY2My05NGM5Yjk2NTU3NjA',
    'x-kpsdk-v': 'j-0.0.0',
}

# 有删减
data = '\x00\x02BxÜ\x00f0\x10\x00\x14~\x98\x94½l\x19¤õ¹\x11\x10\x02\x87\x91\f\x10»z³%\x91Ç\x80Õ\x04Ã\x9fË$\t?>ósaé¢ä\x9a*\x8e\x14\x99\x8e\x95(û\x06¢Åg\t±¨BAÝÉ9Û.\x1e_\x9aöAñ|"'.encode()

response = requests.post(
    'https://api.nike.com/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/tl',
    cookies=cookies,
    headers=headers,
    data=data,
)

"""
核心响应:
cookies:
    ak_bmsc_nke-2.3-ssn: 07Pa4lqGCMrMKksS7KrEqa7Kzp8igR5QjVGQ8QjRjiVa3oLDwRqj45IqD0R6ZZHf59xb4agcILXyQrszQfhqsqrem3rnl1fLErRPvYvHtUaEkOMCoNfFcdTjotv1CnmgrIt6IJeGPCLdrgaEy52QFdTJBABhXkz
    ak_bmsc_nke-2.3: 07Pa4lqGCMrMKksS7KrEqa7Kzp8igR5QjVGQ8QjRjiVa3oLDwRqj45IqD0R6ZZHf59xb4agcILXyQrszQfhqsqrem3rnl1fLErRPvYvHtUaEkOMCoNfFcdTjotv1CnmgrIt6IJeGPCLdrgaEy52QFdTJBABhXkz

X-Kpsdk-Ct: 07Pa4lqGCMrMKksS7KrEqa7Kzp8igR5QjVGQ8QjRjiVa3oLDwRqj45IqD0R6ZZHf59xb4agcILXyQrszQfhqsqrem3rnl1fLErRPvYvHtUaEkOMCoNfFcdTjotv1CnmgrIt6IJeGPCLdrgaEy52QFdTJBABhXkz
    # 更新headers, 用于下次请求
X-Kpsdk-St: 1708323663441
    # 生成workTime
"""

追栈分析

tl是xhr,直接xhr断点

往前看几步,可以看到

需要注意的是body是一个Uint8Array类型数据

尝试追payload值

搜索new Uint8Array

发现搜不到

搜索new,发现一个可疑的地方

在这里把Function.bind.apply(_, u)输出日志断点

看了一下,确实是有Uint8Array,而且有很多。

这里可以继续打条件断电看值,这里我就不打了,因为我已经打过了,这里确实能看到值,但是不是生成值的地方

// 注意打条件断点的时机,因为并不是只有一个Uint8Array
typeof Function.bind.apply(_, u) == 'function' && Function.bind.apply(_, u).toString().indexOf('Uint8Array') == 9

然后看堆栈,不难看出这是一个循环

再仔细看,发现是一个jsvmp,emm...,追站部分结束。。

vmp代码分析

ips.js代码分析,把它的代码扒下来,放本地分析一下

发现是一个自执行里面包裹一个大循环,循环28次,初始化d,d='cdknvozapzrdlosqqbevzuzzleiq'(不固定)

初始化f数组流程

数组f生成逻辑

p = function () {
    var r = function () {
        var n = 4294967295 * Math.random() | 0
            , u = 4294967295 * Math.random() | 0;
        return function () {
            return n = n + 1640531527 | 0,
                u = (u >> 16) + (u << 16) + n | 0,
            (u & 2147483647) / 2147483648
        }
    }();

    // TODO 这里有代码,省略了一点

    // TODO 第三
    function a() {
        // 这里循环次数为随机数,循环u次,直到i.push(t())大于u退出循环
        for (var n = 1 + Math.floor(8 * r() * r()), u = Math.max(Math.floor(4 * r()), n), i = []; i.length < u;)
            i.push(t());
        // 上面得到一个u长度的i
        // 这里开始一个新的循环,循环
        // TODO 第五
        for (
            var c = [
                Math.floor((1 + 1e3 * r()) * Math.exp(7 * r())),
                e(),                // TODO 第六
                void 0,
                function () {       // TODO 把i数组,转成一个arguments对象
                    return arguments
                }.apply(void 0, i)
            ];
            i.length < n;           // 满足条件就循环,不满足不循环
        )
            i.push(t());
        return c.push.apply(c, i),  // 将c和i进行数组进行合并
            c
    }

    // TODO:入口    f = $(o, a)   第一
    for (
        var o = 20,
            f = $(o, a),     // 这里得到一个长度为20的数组
            E = function () {
                // 返回一个随机数
                return f[Math.floor(o * r())]
            },
            h = function () {
                return E()[1]
            },
            l = 0;
        l < o;               // TODO 循环20次
        l++                  // 索引
    ) {
        var I = (l + 1) % o;    // 索引
        // TODO 这里对初始化的f进行赋值,注意这个W
        // // TODO 第七
        f[l][1].W = M(f[I], E);      // TODO 这里返回得是一个函数,函数返回一个 f[l()]  意味着每一个的f[l][1].W中都有一个方法用于返回
        f[l][1].q = M(f[o - I - 1][1], h);
    }
    // TODO f初始化完成
    return {
        e: h,
        n: E
    }
}()

function $(r, t) {
    /*
    * r: 20固定
    * t: p函数中的函数a
    * */
    // TODO 第二
    for (var e = [], a = 0; a < r; a++)
        // a从0开始,小于20
        // t函数不接收参数,单纯的循环20次
        e.push(t(a));
    // 这里得到一个长度是20的数组
    return e
}

// TODO 第四
function t() {
    var n = r();            // 随机数
    // 随机走不同流程
    // 返回不同值
    if (n < .29)
        // 返回随机数
        return r() < .2 ? -Math.floor(Math.exp(2 * r())) : r() < .15 ? 0 : Math.floor(Math.exp(7 * r() * r()));
    if (!(n < .32)) {
        if (n < .62) {
            // 三个函数
            var u = [e, t, a];
            // 返回随机一个函数
            return u[Math.floor(u.length * r())]
        }
        if (n < .87) {
            // 随机往i中push(t())    自身
            for (var i = []; r() < .7;)
                // TODO 递归
                i.push(t());
            return i
        }
        if (n < .97)
            // 返回随机布尔值
            return r() < .25;
        var c = ["create", "offset", "start", "rand", "mv", "xyz", "count"];
        // 返回c中随机的一个元素
        return c[Math.floor(c.length * r())]
    }
}

// TODO 第六
function e() {
    // 这里也是循环i次,得到一个数组n
    for (var n = [], u = Math.floor(Math.exp(4 + 4 * r())), i = 1 + Math.floor(8 * r()), c = 0; c < i; c++)
        n[u++] = t();   // 这里也是走t()
    return {
        F: void 0,
        T: n,           // TODO 赋值n来这里
        P: y,           // 这个y是一个固定函数,先不管
        W: function () {
            return [0]
        },
        R: function () {
            return [0]
        },
        q: function () {
        }
    }
}

// TODO 第七
var M = function () {
    var r = 0;
    return function (t, e) {
        /*
        * t: 20个数组中的其中一个
        * e: 返回一个随机数
        * */
        // 循环三次,得到一个新的f数组
        for (var a = 17 * r++ | 0, o = 3, f = [], E = 0; E < o; E++)
            // TODO 第八
            /*
            e()  -->
            E = function() {
                return f[Math.floor(o * r())]  返回f中的随机一个元素
            }
            */
            // TODO 前提 E === a % o 返回t,否则重新从20个元素中选
            f.push(E === a % o ? t : e());
        return function () {
            var h = Math.floor(20 * Math.random());
            var l = function () {
                return a % (this + h)
            }.bind(o - h);         // o - h  --》 3减一个随机数
            return function () {   // 返回一个函数,函数里面返回f的值
                return f[l()]
            }
        }()
    }
}()

初始化对象C

对象C生成逻辑

function _() {
    var r = [
        1,
        {
            F: T,             // windows
            P: null,
            T: [],
            W: function () {
                return [0]
            },
            R: function () {
                return [0]
            },
            q: function () {
            }
        },
        void 0
    ];
    return {
        R: g(),       // 随机获取一个  f中的元素的W是个方法
        W: r,
        B: void 0
    }
}

g = function () {
    return f[Math.floor(o * r())]            // TODO 这里的f中的元素的W是个方法
}


// L = [8, 42, 28, 22, 2, 38]
// // S是大循环的很长的字符串,得到一个229660长的数组
// v = F(S, "9nWLIft=bBXmA3F6rZOYGTgoiw7N8s2MjSHduV4ezxDvc0pU^yQ$|+~qa5lJCkP1REhK><", 40)


function D(r) {
    for (var t = [T, [w, b], v], e = [Y, O, _, D, d, M, x, g, z]; ;) {
        var a = U[v[r.W[0]++]];
        try {
            var o = a(r, y, V, m, t, e);
            if (o === null)
                break
        } catch (f) {
            O(r, f)
        }
    }
}


var C = _();
{
    s.a = function (r, t) {
        return s.r.slice(r, r + t)
    }
    ;
    var A = v[N + d.indexOf(".")] ^ N
        , B = v.splice(A, v[A + C.W[0]] + 2);
    s.r = R(B, C.W[1].W(), L)       // 这里得到一个很长的字符串
}


// TODO 上述代码就是获得了一个C一个s

// 递归调用
D(C)

主体(vm)函数

function D(r) {
    for (var t = [T, [w, b], v], e = [Y, O, _, D, d, M, x, g, z]; ;) {
        var a = U[v[r.W[0]++]];
        try {
            var o = a(r, y, V, m, t, e); 
            if (o === null)              // 结束条件
                break
        } catch (f) {
            O(r, f)
        }
    }
}

通过进入里面的a方法,通过参数来控制,进入不同的方法(指令集)

直到生成结果

vmp插桩分析

通过动态调试加静态分析的方法,找到被多次调用的方法,然后打上日志断点,让日志输出。

我已经调试过就不走弯路了

通过调试,找到这里s.r.slice(r, r + t),可以将所有的字符串进行输出,而且都是string类型

需要注意的是

  • 不能直接打日志断点,因为浏览器会卡死,应该采用 "" + ybb 的方式,然后复制到本地进行分析

  • vmp用的都是切割字符串的方式,因此不能console.log(s.r.slice(r, r + t)),这样会改变原来的字符串,应该修改代码结构,如上图

将日志打印完成之后效果

还有另一个重要的指令集

在这里把t给输出到本地,方法同上,但是要注意打日志断点的时机(结合上面的全部日志进行判断,控制window.islog),否则也会导致浏览器卡死/报错,我这里只输出了 typeof t == 'string' 类型的,其实也可以把数组之类的也输出,但是需要判断一下长度之类的,否则会报错

输出之后发现几个要找的值都在里面

x-kpsdk-ct

上图看 x-kpsdk-ct 值,通过最长的那个字符串切分出来的= =

x-kpsdk-dt

上图看 x-kpsdk-dt 值,很明显是有在做加法运算,最终得到结果,这个逻辑就要调试代码才能知道了

payload

接下来找payload

找第一份日志文件中最后的几个Uint8Array

因为已经找过了,所以就直接这样断点

断住后,直接到这里断点

发现环境数组

环境数组

[
    "0KPEbwJyHcmY0JMH0C27b8WSXfTm70pvAwwpB5UrpFw7u0oszEolbdCzXuHhCouw8cTZJnzFzxQNN1vBQHQr5HoLSZ1ODUQwthqP48YCCPHPJh8vqgXukdG86N8NcX1EZvXm8zzL2OSTy9ZvQhRdd5VtTC1q53yNsWprQyjKNYoJUd8RFrB7LeQeqhLi1qn8niGxMnibWMVQRX2bipiKbDk84xYPfJsQuSLRDX6Ank4EhENQ53wYZeaM5aMXd3g6j7zhq16tlkMF0Su871UsnHT8x7vFg5t5hW1NuItEvk0o0O0qjhfItWTEfz8nwAeelQNBidez34ExKOHPs1ZWgMLcNg5z1MutheVXPbTU80XpULToGhOhfwvvQN7cLm0HCeMlAhTzLeHCh3P7XwPQHUBJo5Yo6Dfg1wyo1NgMehMGi3mcGpuuT8rmuSt4wvZjqTCSG6JrOUeC2co8hLh2xlwcT3hQ6DpHMSxN0dVfh4U55UqVLtIYQR4uGPTE5oQuohAMFdQTYzPpHHmIWPGqwvnPSAt18Mg3f3uQUIxLhU5wD62dTpCQIU0dHJ7I7kd1LbYMlYlzUUcP9z07X2Opaxn7RxmplqI3yk86QCLQ5rAMxK3x1RSk1vhkPVSHlw0dj97Ua9uRwtRCEqFFdhFgxSwR5LASrwI8f5TBRs3olIw7M1nKjAiD0GPEeqBi2QcnJiIrPslIJkXU1RxJJarSwUCZbqRJM6C5IKlBYXAYvIacLaAueXQQusxAf75LnipJHGqoUjSzuEwJ02ohXKZlP6CFHzVtBqR283piS5LduDxb6YvTnzZhIpohB9gjnj0q3k4ZjS9Bo2QHbJOQnmDPxU0DYLmScgKVuvOvBz3KqDdZamEoqnoWGMWPy4YeRvca4Qxk0XUxO5MukCO54peJiDkbROhaP8vcfsXRlCj8J2f7fKonz4H28CMXayFQ5Ernu7QC5jzLGGPYoPnuvMu04rhpjkyUjB6XWHBGJhYAvNPnpD5ymgQOnhD5qQCEUFf6qv10bROWAGADAVKmPqakCfqVEkOTXfw2WHON8UBdBGYNpteO2os9gl8m4RVkEmqVad2P3c07ts57lW2zzT712iwkGqKGvzSZmCW8GmuEvEbqyeNDQw4SQj6rY7yj7SwlPcVaOqlFZoMeauIdeuPRhNiBKYXMwiygw0oMvgKf1zpcoDPhQBxR7ftBFiBiMIE9MqckHM3h6Nqn8cBe0ngUaSVXrAWWgbvUBmuwnjywGeIQUQjOxGIzAURqm6Wcu70iF8yXOxuUI7NJUY9uNSKrZgW2lxSmKKd0pSOV1E1hj5c7xSx6R9eTBatD1ldvPeon1dWYDnXkKCgqhO4wviDdsIZBzsn82r4tKxhTIbyXqVkkHtVV7OGI4ydO6b90AziJxOtf7h9iGAFfOjuSXOCOPMiUiyYSIB95F1xqBi3hTx8N76w6huMRWyTvtfQGmLvjzhyXFGckL8Y8egWiOXLSuBE7O9Z3DmBLEqieLEGDXK6gF7P5eNcMVuLf2hiavXeTb4X6ppyt6RKhph8QRjWbKXUIyj8ljXbZDStKD7D7hlcLEJzFqRi9V8qrQbjYFk7Sw5GM6tgBtfYuuaXIlEom47U0aKnTWUJjnnM582K0yUsFskuRc1DkLilMQ1WjveNliQldfXzh7SrZ4SlYuijfqKJVy1CjYpY9DNCV9okaCDRmlxkGx0HImlK7Bifs2TbC00UB2jvdmcGdDl0QTqRLPH3zaz099KJODcMceXtQzWBnlOlEOseNz9lTRMcb1pFQVB7yBkazUs6l5P6Mj9T5KLwcAIHL0BxoZ6K4YhFNyNgNLgvoZWqoD56VhImXeeKZQufdcmUeAr",
    "TITAyxTYkM5MTN=k",
    [
        0
    ],
    [
        "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    ],
    [
        0
    ],
    [
        1130,
        2.2
    ],
    [
        "maybe"
    ],
    [
        3
    ],
    [
        0
    ],
    [
        "0"
    ],
    [
        "Win32"
    ],
    [
        "probably"
    ],
    [
        "中国标准时间"
    ],
    [
        "ANGLE (Intel, Intel(R) UHD Graphics 770 (0x00004680) Direct3D11 vs_5_0 ps_5_0, D3D11)"
    ],
    [
        false
    ],
    [
        ""
    ],
    [
        "Google Inc. (Intel)"
    ],
    [
        "onscrollend"
    ],
    [
        3
    ],
    [
        true
    ],
    [
        2
    ],
    [
        0
    ],
    [
        true
    ],
    [
        0
    ],
    [
        0
    ],
    [
        0
    ],
    [
        0
    ],
    [
        9
    ],
    [
        2
    ],
    [
        10
    ],
    [
        "webkitSpeechRecognition"
    ],
    [
        0
    ],
    [
        null
    ],
    [
        "probably"
    ],
    [
        ""
    ],
    [
        ""
    ],
    [
        4
    ],
    [
        {
            "value": [
                283174996032000,
                "cUWuCi%)K6q&3Or"
            ]
        }
    ],
    [
        "zh-CN"
    ],
    [
        null
    ],
    [
        "中国标准时间"
    ],
    [
        false
    ],
    [
        0
    ],
    [
        ""
    ],
    [
        0
    ],
    [
        true
    ],
    [
        1
    ],
    [
        22
    ],
    [
        "Number"
    ],
    [
        "webkitResolveLocalFileSystemURL"
    ],
    [
        ""
    ],
    [
        20
    ],
    [
        null
    ],
    [
        200704
    ],
    [
        null
    ],
    [
        "document"
    ],
    [
        "TypeError: Function.prototype.toString requires that 'this' be a Function\n    at Number.toString (<anonymous>)\n    at eval (eval at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:716:14), <anonymous>:3:16)\n    at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:909:24)\n    at D (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:1144:25)\n    at https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:852:13\n    at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:993:14)\n    at D (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:1144:25)\n    at https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:852:13\n    at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:909:24)\n    at D (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:1144:25)"
    ],
    [
        2
    ],
    [
        6
    ],
    [
        4
    ],
    [
        4
    ],
    [
        null
    ],
    [
        true
    ],
    [
        4
    ],
    [
        "KPSDK"
    ],
    [
        17
    ],
    [
        "0"
    ],
    [
        7
    ],
    [
        0
    ],
    [
        0
    ],
    [
        232
    ],
    [
        "zh-CN"
    ],
    [
        false
    ],
    [
        9
    ],
    [
        true
    ],
    {
        "t": [
            "85d.19999a",
            false,
            166.2,
            "3.0"
        ]
    },
    [
        "Array"
    ],
    [
        "Google Inc. (Intel)"
    ],
    [
        4
    ],
    [
        24
    ],
    [
        true
    ],
    [
        0
    ],
    [
        "ANGLE (Intel, Intel(R) UHD Graphics 770 (0x00004680) Direct3D11 vs_5_0 ps_5_0, D3D11)"
    ],
    [
        3
    ],
    [
        8
    ],
    [
        "webkitResolveLocalFileSystemURL"
    ],
    [
        225
    ],
    [
        "probably"
    ],
    [
        false
    ],
    [
        ""
    ],
    [
        0
    ],
    [
        "zh-CN"
    ],
    [
        "1,1024"
    ],
    [
        "maybe"
    ],
    [
        "2164560f-8a68-427a-a750-4d5e60b1e108"
    ],
    [
        "probably"
    ],
    [
        [
            "getRandomValues",
            "constructor",
            "subtle",
            "randomUUID",
            "seedRandomValue",
            "generate256BitKey",
            "regenerate256BitKey",
            "setRandomBits",
            "getLatestHMACVersion",
            "__defineGetter__",
            "__defineSetter__",
            "hasOwnProperty",
            "__lookupGetter__",
            "__lookupSetter__",
            "isPrototypeOf",
            "propertyIsEnumerable",
            "toString",
            "valueOf",
            "__proto__",
            "toLocaleString"
        ]
    ],
    [
        "3"
    ],
    [
        "5Az!0023"
    ],
    [
        0
    ],
    [
        "credentialless"
    ],
    [
        6
    ],
    [
        1920
    ],
    [
        24
    ],
    [
        null
    ],
    [
        null
    ],
    [
        "Class extends value #<MimeTypeArray> is not a constructor or null"
    ],
    [
        "self"
    ],
    [
        "webkitSpeechRecognitionEvent"
    ],
    [
        null
    ],
    [
        0
    ],
    [
        "webkitRequestFileSystem"
    ],
    [
        ""
    ],
    [
        "KPSDK"
    ],
    [
        "Object"
    ],
    [
        1080
    ],
    [
        ""
    ],
    [
        1
    ],
    [
        1920
    ],
    [
        "landscape-primary"
    ],
    [
        "probably"
    ],
    [
        "webkitResolveLocalFileSystemURL"
    ],
    [
        "webkitRequestFileSystem"
    ],
    [
        false
    ],
    [
        5
    ],
    [
        null
    ],
    [
        false
    ],
    [
        2
    ],
    [
        "probably"
    ],
    [
        ""
    ],
    [
        "Function"
    ],
    [
        "speechSynthesis"
    ],
    [
        1040
    ],
    [
        "WebGL 2.0 (OpenGL ES 3.0 Chromium)"
    ],
    [
        0
    ],
    [
        "1,1"
    ],
    [
        ""
    ],
    [
        [
            [
                "PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "Chrome PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "Chromium PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "Microsoft Edge PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "WebKit built-in PDF",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ]
        ]
    ],
    [
        0
    ],
    [
        "onscrollend"
    ],
    [
        "50"
    ],
    [
        "probably"
    ],
    [
        "1709202759153-1921326662-Win32-4047ghi"
    ],
    [
        "Illegal invocation"
    ],
    [
        ""
    ],
    [
        "Class extends value #<PluginArray> is not a constructor or null"
    ],
    [
        "webkitSpeechRecognitionEvent"
    ],
    [
        29
    ],
    [
        3
    ],
    [
        0
    ],
    [
        "zh-CN"
    ],
    [
        4
    ],
    [
        "Class extends value function createElement() { [native code] } is not a constructor or null"
    ],
    [
        "parseFloat"
    ],
    [
        true
    ],
    [
        "0"
    ],
    [
        -480
    ],
    [
        null
    ],
    [
        13
    ],
    [
        "vilame_setter"
    ],
    [
        7
    ],
    [
        -480
    ],
    [
        "maybe"
    ],
    [
        1
    ],
    [
        "中国标准时间"
    ],
    [
        "3"
    ],
    [
        false
    ],
    [
        "probably"
    ],
    [
        "1"
    ],
    [
        0
    ],
    [
        1920
    ],
    [
        0
    ],
    [
        24
    ],
    [
        false
    ],
    [
        5
    ],
    [
        3
    ],
    [
        1040
    ],
    [
        ""
    ],
    [
        true
    ],
    [
        10
    ],
    [
        3
    ],
    [
        "2"
    ],
    [
        8
    ],
    [
        "Class extends value function query() { [native code] } is not a constructor or null"
    ],
    [
        5
    ],
    [
        1080
    ],
    [
        4
    ],
    [
        "webkitRequestFileSystem"
    ],
    [
        "50"
    ],
    [
        2
    ],
    [
        ""
    ],
    [
        11
    ],
    [
        "0"
    ],
    [
        [
            4128,
            16638
        ]
    ],
    [
        "probably"
    ],
    [
        5
    ],
    [
        ""
    ],
    [
        ""
    ],
    [
        1
    ],
    [
        "probably"
    ],
    [
        1137
    ],
    [
        null
    ],
    [
        0
    ],
    [
        "2"
    ],
    [
        null
    ],
    [
        1920
    ],
    [
        24
    ],
    [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    ],
    [
        "1"
    ],
    [
        "maybe"
    ],
    [
        3
    ],
    [
        60
    ],
    [
        "Illegal invocation"
    ],
    [
        20
    ],
    [
        "Illegal invocation"
    ],
    [
        null
    ],
    [
        "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    ],
    [
        "Win32"
    ],
    [
        "0"
    ],
    [
        0
    ],
    [
        null
    ],
    [
        "4"
    ],
    [
        null
    ],
    [
        3
    ],
    [
        0
    ],
    [
        "Function.prototype.toString requires that 'this' be a Function"
    ],
    [
        ""
    ],
    [
        1024
    ],
    [
        true
    ],
    [
        3
    ],
    [
        null
    ],
    [
        "webkitSpeechRecognitionError"
    ],
    [
        1
    ],
    [
        1
    ],
    [
        "webkitResolveLocalFileSystemURL"
    ],
    [
        null
    ],
    [
        "name"
    ],
    [
        ""
    ],
    [
        24
    ],
    [
        24
    ],
    [
        ""
    ],
    [
        0
    ],
    [
        ""
    ],
    [
        false
    ],
    [
        "Function.prototype.toString requires that 'this' be a Function"
    ],
    [
        true
    ],
    [
        0
    ],
    [
        2
    ],
    [
        "window"
    ],
    [
        3
    ],
    [
        24
    ],
    [
        2
    ],
    [
        [
            [
                "PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "Chrome PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "Chromium PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "Microsoft Edge PDF Viewer",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ],
            [
                "WebKit built-in PDF",
                "Portable Document Format",
                [
                    [
                        "application/pdf",
                        "pdf"
                    ],
                    [
                        "text/pdf",
                        "pdf"
                    ]
                ]
            ]
        ]
    ],
    [
        "probably"
    ],
    [
        true
    ],
    [
        ""
    ],
    [
        2
    ],
    [
        "Illegal invocation"
    ],
    [
        "vilame_setter"
    ],
    [
        212992
    ],
    [
        2
    ],
    [
        0
    ],
    [
        "0"
    ],
    [
        "location"
    ],
    [
        "probably"
    ],
    [
        151
    ],
    [
        "TypeError: Function.prototype.toString requires that 'this' be a Function\n    at toString (<anonymous>)\n    at eval (eval at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:716:14), <anonymous>:3:29)\n    at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:909:24)\n    at D (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:1144:25)\n    at https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:852:13\n    at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:993:14)\n    at D (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:1144:25)\n    at https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:852:13\n    at U (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:909:24)\n    at D (https://api.nike.com/[path]/ips.js?ak_bmsc_nke-2.3=07HMQh4SbW8Nxg08[...]:1144:25)"
    ],
    [
        0
    ],
    [
        "4"
    ],
    [
        "webkitRequestFileSystem"
    ],
    [
        0
    ],
    [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    ],
    [
        "landscape-primary"
    ],
    [
        "probably"
    ],
    [
        0
    ],
    [
        "MzMzMjMyeERORFUxeEQzMTMxMzh4RE5EQTB4RDMyMzIzN3hETmpVdw==",
        142.3
    ]
]

环境数组通过TextEncoder后,变成Unit8Array

搜索a(n, _(u, r, l))

u: [123, 144, 165, 23, 49, 34, 196, 213, 61, 127, 128, 195, 188, 38, 231, 103]
r: [83, 204, 246, 249, 160, 248, 155, 27]
l: 是上面那个Uint8Array

接着进入VM

得到:

VM代码

(function anonymous() {
    return (function() {
        function e(e, t) {
            var r = 8 * t;
            return [n(e, r), n(e, r + 4)];
        }
        function t(e, _ref7, _ref8, i, c) {
            var t = _ref7[0]
              , n = _ref7[1];
            var r = _ref8[0]
              , o = _ref8[1];
            var a = function(e, t) {
                var n = t[0]
                  , r = t[1]
                  , o = 0;
                for (var _t4 = 0; _t4 < 32; _t4 += 1)
                    n = n + ((r << 4 ^ r >> 5) + r ^ o + e[3 & o]) | 0,
                    o = o + 2654435769 | 0,
                    r = r + ((n << 4 ^ n >> 5) + n ^ o + e[o >> 11 & 3]) | 0;
                return [n, r];
            }(e, [r ^ t, o ^ n]);
            return function(e, t, _ref9) {
                var n = _ref9[0]
                  , r = _ref9[1];
                var o = 8 * t;
                e[o] = n >> 24 & 255,
                e[o + 1] = n >> 16 & 255,
                e[o + 2] = n >> 8 & 255,
                e[o + 3] = 255 & n,
                e[o + 4] = r >> 24 & 255,
                e[o + 5] = r >> 16 & 255,
                e[o + 6] = r >> 8 & 255,
                e[o + 7] = 255 & r;
            }(i, c, a),
            a;
        }
        function n(e, t) {
            return e[t] << 24 | e[t + 1] << 16 | e[t + 2] << 8 | e[t + 3] << 0;
        }
        return [e, t, function(r, o, i) {
            var c = function(e) {
                if (16 !== e.length)
                    throw new Error("key must be 128-bit");
                return [n(e, 0), n(e, 4), n(e, 8), n(e, 12)];
            }(r)
              , a = function(e) {
                if (8 !== e.length)
                    throw new Error("iv must be 64-bit");
                return [n(e, 0), n(e, 4)];
            }(o)
              , s = []
              , u = Math.ceil(i.length / 8);
            var l = 0
              , d = 0;
            var f = [];
            var p = t(c, [0, 0], a, f, d++);
            for (s.push([0, i.length]); s.length < 5 && l < u; )
                s.push(e(i, l++));
            var y = 0;
            for (; s.length > 0; ) {
                y = (y + p[0]) % s.length,
                y < 0 && (y += s.length);
                p = t(c, p, s[y], f, d++),
                l < u ? s[y] = e(i, l++) : s.splice(y, 1);
            }
            return f;
        }
        , function(e) {
            var t = [];
            for (var _n2 = 0; _n2 < e.length; _n2 += 1) {
                var _r3 = e.charCodeAt(_n2);
                _r3 <= 255 ? t.push(_r3) : t.push(255);
            }
            return t;
        }
        ];
    }
    )
}
)

接着,一个长度为2的和一个长度为8数字进行拼接,得到长度为10的数组

最终,长度10的数字和VM出来的大数组拼接得到最终的payload,拼接上长度是8706

发起请求时,长度是8706

反编译

首先要搞清楚vm运行流程,写起ast就会事半功倍。

vm运行流程

vm主体函数

先看vm主体函数

可以看到,传入vm的参数只有一个r,v是字节码数组,r.W[0]是即将执行的字节码索引。原代码中U为指令集,这里将U改为了和腾讯vmp同样处理手段的function。

分析指令集发现大多数指令都是简单的二元运算:

堆栈

简单跟栈后可以看出,n可以看做vm的堆栈,e(n)为pop(这里的pop只取值,不从栈中删元素),a(n, xxx)为push(push也不是简单的放到栈前或栈后,而是stack[index] = xxx)。

其中入栈为:

G为下:

也就是说,以入栈操作码的下一位为索引,取字节码相应位置数字后右移5来储存入栈元素。

出栈:

R:

根据传入的索引,取用到的常量(数字、字符串、布尔值等)或者入栈的变量。

指令

17为变量初始化,78为函数初始化,52为对象属性绑定,65、42、93等对n.W[0]有操作的为跳转、if/for等,含有a(n, _(的如82、102、103等为函数执行。与r[index]相关为vm外部函数或者变量的调用。

ast编写

跟tdc区别不大,多了个内存池出来储存一些object的属性,由于对每个obj的命名都是唯一的,将每个a[b]转化为了obj_xxx = a[b],将obj_xxx放入堆栈而不是把a[b]直接放入堆栈,所以不需要做详细的作用域管理。

修改出栈类型:

重写指令:

修改vm函数,还原函数体、判断等:

这里借助了遗心大佬反编译美团vmp的思路,加了一个start和end索引(这里的start为r.W[0]就不用再加了),判断、循环、函数还原简单了不少。

虚假分支,kasada的偏简单,根据特征直接eval即可判断真假,剔除错误分支。

结束

emm.............................