设为首页收藏本站 今天是: 2023-10-04    "世界动物日"  热爱动物并和动物们建立了“兄弟姐妹”般的关系

复仇者黑客组织

 找回密码
 立即注册

QQ登录

只需一步,快速开始

    查看: 105|回复: 9

    【某点数据】榜单数据抓取

    [复制链接]

    该用户从未签到

    4

    主题

    4

    帖子

    28

    积分

    网站信息宣传员

    Rank: 7Rank: 7Rank: 7

    积分
    28
    发表于 2023-9-19 02:13:35 | 显示全部楼层 |阅读模式
    一直在搞其他事情,好久没搞js加密分析了,正好遇到一个很简单的数据要搞。想着也很久没在论坛发帖了,这次就发下。【某点数据】的榜单数据抓取。

    [Java]  
    1. 列表页接口:【https://xxx/pc/app/v1/rank?market_id=11&genre_id=4&country_id=24&device_id=0&page=1&time=1691424000&rank_type=1&brand_id=1&k=AVUJVF8GAh5QBQVWDFVeBwEcXRwXQhFUXgQGHlkBAVcOTUgRGkwNHBdCEUoYBhxaCFpa】
    2. 打开列表页链接清空下请求,点击下其他的分类,一下子就看到数据返回的接口了。除了k是根据动态计算的,其他都是按照分类或者时间戳写死的。
    复制代码

    TBC茶馆-复仇者黑客组织不停在搞其他事情,很久没搞js加密分析了,恰好遇到一个很简朴的数据要搞。想着也很久没在论坛发帖了,这次复仇者黑客组织(1)
    [Asm]  
    1. 老规矩先全局搜下接口路径,发现没有,好家伙,藏的那么深,从接口执行堆栈流程看到有个getAppRank 过于明显果断从这里开始debug。
    复制代码

    TBC茶馆-复仇者黑客组织不停在搞其他事情,很久没搞js加密分析了,恰好遇到一个很简朴的数据要搞。想着也很久没在论坛发帖了,这次复仇者黑客组织(2)
    [Asm]  
    1. debug过程中发现接口路径是从【/web/api/rank】替换到【/app/v1/rank】
    复制代码

    TBC茶馆-复仇者黑客组织不停在搞其他事情,很久没搞js加密分析了,恰好遇到一个很简朴的数据要搞。想着也很久没在论坛发帖了,这次复仇者黑客组织(3)

    [Asm]  
    1. 最后我们顺着debug看下k的生成规则是啥,发现k是由请求参数+basse64生成这就好弄了,分析下这块逻辑。
    复制代码

    TBC茶馆-复仇者黑客组织不停在搞其他事情,很久没搞js加密分析了,恰好遇到一个很简朴的数据要搞。想着也很久没在论坛发帖了,这次复仇者黑客组织(4)

    简单带你直接把这块js扣下看看缺啥补啥。具体看代码上的注释,已经把原代码和修改的备注了。
    [Asm]  
    1. 20230810 【'1d8en73(i4'】 本以为是固定参数,后发现是每天虽则签名更改,一天都不会变动,等有空再更新上来
    复制代码


    [JavaScript]  
    1. function getToken(e, path, n, r) {
    2.         function u8ArrZBase64(u8Arr) {
    3.           try{
    4.                          let CHUNK_SIZE = 0x8000;
    5.                          let index = 0;
    6.                          let length = u8Arr.length;
    7.                          let result = '';
    8.                          let slice;
    9.                          while (index < length) {
    10.                                  slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
    11.                                  result += String.fromCharCode.apply(null, slice);
    12.                                  index += CHUNK_SIZE;
    13.                          }
    14.                          return btoa(result);
    15.                  }
    16.                  catch(e) {
    17.                          throw e;
    18.                  }
    19.         }
    20.         var s = n.s
    21.           , d = n.k
    22.           , f = n.l
    23.           , v = n.d
    24.           , l = n.sort
    25.           , k = n.num
    26.           , y = function(content, t, e) {
    27.                 for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
    28.                         a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
    29.                 return a.join("")
    30.         }(function(s, t, path, e) {
    31.                 return [s, t, e, path].join("(&&)")
    32.         }(function(t, e) {
    33.                 // 原代码var n = c()(t); 缺c()(t) debug后发现只是简单校验t,我们可以直接把t复制给n
    34.                 var n = t;
    35.                 // 原代码
    36.                 //if (!_()(n)) {
    37.                 //        var r = [];
    38.                 //        for (var d in n)
    39.                 //                m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
    40.                 //                "post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
    41.                 //                r.push(n[d]);
    42.                 //        return r.sort(),
    43.                 //        r.join("")
    44.                 //}
    45.                 // debug并删除无用代码,就是简单拼接
    46.                 var r = [];
    47.                 for (var d in n){
    48.                         r.push(n[d])
    49.                 }
    50.                 return r.sort(),r.join("");
    51.                 // Object(h.b)(s, d, f) 方法主要针对入参n中s,k的Uint8Array,并转成字符串,进去发现只是可以是写死的字符串1d8en73(i4
    52.         }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, l), '1d8en73(i4', k);
    53.         // 最后就是u8Arr转Base64
    54.         return u8ArrZBase64(new TextEncoder().encode(y));
    55. }
    56. var path = '/v1/rank';
    57. var eData = {
    58.     "market_id": 11,
    59.     "genre_id": 6,
    60.     "country_id": 24,
    61.     "device_id": 0,
    62.     "page": 1,
    63.     "time": 1690732800,
    64.     "rank_type": 1,
    65.     "brand_id": 0
    66. }
    67. // s,k,l  均会过期,定时从列表页解析即可,https://xxx/rank/googleplay/11-1-14-24-0?time=1690387200000
    68. var nData = {
    69.     "s": "7f260473b50b9a6beb9a384d3adc2027",
    70.     "k": "d8462b23fc155996",
    71.     "l": "4e226e4686f23bc3",
    72.     "d": 0,
    73.     "sort": "dd",
    74.     "num": 10
    75. }
    76. var rData = "get";
    77. getToken(eData, path,nData, rData)
    复制代码


    [Asm]  
    1. 前几天没来得及更新,次日发现某点还有个需要签名会每天变动,因此以下补充签名生成规则。对应上述代码中 【Object(h.b)(s, d, f)】,开始debug进去查看,着急搬砖直接上解析后的加密规则,在代码里都注释了
    复制代码




    [JavaScript]  
    1. function readUInt32BE(tt, t) {
    2.         return 16777216 * tt[t] + (tt[t + 1] << 16 | tt[t + 2] << 8 | tt[t + 3])
    3. }
    4. function oFunction(t) {
    5.         for (var e = t.length / 4 | 0, r = new Array(e), i = 0; i < e; i++)
    6.                 r[i] = readUInt32BE(t, 4 * i);
    7.         return r
    8. }
    9. // 后续至关重用
    10. var f = [0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54]
    11.   , d = function() {
    12.         for (var t = new Array(256), e = 0; e < 256; e++)
    13.                 t[e] = e < 128 ? e << 1 : e << 1 ^ 283;
    14.         for (var r = [], n = [], o = [[], [], [], []], h = [[], [], [], []], l = 0, f = 0, i = 0; i < 256; ++i) {
    15.                 var d = f ^ f << 1 ^ f << 2 ^ f << 3 ^ f << 4;
    16.                 d = d >>> 8 ^ 255 & d ^ 99,
    17.                 r[l] = d,
    18.                 n[d] = l;
    19.                 var c = t[l]
    20.                   , m = t[c]
    21.                   , v = t[m]
    22.                   , y = 257 * t[d] ^ 16843008 * d;
    23.                 o[0][l] = y << 24 | y >>> 8,
    24.                 o[1][l] = y << 16 | y >>> 16,
    25.                 o[2][l] = y << 8 | y >>> 24,
    26.                 o[3][l] = y,
    27.                 y = 16843009 * v ^ 65537 * m ^ 257 * c ^ 16843008 * l,
    28.                 h[0][d] = y << 24 | y >>> 8,
    29.                 h[1][d] = y << 16 | y >>> 16,
    30.                 h[2][d] = y << 8 | y >>> 24,
    31.                 h[3][d] = y,
    32.                 0 === l ? l = f = 1 : (l = c ^ t[t[t[v ^ c]]],
    33.                 f ^= t[t[f]])
    34.         }
    35.         return {
    36.                 SBOX: r,
    37.                 INV_SBOX: n,
    38.                 SUB_MIX: o,
    39.                 INV_SUB_MIX: h
    40.         }
    41. }();
    42. function _reset(tt) {
    43.         for (var t = tt, e = t.length, r = e + 6, n = 4 * (r + 1), o = [], h = 0; h < e; h++)
    44.                 o[h] = t[h];
    45.         for (h = e; h < n; h++) {
    46.                 var l = o[h - 1];
    47.                 h % e == 0 ? (l = l << 8 | l >>> 24,
    48.                 l = d.SBOX[l >>> 24] << 24 | d.SBOX[l >>> 16 & 255] << 16 | d.SBOX[l >>> 8 & 255] << 8 | d.SBOX[255 & l],
    49.                 l ^= f[h / e | 0] << 24) : e > 6 && h % e == 4 && (l = d.SBOX[l >>> 24] << 24 | d.SBOX[l >>> 16 & 255] << 16 | d.SBOX[l >>> 8 & 255] << 8 | d.SBOX[255 & l]),
    50.                 o[h] = o[h - e] ^ l
    51.         }
    52.         for (var c = [], m = 0; m < n; m++) {
    53.                 var v = n - m
    54.                   , y = o[v - (m % 4 ? 0 : 4)];
    55.                 c[m] = m < 4 || v <= 4 ? y : d.INV_SUB_MIX[0][d.SBOX[y >>> 24]] ^ d.INV_SUB_MIX[1][d.SBOX[y >>> 16 & 255]] ^ d.INV_SUB_MIX[2][d.SBOX[y >>> 8 & 255]] ^ d.INV_SUB_MIX[3][d.SBOX[255 & y]]
    56.         }
    57.         return {
    58.                 '_nRounds' : r,
    59.                 '_keySchedule' : o,
    60.                 '_invKeySchedule' : c
    61.         }
    62. }
    63. function DAES(t) {
    64.         var _key = oFunction(t);
    65.         var rs = _reset(_key);
    66.         return {
    67.                 '_key' : _key,
    68.                 '_nRounds' : rs._nRounds,
    69.                 '_keySchedule' : rs._keySchedule,
    70.                 '_invKeySchedule' : rs._invKeySchedule
    71.         }
    72. }
    73. function dFrom(sData,sP) {
    74.         k(sData,sP,0,16);
    75.         return sData;
    76. }
    77. function k(t, e, r, n) {
    78.         r = Number(r) || 0;
    79.         var f = t.length - r;
    80.         n ? (n = Number(n)) > f && (n = f) : n = f;
    81.         var o = e.length;
    82.         if (o % 2 != 0)
    83.                 throw new TypeError("Invalid hex string");
    84.         n > o / 2 && (n = o / 2);
    85.         for (var i = 0; i < n; ++i) {
    86.                 var c = parseInt(e.substr(2 * i, 2), 16);
    87.                 if (isNaN(c))
    88.                         return i;
    89.                 t[r + i] = c
    90.         }
    91.         return i
    92. }
    93. function l(t, e, r, n, o) {
    94.         for (var h, l, f, d, c = r[0], m = r[1], v = r[2], y = r[3], w = t[0] ^ e[0], _ = t[1] ^ e[1], M = t[2] ^ e[2], S = t[3] ^ e[3], E = 4, k = 1; k < o; k++)
    95.                 h = c[w >>> 24] ^ m[_ >>> 16 & 255] ^ v[M >>> 8 & 255] ^ y[255 & S] ^ e[E++],
    96.                 l = c[_ >>> 24] ^ m[M >>> 16 & 255] ^ v[S >>> 8 & 255] ^ y[255 & w] ^ e[E++],
    97.                 f = c[M >>> 24] ^ m[S >>> 16 & 255] ^ v[w >>> 8 & 255] ^ y[255 & _] ^ e[E++],
    98.                 d = c[S >>> 24] ^ m[w >>> 16 & 255] ^ v[_ >>> 8 & 255] ^ y[255 & M] ^ e[E++],
    99.                 w = h,
    100.                 _ = l,
    101.                 M = f,
    102.                 S = d;
    103.         return h = (n[w >>> 24] << 24 | n[_ >>> 16 & 255] << 16 | n[M >>> 8 & 255] << 8 | n[255 & S]) ^ e[E++],
    104.         l = (n[_ >>> 24] << 24 | n[M >>> 16 & 255] << 16 | n[S >>> 8 & 255] << 8 | n[255 & w]) ^ e[E++],
    105.         f = (n[M >>> 24] << 24 | n[S >>> 16 & 255] << 16 | n[w >>> 8 & 255] << 8 | n[255 & _]) ^ e[E++],
    106.         d = (n[S >>> 24] << 24 | n[w >>> 16 & 255] << 16 | n[_ >>> 8 & 255] << 8 | n[255 & M]) ^ e[E++],
    107.         [h >>>= 0, l >>>= 0, f >>>= 0, d >>>= 0]
    108. }
    109. function N(t, e, r, n) {
    110.         e < 0 && (e = 4294967295 + e + 1);
    111.         for (var i = 0, f = Math.min(t.length - r, 4); i < f; ++i)
    112.                 t[r + i] = e >>> 8 * (n ? i : 3 - i) & 255
    113. }
    114. function writeUInt32BE(tData, t, e,r) {
    115.         return t = +t,
    116.         e |= 0,
    117.         true ? (tData[e] = t >>> 24,
    118.         tData[e + 1] = t >>> 16,
    119.         tData[e + 2] = t >>> 8,
    120.         tData[e + 3] = 255 & t) : N(tData, t, e, !1),
    121.         e + 4
    122. }
    123. function decryptBlock(t,kData){
    124.         var e = (t = oFunction(t))[1];
    125.         t[1] = t[3],
    126.         t[3] = e;
    127.         var thisData = DAES(new TextEncoder().encode(kData));
    128.         var tData = new Uint8Array(16);
    129.         var r = l(t, thisData._invKeySchedule, d.INV_SUB_MIX, d.INV_SBOX, thisData._nRounds)
    130.           , h = new Uint8Array(16);
    131.         // console.log('e:'+e);
    132.         // console.log('h:'+h);
    133.         // console.log('r:'+r);
    134.         // console.log('t:'+t);
    135.         writeUInt32BE(tData, r[0], 0),
    136.         writeUInt32BE(tData, r[3], 4),
    137.         writeUInt32BE(tData, r[2], 8),
    138.         writeUInt32BE(tData, r[1], 12),
    139.         h;
    140.         return tData;
    141. }
    142. function exports(a, b) {
    143.         for (var t = Math.min(a.length, b.length), r = new Uint8Array(16), i = 0; i < t; ++i)
    144.                 r[i] = a[i] ^ b[i];
    145.         return r
    146. }
    147. function slice(tData, t, e) {
    148.         var r, n = tData.length;
    149.         if ((t = ~~t) < 0 ? (t += n) < 0 && (t = 0) : t > n && (t = n),
    150.         (e = void 0 === e ? n : ~~e) < 0 ? (e += n) < 0 && (e = 0) : e > n && (e = n),
    151.         e < t && (e = t),true)
    152.                 (r = tData.subarray(t, e)).__proto__ = d.prototype;
    153.         return r
    154. }
    155. function ttt(t) {
    156.         var e = t[15];
    157.         if (e < 1 || e > 16)
    158.                 throw new Error("unable to decrypt data");
    159.         var i = -1;
    160.         for (; ++i < e; )
    161.                 if (t[i + (16 - e)] !== e)
    162.                         throw new Error("unable to decrypt data");
    163.         if (16 === e)
    164.                 return;
    165.         return slice(t, 0, 16 - e)
    166. }
    167. function getSign(sData,kData,lData){
    168.         // 按s字符串生成 对应 16位数组
    169.         var dFromResult = dFrom(new Uint8Array(16),sData);
    170.         console.log(dFromResult);
    171.         // 将k转16为数组通过 DAES方法 生成_key、_nRounds、_keySchedule、_invKeySchedule,等签名所需参数,并返回执行结果
    172.         var decryptBlockResult= decryptBlock(dFromResult,kData);
    173.         console.log(decryptBlockResult);
    174.         var exportsResult = exports(decryptBlockResult,new TextEncoder().encode(lData));
    175.         console.log(exportsResult);
    176.         // 按数组切片重组并转成字符串得到签名
    177.         return new TextDecoder("utf-8").decode(ttt(exportsResult));
    178. }
    179. var params = process.argv.splice(2);
    180. process.stdout.write(getSign(params[0],params[1],params[2]));
    复制代码





    [Asm]  
    1. 最后先调用getSign 再根据参数调用getToken即可
    复制代码



    TBC茶馆-复仇者黑客组织不停在搞其他事情,很久没搞js加密分析了,恰好遇到一个很简朴的数据要搞。想着也很久没在论坛发帖了,这次复仇者黑客组织(5)




    上一篇:fiddler everywhere 3.3.0 去除授权校验
    下一篇:WizTree(大文件目录排查工具)去除右上方抖动捐赠提示-小白级别

    该用户从未签到

    0

    主题

    1293

    帖子

    2

    积分

    新手上路

    Rank: 1

    积分
    2
    发表于 2023-9-19 02:14:03 | 显示全部楼层
    https://static.diandian.com/_app/app~f69643ec.f0b6bc0.js

    1:400756 这个e(n)好像也能生成k这个参数
    回复

    使用道具 举报

    该用户从未签到

    2

    主题

    1265

    帖子

    1245

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1245
    发表于 2023-9-19 02:14:22 | 显示全部楼层
    支持帮顶谢谢大佬!
    回复

    使用道具 举报

    该用户从未签到

    4

    主题

    1266

    帖子

    1010

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1010
    发表于 2023-9-19 02:15:13 | 显示全部楼层
    都是大佬啊,牛
    回复

    使用道具 举报

    该用户从未签到

    3

    主题

    1266

    帖子

    1261

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1261
    发表于 2023-9-19 02:16:00 | 显示全部楼层
    大佬优秀,我去试试其他站可不可以
    回复

    使用道具 举报

    该用户从未签到

    3

    主题

    1232

    帖子

    850

    积分

    高级会员

    Rank: 4

    积分
    850
    发表于 2023-9-19 02:16:44 | 显示全部楼层
    感谢分享,其他的我也试试看行不行
    回复

    使用道具 举报

    该用户从未签到

    1

    主题

    1230

    帖子

    260

    积分

    中级会员

    Rank: 3Rank: 3

    积分
    260
    发表于 2023-9-19 02:17:13 | 显示全部楼层
    教程很详细,学习了
    回复

    使用道具 举报

    该用户从未签到

    1

    主题

    1158

    帖子

    890

    积分

    高级会员

    Rank: 4

    积分
    890
    发表于 2023-9-19 02:18:12 | 显示全部楼层
    这个容易黑号
    回复

    使用道具 举报

    该用户从未签到

    3

    主题

    1266

    帖子

    1261

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1261
    发表于 2023-9-19 02:18:40 | 显示全部楼层
    值得学习的文章
    回复

    使用道具 举报

    该用户从未签到

    4

    主题

    1240

    帖子

    1020

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1020
    发表于 2023-9-19 02:18:48 | 显示全部楼层
    这个感觉还阔以
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭Powered by ©科大讯飞语音云
    嗨!您好:
    欢迎来到 复仇者黑客组织。
    我的名字叫小光
    很高兴能够为您服务!
    如果已经注册【立即登录】
    还没有账号请立即注册
    Loading...
    快速回复 返回顶部 返回列表