10-七麦js扣代码

我们来用一个案例来解释js扣代码:qimai数据

寻找加密位置

下xhr断点

打开网站,打开开发者工具,抓取翻页数据包(多取几个,对比数据)

发现**analysis**是加密数据,尝试搜索关键字:

全都没找到数据,很可能是混淆了,别白白费力气了,这个参数也不特殊,本人不知道怎么hook,所以我选择xhr

下面来xhr定位:

粘贴到xhr断点的地方然后关闭开发者工具 ,因为我们之前为了对比数据包中的参数把翻页翻完了,数据加载过了,没办法重新触发断点,所以要重新刷新网页,再打开开发者工具,触发翻页接口,打上xhr断点

看参数

我们直接看最外层那个函数的传参:

我们所在的栈是作用域跟到的位置(就是后面有黄色字体的地方) ,而我们看的是所在栈的外层函数 ,只有调用了外层函数 才能进来内层 ,所以外层也是程序运行经过的地方 ,自然放入了栈堆,正好是在所在栈的前一栈 ,所以相当与我们直接看的是前一个栈 ,而这个栈参数是加密的,所在栈就不用看了。我的意思是,既然这种可以,(栈多的时候)我们也可以在右边直接二分法跳栈分析,前一个栈都是加密的,那后一栈就不用看了,节省时间

然后我们看所在栈的上上一个栈:

然后再继续跟发现跟不过去(作用域不在上个栈了)

这是因为异步调用无法跟栈,异步标志:

跟进异步

我们可以在异步执行之前的代码中打上断点:

然后下拉页面触发断点:

然后看加密参数是否是加密的,结果是正常的,没有加密参数,url也是正常的:

那可能加密逻辑就在这个函数中,但是我们看整个函数的逻辑也没有加密的逻辑,然后异步回调之后的e就有了加密参数:

说明加密逻辑藏在异步中,我们来着重看一下这段代码(在js中这段代码会很常见):

首先是一个for循环,然后看for后面那个括号后一半括号在哪儿,是在t.length之后,然后t.length前面是分号,根据for循环语法:

javascript 复制代码
for (初始化表达式; 条件表达式; 更新表达式) {
    // 循环体
}

说明t.length才是for循环的条件,然后n.then是循环体

这里有两点说一下:

1.t.shift()是每次删除一个t中的元素然后返回出来删除的元素

2...then异步调用成功执行括号中第一个·t.shift(),失败调用第二个t.shift(),但是不管调不调用某一个,那一个都会取出一个元素然后放在那里等着调用,意思就是每次运行完.then这一行t中都会少两个

所以每次循环一遍就少俩,此循环就循环三次,刚我们说了加密逻辑藏在异步中,一般来说异步都会成功,所以调用的很可能就是第一个t.shift,那么每次取出的就是0,2,4,我们逐个打断点(如果不放心可以每一个都打上断点)然后运行:

断下来了,说明走这条路而且这里数据也是加密的,那说明加密位置很可能就在这里了,为什么?因为你都打上断点了,他走的第一条路就会被断下来,走之前没加密,走过来就加密了,那很可能就在此了,这里混淆了,这里我们从上往下分析(这个图是因为运行到最下面加密完数据了,t就变成了密文):

上面其实就是个拦截器(函数.interceptors.request.use):

javascript 复制代码
axios = require('axios');

// 请求拦截器
axios.interceptors.request.use(function (config) {  // 请求成功
    console.log('success')
    config.headers['sign'] = '123456'  // 此处可以添加参数加密
    return config
})

// 写要拦截的网站
axios.get('https://httpbin.org/get').then(res=>{console.log(res)})

这不就是把数据拦截下来然后加密在传过去的套路吗

确定加密位置

但是有一个问题,直接运行到return t没法逐步分析了,因为运行到最后所有都成了密文,很难找加密起始的位置,而且这里混淆了也看不出加密关键字,我们重新触发一下断点,上一文我们说尽量不要直接刷新网页,因为接口不同,现在跟我步骤:

这样就过掉了所有断点,然后刷新页面,并关掉'停用断点'(如果停在了xhr断点那里就启用'停用断电'过去然后再重新关闭'停用断点')现在是这个样子:

