大家好,相信各位童鞋通过上期《Python爬虫之Js逆向案例(7)-知hu最新x-zse-96之rpc方案》这篇文章了解了什么是jsrpc
、原理,以及如何使用该方案获取x-zse-96
加密!今天案例主角是其兄弟字段x-zst-81
,该字段在一个半月前就扣过,这个字段的加密变化似乎不是特别大,所以想了解x-zst-81
字段定位详细过程的可前往阅读《Python爬虫之Js逆向案例(4)-zhihu x-zst-81》。该字段的调用过程跟webpack
有关,因此选为本节分享的案例内容,也是js逆向
必备技能之一,webpack
!
为了照顾刚入门童鞋,文章每一步的分析过程尽可能的详细(有经验的同学可以选择感兴趣的地方快速浏览)
下面会进行以下几步进行分析(下方演示过程全部使用chrome
浏览器);
webpack
?;webpack
产物;webpack
代码;python
爬虫结果演示;webpack官网中的一句原话是这样说的:
本质上,
webpack
是一个现代JavaScript
应用程序的静态模块打包器(module bundler)。当 webpack
处理应用程序时,它会递归地构建一个依赖关系图(dependency
graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
正如上面描述的一样,这个东西就是一款现代化的前端模块打包工具而已!!!
它是打包工具跟我们逆向有什么关系???
有关系呀!这个东西既然是前端打包用的,那有些网站必然会用到这些工具,而且该工具在当前的前端开发过程中,使用率极高,注意是极高哦!!!毫不夸张的说,webpack
在目前前端打包工具使用上绝对是NO.1
,所以我们在逆向时碰到一个网站使用webpack
打包的概率可比买刮刮乐中奖概率大太多,因此,webpack
的逆向分析就必须拿出来分析分享一下了!
webpack
官网上介绍了那么多东西,对于学习逆向的童鞋来说,我们需要全部都精通吗?
啥?!!!全部都精通?别开玩笑,我们是在学习逆向的技能,又不是为了精通前端打包!
所以,我感觉没必要,对于逆向来说,只需要学会辨别webpack
产物、执行webpack
模块,足够了!
不扯了!下面开始正题!
webpack
特征还算比较明显,先来看一下大体结构:
!function(e){
// 内部函数c
function c(t) {
if (r[t])
return r[t].exports;
var n = r[t] = {
i: t,
l: !1,
exports: {}
};
return e[t].call(n.exports, n, n.exports, c),
n.l = !0,
n.exports
}
}(
// 参数是个对象
{
"SXT9":function(){
console.log("test")
}
}
)
或者:
!function(e){
// 内部函数c
function c(t) {
if (r[t])
return r[t].exports;
var n = r[t] = {
i: t,
l: !1,
exports: {}
};
return e[t].call(n.exports, n, n.exports, c),
n.l = !0,
n.exports
}
}(
// 参数是个数组
[
function(){...},
function(){...},
function(){...},
]
)
我们简单解剖一下上面的特征:
!function(e){}()
call
、apply
、exports
的内部函数:// 函数c可能会是其他的名称a,b,z等等,但是函数内部的结构长得基本都是下面这个样子:
function c(t) {
if (r[t])
return r[t].exports;
var n = r[t] = {
i: t,
l: !1,
exports: {}
};
return e[t].call(n.exports, n, n.exports, c),
n.l = !0,
n.exports
}
上面这个函数其实是webpack
的模块加载器!他的作用就是根据实际需要,把自执行函数里的参数中的模块提取出来,以供后续执行;
至于
call
和apply
的作用,可以去MDN上看解释,我就不再复述了。
// 自执行函数
!function(e){}(参数)
// 参数类型 对象型
{
XXXX:function(){}
}
// 参数类型 数组型
[
function(){...},
function(){...},
]
webpackJsonp
模块:能辨别上面这些东西,基本上webpack
有关的内容就学一半了。是不是很简单!!!
下面内容主要有4个任务
:
- 确定加密函数所在位置;
- 扣到加密函数的代码;
- 导出加载器到全局变量;
- 使用加载器执行加密模块,拿到加密值;
定位代码、扣代码这块在《Python爬虫之Js逆向案例(4)-zhihu x-zst-81》中有详细介绍,这里就不说那么详细了。
xZst81
字段是由n()
函数执行后生成的,如下图:
观察这个加密后发现,加密函数所处的位置正是在自执行函数的入参模块中,如下图:
我们把整个自执行函数全部扣出来,好家伙呀!这个自执行函数有9w多行
,,,没办法,模块太多分不清哪些是用不到的,先都抠出来吧!新建一个文件zh_xzst81_rpc.js
。
注意,这个时候我们不要只扣着一个模块的代码,因为这个模块还依赖其他的模块,只扣这一点无法运行;
高能总结
技巧:如果你此时也是使用了编辑器vscode
的话,上面扣到的代码9w多行
,太大了,可以把代码块先折叠起来,再根据需要搜索到对应位置。vscode
折叠代码块的快捷键:按下command
键之后(不松开),再分别按下k
和0
(是零,不是o
)。
在自执行函数外定义一个全局变量get_loader
,如下图:
把加载器在自执行函数体的最下方赋值给全局变量,如下图:
继续调试,发现n()
函数的实现代码也是在另一个webpack
模块的内部,如下图:
从上面我们能看到,执行加密的模块跟调用加密的模块不在一个文件里,这该怎么办呢?
不要慌!
此时把webpackJsonp
这个文件全部扣出来,放到zh_xzst81_rpc.js
文件中即可。细心的小伙伴可能留意到自执行函数体里有一行代码,如下图:
也就是说:
自执行函数在运行时,就已经把放在
webpackJsonp
上全局的模块给加载进去了,后面加载器之行模块的时候就能直接调用,内部怎么运行可以不用管!
到这里,本案例中需要扣的代码就已经扣完了!
怎么调用这个加密模块呢?
那肯定是先从加密位置所在的上下文模块开始运行了,于是只需要把这块加密相关的模块扣出来,放在zh_xzst81_rpc.js
文件最下方,换成我们自定义的全局变量去加载就行了,n
换成get_loader
,如下图:
我们把zh_xzst81_rpc.js
文件里的所有代码放到snippet
里运行一下试试结果:
完美拿到xzst81
字段加密值!是不是很开心!
先别开心太早!毕竟运行的是扣出来的代码,还需要验证的!!!
验证:
- 先生成
xzst81
的加密结果;- 拿到
xzst81
的结果去生成x-zse-96
的加密结果;
实际上如果使用rpc的方式,不用扣这么多代码,或者根本不用扣代码,操作可参考这个链接:https://blog.csdn.net/u014644574/article/details/121933772
Q1:
x-zst-81
相关代码扣出来之后能不能在本地运行?
A1:目前不能。跟x-zse-96
字段生成一样,也校验了很多环境,如果童鞋有时间的话,可以去补环境,补全之后应该是可以的。本案例本地不能运行并不代表其他案例不能,下一期会分享一个webpack扣出来之后本地能运行的。
Q2:代码既然不能在本地用,那在爬虫代码里如何使用呢?
A2:可参考《Python爬虫之Js逆向案例(7)-知hu最新x-zse-96之rpc方案》中介绍的方案,结合rpc
的方式使用;
Q3:扣出来的代码
9W多行
,能不能优化呢?
A3:可以优化,优化技巧请留意知识星球!
下期预告,一个webpack扣出来之后本地能直接运行的、相对简单一点的案例!
webpack
逆向技能也是学习逆向时的必备技能请务必掌握!!!本案例操作时有疑问,可留言、私信,或者去星球提问一对一指导!
后期会持续分享爬虫案例-100例,不想自己造轮子的同学可加入我的知识星球,有更多技巧、案例注意事项、案例坑点终结、答疑提问特权等你哦!!!
欢迎加入「python、爬虫、逆向Club」知识星球