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需要此接口密文,那就调用核心代码函数

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

相关推荐
寻星探路3 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
ValhallaCoder5 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
猫头虎6 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端