然后下拉页面触发断点(之前断点没删就一点一点运行进来就行):

然后逐步运行观察右侧t.url在哪变成密文

往下运行:

点了五次到这里,目前无密文,继续运行:

说明url中的密文在黄线上方产生(在黄线上的是准备运行的代码,黄线上面的是刚运行的代码),然后在刚执行的代码那行打上断点,重复上面步骤重新进入这个函数,然后直接运行,断在刚打断点这里即可,然后再分析这行代码(因为运行完可能会变):

javascript 复制代码
-B == t[qt][O](v) && (t[qt] += (-B != t[qt][O](Bn) ? Nn : Bn) + v + B5 + R[V5](e))

首先有一个逻辑与:&&当左侧代码为true时运行右侧代码,然后后面有一个三元运算符:

t[qt] += (-B != t[qt][O] ? Nn : Bn

当-B != t[qt][O]成立时运行问号后代码,不成立运行冒号后代码,后面就没啥了,然后在浏览器分析:

前面是true,接着运行:

false运行冒号:

现在结果是:"/rank/release?"+... 继续运行:

结果为:"/rank/release?analysis="+... 继续运行:

R是window,调用window中的encodeURIComponent 方法,我们查一下这个方法:

意思就是转换一种编码,不用管,然后我们发现了:

下面就是确定真正的加密位置了,e肯定是被赋值的,一点一点往上找:

逗号表达式写出来就是这个样子(把零和括号删掉就能变清晰):

javascript 复制代码
e = i[Jt](i[Qt](a, d))

然后i中调用了Jt函数,参数为i[Qt](a, d),然后i中又调用了Qt函数,参数为a和d,d不知道哪儿来的,但是a有来源(找赋值的地方):

在最开头的地方打上断点,重新将代码运行过来:

看看a怎么生成的:

就是和py中的lst.jion("")一样,将'列表'中的字符串拼接在一起,然后经过两行代码将a参数整理出来:

然后和d参数一起传入一个函数然后加密出e,其实到这里我们基本已经知道加密的核心代码了:

那就把它拿下来

扣代码

扣下核心代码

扣下核心代码并整理:

封装函数

将核心代码封装成函数,第一行的a是传入的,封装成函数之后为防止a混乱,将式子中的a换一个名字,然后将参数先写死,var一个变量接收:

然后调用函数运行一下看看:

报错了,说明缺东西,缺环境,下面就要补全这些环境

补环境

补环境就缺啥补啥就行,但是需要耐心和细心,上一幅图缺i,那我们回到浏览器看看i是啥:

为啥Jt是函数呢,记住一句话,括号前面是函数,括号里面是参数(个人总结不一定百分百对)还有一种就是你直接进对象i里找,这里混淆之后是Jt,鼠标放上是cv,你就找i中的cv就行:

打开cv,是个函数,点进去(有函数入口(FunctionLocation)是开发者写出来的函数,用的话要进去cv大法,没有的大概就是内置可以直接拿着函数名用的):

复制这一段:

粘贴下来,并改下函数名:

然后再运行:

我们需要先进入cv函数然后加上断点运行进来看看R是个啥:

发现R是个window对象,接着看:

V5(调用的是encodeURIComponent方法)

R[V5](这里没有FunctionLocation就是内置函数可以直接像我一样用)

t

T

直接把这些方法补进我们的代码中:

继续运行:

回原文继续改:

都打上断点,看看它走哪条路:

再运行:

回浏览器去看:

重新触发断点,都看看吧:

p

qt

T

t[Tt]

N

r(这里不是固定的,看是不是固定的可以过掉断点重新触发看看一不一样)

r生成逻辑(可以局部搜索Ctrl+ F或者先在本函数作用域找):

除了r都是固定值,直接补上(可以在控制台输出这些,到时候报错一个个补)再运行:

运行后会报出i未定义,进入浏览器打上断点,运行看i和i[Jt],i[Qt]:

i[Jt]

是cv欸,我们有救了(不就是我们刚写的改名为func_cv的函数么)

i[Qt]

是函数,进去Ctrl + C

将上面的补入代码:

运行一下:

进入浏览器打上断点,运行进来:

$5

补上:

下面开始参数d

那就只有一种可能,它的上一级作用域这个变量就有了,先看一下全局:

炒鸡多啊,大概看下没有,一般来说赋值其实不会太远,我们Ctrl + F局部搜索一下d =

发现这里挺像,离得很近,而且它所在的作用域在刚那个函数的上一级,下个断点,刷新触发断点(这里的数据是刷新页面时就加载好了的,通过翻页没法断下来,只有再刷新让他再加载一遍才能从这里过从而断下来):

控制台输出一下:

然后记住,重新刷新页面看看是不是固定的:

那就是固定的,把d填上,再运行:

看来还需要补N,找一下:

顺手看下I5

说明是join("")方法,补上:

后面就报错哪里就找哪里就行,大多补环境的方法已经讲过,总结一下:

TOP0:缺啥补啥,报错啥回去找到啥

1.显示是函数的就进函数cv大法,但有些是内置函数没有入口就直接复制函数名直接用就行

2.不确定参数变不变就多运行到断点几次看看一不一样

3.对于当前定义域中没有的变量就局部搜索Ctrl+F或者附近找找

4.看起来特殊点的可以全局搜索(和关键字搜索一样)Ctrl+Shift+F

注意:前面有些我是连着找连着补,尽量补一个运行一个,报错之后,再找再补再报错,再找再补再... ...

最后代码是这样的:

javascript 复制代码
// 扣核心代码
var params_ = '2025-09-302025-09-302025-09-303364allcn'

function func_cv(paramsFromMain) {
                t = encodeURIComponent(paramsFromMain)['replace'](/%([0-9A-F]{2})/g, function(n, t) {
                    return func_o("0x" + t)
                });
                try {
                    return btoa(t)
                } catch (n) {
                    return R[W5][K5](t)[U5](Z5)
                }
            }
function func_o(n) {
                t = "",
                ["66", "72", "6f", "6d", "43", "68", "61", '72', "43", "6f", "64", "65"].forEach(function(n) {
                    t += unescape("%u00" + n)
                });
                var t, e = t;
                return String[e](n)
            }
function func_oZ(n, t) {
    t = t || u();
    for (var e = (n = n["split"]("")).length, r = t.length, a = "charCodeAt", i = 0; i < e; i++)
        n[i] = func_o(n[i][a](0) ^ t[(i + 10) % r][a](0));
    return n.join("")
}
function main(params) {
    a = func_cv(params) // 调用func_cv函数
    a = (a += "@#" + "/rank/release".replace("https://api.qimai.cn", "")) + ("@#" + new Date - (-3 || 0) - 1661224081041) + ("@#" + 3)
    e = func_cv(func_oZ(a, 'xyz517cda96efgh'))
    return e
}

console.log(main(params_))

总结

逆向其实大方向就是:

1.确定加密位置

2.扣关键代码并封装

3.补环境(看着麻烦,实则有时候确实麻烦)

4.若py需要此接口密文,那就调用核心代码函数

这节课挺长,动手实践一下然后理解大方向即可,多做几个案例就会了,之后学习标准算法有时候就不需要这么麻烦了,若本文有哪些地方有误请及时纠正,或者交流讨论,加油加油

相关推荐
Komorebi_99998 小时前
Vue3 + TypeScript provide/inject 小白学习笔记
前端·javascript·vue.js
少吃一口都不行8 小时前
脚手架学习
前端·javascript·学习
地方地方8 小时前
手写JavaScript 深拷贝
前端·javascript
yeyuningzi8 小时前
npm升级提示error engine not compatible with your version of node/npm: npm@11.6.2
前端·npm·node.js
1024小神8 小时前
next 项目中的 'use client' 是什么意思
前端
77qqqiqi8 小时前
python循环语句
python
我是华为OD~HR~栗栗呀8 小时前
24届-Python面经(华为OD)
java·前端·c++·python·华为od·华为·面试
2401_841495648 小时前
【数值分析】插值法实验
python·数学·算法·可视化·数值分析·数学原理·插值法
whysqwhw8 小时前
mac上AndroidStudio升级无写入权限问题
前端