TikTok X-Gnarly算法

其它文档 · 昨天 · 14 人浏览

说明

朋友的一个项目,找到了相关的算法, 然后高了一个HTML便于算法测试。有需要请自取。
如果需要A_bogus参数调试的,可以看下面的网址:
https://lxjc.com/abogus/

源码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>X-Gnarly 浏览器端生成器</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <style>
        body { font-family: system-ui, -apple-system, sans-serif; padding: 20px; max-width: 800px; margin: 0 auto; }
        label { font-weight: bold; display: block; margin-top: 15px; }
        textarea, input { width: 100%; padding: 8px; margin-top: 5px; box-sizing: border-box; }
        textarea { height: 100px; font-family: monospace; }
        button { margin-top: 20px; padding: 10px 20px; background: #000; color: #fff; border: none; cursor: pointer; border-radius: 4px; font-size: 16px; }
        button:hover { background: #333; }
        #result { background: #f4f4f4; padding: 15px; border-radius: 4px; margin-top: 20px; word-break: break-all; font-family: monospace; border: 1px solid #ddd; }
    </style>
</head>
<body>

    <h2>X-Gnarly 生成器 (TikTok Web 逆向测试)</h2>
    
    <label>Query String:</label>
    <textarea id="queryString">WebIdLastTime=1746886547&aid=1988&app_language=en-GB&app_name=tiktok_web&browser_language=en-GB&browser_name=Mozilla&browser_online=true&browser_platform=MacIntel&channel=tiktok_web&cookie_enabled=true&data_collection_enabled=false&device_platform=web_pc&focus_state=true&from_page=&history_len=2&is_fullscreen=false&is_page_visible=true&odinId=7502820379158911111&permissionList=001004%2C001005&priority_region=&referer=&screen_height=956&screen_width=1470&user_is_login=false&webcast_language=en-GB&msToken=</textarea>
    
    <label>User Agent:</label>
    <textarea id="userAgent">Mozilla/5.0 (Macintosh; Intel Mac OS X 1_1_1) AppleWebKit/111.11 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/111.11</textarea>

    <button id="generateBtn">生成 X-Gnarly</button>

    <div id="result">点击上方按钮生成结果...</div>

    <script>
        const crypto = {
            createHash: function(algo) {
                let data = "";
                return {
                    update: function(str) {
                        data += str;
                        return this;
                    },
                    digest: function(format) {
                        return CryptoJS.MD5(data).toString();
                    }
                };
            }
        };
        let aa = [4294967295, 138, 1498001188, 211147047, 253, /\s*\(\)\s*{\s*\[\s*native\s+code\s*]\s*}\s*$/, 203, 288, 9, 1196819126, 3212677781, 135, 263, 193, 58, 18, 244, 2931180889, 240, 173, 268, 2157053261, 261, 175, 14, 5, 171, 270, 156, 258, 13, 15, 3732962506, 185, 169, 2, 6, 132, 162, 200, 3, 160, 217618912, 62, 2517678443, 44, 164, 4, 96, 183, 2903579748, 3863347763, 119, 181, 10, 190, 8, 2654435769, 259, 104, 230, 128, 2633865432, 225, 1, 257, 143, 179, 16, 600974999, 185100057, 32, 188, 53, 2718276124, 177, 196, 4294967296, 147, 117, 17, 49, 7, 28, 12, 266, 216, 11, 0, 45, 166, 247, 1451689750];
        let kt = [aa[44], aa[74], aa[10], aa[62], aa[42], aa[17], aa[2], aa[21], aa[3], aa[70], aa[50], aa[32], aa[0] & Date["now"](), Math["floor"](aa[77] * Math["random"]()), Math["floor"](aa[77] * Math["random"]()), Math["floor"](aa[77] * Math["random"]())];
        let St = aa[88];
        let Ot = [aa[9], aa[69], aa[51], aa[92]];

        function numToUint8Array(value) {
            let abLen = value < 255 * 255 ? 2 : 4;
            let ab = new ArrayBuffer(abLen);
            let dv = new DataView(ab);
            if (value < 255 * 255) {
                dv.setUint16(0, value, false);
            } else {
                dv.setUint32(0, value, false);
            }
            return new Uint8Array(ab);
        }

        function Ab12(e) {
            return function (e) {
                if (Array["isArray"](e)) return Ab39(e);
            }(e) || function (e) {
                var sa;
                sa = [null];
                if ("undefined" != typeof Symbol && sa[0] != e[Symbol["iterator"]] || sa[0] != e["@@iterator"]) return Array["from"](e);
            }(e) || Ab3(e) || function () {
                throw new TypeError("Invalid attempt to spread non-iterable instance.");
            }();
        }

        function Ab18(e, t, r, n, o) {
            var ob = [16, 12, 8, 7];
            e[t] += e[r], e[o] = Ab41(e[o] ^ e[t], ob[0]), e[n] += e[o], e[r] = Ab41(e[r] ^ e[n], ob[1]), e[t] += e[r], e[o] = Ab41(e[o] ^ e[t], ob[2]), e[n] += e[o], e[r] = Ab41(e[r] ^ e[n], ob[3]);
        }

        function Ab21(e, t, r) {
            var qb = [0];
            for (var n = Math["floor"](r["length"] / 4), o = r["length"] % 4, i = Math["floor"]((r["length"] + 3) / 4), u = Array(i), a = 0; a < n; ++a) {
                var s = 4 * a;
                u[a] = r[s] | r[s + 1] << 8 | r[s + 2] << 16 | r[s + 3] << 24;
            }
            if (o > qb[0]) {
                u[a] = 0;
                for (var c = 0; c < o; ++c) u[a] |= r[4 * a + c] << 8 * c;
            }
            for (function (e, t, r) {
                for (var n = e["slice"](), o = 0; o + 16 < r["length"]; o += 16) {
                    var i = Ab33(n, t);
                    Ab23(n);
                    for (var u = 0; u < 16; ++u) r[o + u] ^= i[u];
                }
                for (var a = r["length"] - o, s = Ab33(n, t), c = 0; c < a; ++c) r[o + c] ^= s[c];
            }(e, t, u), a = 0; a < n; ++a) {
                var f = 4 * a;
                r[f] = 255 & u[a], r[f + 1] = u[a] >>> 8 & 255, r[f + 2] = u[a] >>> 16 & 255, r[f + 3] = u[a] >>> 24 & 255;
            }
            if (o > qb[0]) for (var d = 0; d < o; ++d) r[4 * a + d] = u[a] >>> 8 * d & 255;
        }

        function Ab22(e, t, r) {
            return function (e, t, r) {
                for (var n = [], o = 0; o < r["length"]; ++o) n["push"](r["charCodeAt"](o));
                return Ab21(e, t, n), String.fromCharCode["apply"](String, n);
            }([].concat(Ot, Array.from(e)), t, r);
        }

        function Ab23(e) {
            var pb = [12, 4294967295, 1];
            e[pb[0]] = e[pb[0]] + pb[2] & pb[1];
        }

        function Ab33(e, t) {
            var r = e["slice"]();
            !function (e, t) {
                for (var r = 0; r < t && (Ab18(e, 0, 4, 8, 12), Ab18(e, 1, 5, 9, 13), Ab18(e, 2, 6, 10, 14), Ab18(e, 3, 7, 11, 15), !(++r >= t)); ++r) 
                    Ab18(e, 0, 5, 10, 15), Ab18(e, 1, 6, 11, 12), Ab18(e, 2, 7, 12, 13), Ab18(e, 3, 4, 13, 14);
            }(r, t);
            for (var n = 0; n < 16; ++n) r[n] += e[n];
            return r;
        }

        function Ab39(e, t) {
            var ta = [null];
            (ta[0] == t || t > e["length"]) && (t = e["length"]);
            for (var r = 0, n = new Array(t); r < t; r++) n[r] = e[r];
            return n;
        }

        function Ab41(e, t) {
            var nb = [32];
            return e << t | e >>> nb[0] - t;
        }

        function rand () {
            var r, t, e, rb = [4294967296, 4294965248, 53, 0, 2, 11, 8, 7];
            e = Ab33(kt, rb[6]), t = e[St], r = (rb[1] & e[St + rb[6]]) >>> rb[5];
            rb[7] === St ? (Ab23(kt), St = rb[3]) : ++St;
            return (t + rb[0] * r) / Math["pow"](rb[4], rb[2]);
        }

        function encode({queryString, body, userAgent}) {
            let obj = {}
            obj[1] = 1
            obj[2] = 0
            obj[3] = crypto.createHash('md5').update(queryString).digest('hex')
            obj[4] = crypto.createHash('md5').update(body).digest('hex')
            obj[5] = crypto.createHash('md5').update(userAgent).digest('hex')

            const currentDate = new Date()
            const timestamp = currentDate.getTime()
            obj[6] = Math.floor(timestamp / 1000)
            obj[7] = 1245783967
            obj[8] = (timestamp * 1000) % 2147483648
            obj[9] = "5.1.0"
            obj[0] = obj[6] ^ obj[7] ^ obj[8] ^ obj[1] ^ obj[2]

            let arr = [Object.keys(obj).length]

            for (const [key, value] of Object.entries(obj)) {
                arr.push(parseInt(key))
                let valArr, lenArr;

                if (typeof value === "number") {
                    valArr = numToUint8Array(value)
                    lenArr = numToUint8Array(valArr.length)
                } else {
                    let te = new TextEncoder()
                    valArr = te.encode(value)
                    lenArr = numToUint8Array(valArr.length)
                }

                arr.push(...lenArr)
                arr.push(...valArr)
            }

            let str = ""
            for (let i = 0; i < arr.length; i++) {
                str += String.fromCharCode(arr[i])
            }

            let a = 1 << 6
            let b = 1 << 3
            let c = a ^ b
            let d = c ^ 3
            let e = d & 255
            let someRandomChar = String.fromCharCode(e)

            let key = []
            let keyStringArr = []
            let rounds = 0

            for (let i = 0; i < 12; i++) {
                let randomNumber = rand();
                let num = Math.floor(Math.pow(2, 32) * randomNumber)
                key.push(num)

                rounds = ((num & 15) + rounds) & 15

                let first = num & 255
                let second = (num >>> 8) & 255
                let third = (num >>> 16) & 255
                let fourth = (num >>> 24) & 255
                keyStringArr.push(first, second, third, fourth)
            }

            rounds += 5

            let x = Ab22(key, rounds, str)
            let someVal = 0

            for (let i = 0; i < keyStringArr.length; i++) {
                let el = keyStringArr[i]
                someVal += el
                someVal = someVal % (x.length + 1)
            }

            for (let i = 0; i < x.length; i++) {
                let charCode = x.charCodeAt(i)
                someVal += charCode
                someVal = someVal % (x.length + 1)
            }


            let keyString = String.fromCharCode.apply(null, keyStringArr)
            str = someRandomChar + x.substring(0, someVal) + keyString + x.substring(someVal)

            let charSet = "u09tbS3UvgDEe6r-ZVMXzLpsAohTn7mdINQlW412GqBjfYiyk8JORCF5/xKHwacP="
            let res = ""

            for (let i = 3; i <= str.length; i += 3) {
                let val = (str.charCodeAt(i - 3) & 255) << 16
                val = ((str.charCodeAt(i - 2) & 255) << 8) | val
                val = (str.charCodeAt(i - 1) & 255) | val
                
                pos = val & 16515072
                pos = pos >> 18
                res += charSet.charAt(pos)

                pos = val & 258048
                pos = pos >> 12
                res += charSet.charAt(pos)

                pos = val & 4032
                pos = pos >> 6
                res += charSet.charAt(pos)

                pos = val & 63
                pos = pos >> 0
                res += charSet.charAt(pos)
            }

            return res
        }

        document.getElementById('generateBtn').addEventListener('click', () => {
            const qs = document.getElementById('queryString').value;
            const ua = document.getElementById('userAgent').value;
            
            try {
                let xGnarly = encode({
                    queryString: qs,
                    body: "",
                    userAgent: ua
                });
                
                document.getElementById('result').innerText = xGnarly;
                console.log("Generated X-Gnarly:", xGnarly);
            } catch (error) {
                document.getElementById('result').innerText = "生成报错了: " + error.message;
                console.error(error);
            }
        });
    </script>
</body>
</html>