python爬虫 - js逆向之取巧秒解webpack打包的加密参数
前言
今天的分析对象是这个:aHR0cHM6Ly9tLmN{防查找,去掉我,包括大括号}0eXVuLmNuL3dhc{防查找,去掉我,包括大括号}C9tYWluL2F1dGgv{防查找,去掉我,包括大括号}bG9naW4=
就是去搞这个登录接口的加密参数
就这三个参数
第一个不用说,就是个时间戳
第二个comParam_seqCode和第三个comParam_signature就是我们要破解的参数了
分析
开始搞吧,直接搜索comParam_seqCode
很快就找到了这里,同时第三个参数sign也找到了
打断点测试下吧
输入账号密码,点击登录,然后跟着断点走:
走到了这里:
先看下这个t.d是属于哪个函数对象的,往上找第一个外层定义的,不太理解的,诀窍就是,往上跟着找同排列的同级的,然后第一个同级的外层定义体,这个就是函数对象了,如下:
继续点,又走到了这里,说明这里才是实际的加密逻辑
看这种加密逻辑,有点像webpack啊,直接搜webpack看看:
还真的有,那就可以走一个取巧的方案了,因为本篇文章,标题也说了取巧方式,所以不会直接去逆向,而是用webpack的属性,导出我们需要的加密方法,然后调用即可
怎么导出,先不急,看看加密逻辑,上面是第二个参数,再看第三个加密参数的逻辑,接着走断点:
发现走到一个chunk里,这个chunk名字不重要
先看这个S是在哪个函数对象里,网上找,发现这个8d81,好,做个记录
继续走断点,走完断点,第二个,第三个参数,值都有了
整个流程就完了,总结下,comParam_seqCode进入到了一个7f6d的函数对象里,comParam_signature进入到了一个8d81里,这里我们只需要把这两个函数导出来,然后调用即可
调试
这里就不多说了,webpack其实是一种代码打包压缩,实际上并不是加密,搞过vue的应该有了解,我的博客里也有vue相关的文章:https://www.cnblogs.com/Eeyhan/category/1422542.html
具体就不多介绍了,反正就是,webpack打包之后,最后会暴露出一个入口,这个入口会被调用,然后才进入核心的webpack代码,所以我们找到这个打包到入口函数的过程,然后赋值给一个全局对象,我们直接调用这个全局对象就可以直接用里面的方法了,具体逻辑就不太好用文字说明了,直接实操吧:
找到导出器exports,包含exports的字眼,因为所有的webpack打包,都长这样,一搜发现还挺多的,那哪个才是我们要用的呢?
先把这个main.xxx.js的代码全部复制下来,放在本地,在上面我看着眼花,而且没法缩进,本地搜发现就12个
找一个定义export之后又立即有操作的,就是它了,一般在整个js的最开始部分,这里一找就找到了
可以看看,其他的都是些赋值操作:
中间略过。。。。。。
后面全是赋值操作,这种我们也不方便处理,肯定要在一个地方设置之后一劳永逸的,那一定是最开始那里了
那好,开始操作吧,我们先在js文件的最开始部分,定义两个变量,不给修饰符就默认是全局变量,当然你也可以给个var
然后再刚才定位到导出器那里,如下设置:
if (typeof (_map[n]) == 'undefined'){
_map[n] = 1;
_code = _code+ '"'+n+'":'+e[n]+",";
}
注意,一定要在return前面,exports定义的后面
再在这个函数的后面赋值给一个全局对象,值为这个函数名:
最后一步,把导出器输出的入口函数去掉,因为我们根本就不需要它了,删掉t()即可,然后保证代码不标红
已经完了?
没有呢,我们还要做导出捕获,打开fiddler,把线上的那个js替换成我们改过的这个js文件,打开fiddler:
保存之后,浏览器直接开个无痕模式吧,懒得去清那个站的cookie了,搞起麻烦,开无痕,两个对比,正好,回车:
打开看到fiddler那个文件报错了
把路径的反斜杠改为斜杠,保存,重新刷新,网站打开是空白,不要紧,打开控制台
顺便看看,这边也成功请求,只要不是红色就是没问题,如果是红色,请检测你的路径
现在在控制台里,看看刚才的方法能用不:
ojbk
现在把7f6d的放进去执行,
执行完了后,_code里就会有东西,这个_code一开始是空的,执行了window.get_code后,就会把相关的东西放进_code里,这里你可以理解为手动调用了一次导出器,把要导出的东西放到了_code里
把这一长段js复制出来,调整下,直到不标红,这个是个繁琐且没有技术含量的操作,但是却是一项不可缺失的操作,就像曾经在大厂呆过的我一样,做的事感觉low,但是就是不可缺失
调整完之后,把这整段代码,替换掉刚才本地的js里的这段:
就是上面的最后缩进好的整段,但不包括大括号哈,原始的部分内容如下:
现在把刚才调整好的导出的js覆盖掉上面的,调整完如下,第一个就是7f6d
现在就开始调用了,如下:
报错了,先放一放,有朋友应该会问了,你怎么知道要调用k啊,看最开始的代码,这个u['k'].(),这个写法不纠结了,反正我告诉你此时跟k()是一个意思
继续看那个报错,把window补齐下,这个就再熟悉不过了,补齐,此时这里的window一定要写成global才行,写成空对象{}不能出值,调用k
继续执行,又报了个userAgent的错
这个就很简单了
继续执行:
补:
继续,ok,comParam_seqCode是有了,
接下来第三个加密参数,这个就有点意思,因为我们刚才拿到的是8d81,但我们如下调用,报错了,
这,有点意思了,那还是像刚才那样,去导出看看,先把补环境这里注释掉,
继续用fd替换然后控制台执行:
然后把这段代码,跟之前的7f6d放一起就行了:
现在再执行下这个函数,不报错了,
调用看看,这里又有个问题,怎么调用啊,直接调用看看:
这个值也不知道对不对,打断点走到这里看看,注意这里的代码不是替换过的代码,原始代码:
这时候,在控制台执行看看,发现,不传任何值的时候,完美,对上了,此时感觉有点像md5啊,不过不用细抠逻辑,相信就算是md5也肯定是做了加盐的,肯定不会原始的md5
那传对应值呢?先看调用逻辑
那o我们已经有了,a,t,n是啥?原始代码的控制台看看:
发现a就是刚才的k()方法的值,t是固定的,n就是个时间戳,不过精确到了微妙级别,ok,就用这三个值单独调用下,看能不能对上就行了:
再看原始的控制台输出呢,对上了,此时此刻,其实已经可以说算搞定了
再看comParam_signature 其实是o()(n + a + o()(a + t + n))
那么我们的代码就写成如下即可:
执行结果就不对比了,就掉了两次而已,三个参数也没变,没有太大区别,成了
就是这样的了
后续就可以把这段js封装成一个函数,然后被python的pyexecjs库执行即可,然后带上加密参数去请去,完美,另外注意那个t变量,因为是写死的,保不齐可能会像某词典一样,不定期改变这个值,所以你要长期用,应该要单独写一个程序去请求这个js获取源码,把t抠出来作为变量传入,活动输出,具体的python代码细节就不展开了,也不是什么难事了,略过
补充
其实,这种不算是实际的破解,而是调用,玩逆向的,不要纠结于用的什么方法解决,能搞定就行了,但是平时实际的研究的时候,对于一个问题掌握多个解决方法,肯定是可以的
另外,如果对这个webpack逻辑熟悉,不用搞得那么复杂,我只是写的比较细,真的操作秒解决不是夸张说法
有经验的人怎么做,拿到7f6d和8d81之后
第一步
把名字为main的js文件内容copy下来,然后把最后那一大坨本来要覆盖的,直接删除
第二步
把7f6d和8d81在源码里搜到的,复制下来放进去:
第三步:
啥都不用管,直接把这个导出器的结果赋值了
第四步:
执行,然后,缺啥补啥,补环境略过,一样可以拿到值
都不需要用fiddler替换,然后用那什么map,code,在控制条输出值再调整,这个繁琐的过程直接没有了
别看上面四步说起来有个几十个字,操作起来真的就分分钟,执行肯定是秒秒种出结果的
另外要注意的是,有时候,去找那个导出器exports时,可能对webpack不熟悉,找到个其他的文件,然后这个文件里面就有很多个exports,搞得你都不知道怎么操作了,那说明你一定找错了,就比如这个站,如果你找到的是名为chunk的js的话,里面就有很多个exports。
webpack作为一个打包工具,一定有个入口,基本都在一个叫main的文件里,或者其他的index之类的,找到那个只有一个exports定义加return的就行了
结语
你觉得难吗?