前言
好久没有做逆向案例分析了,最近都在看同行朋友写好的案例,感觉学到很多,算是取长补短了
不多bb,机缘巧合下,拿到个目标网站
分析
首先抓个包,就看到请求参数里带着这几个参数
主要就是_signature了,其他的参数都不重要得想必你一看就知道啥意思了。
行,开始分析_signature了
先,全局搜一下,很好只有一个结果:
点进去看到主要就这三个地方:
三个地方都打上断点:
继续滑动下拉,发现值已经有了:
鼠标放到变量上面,看到我们需要得_signature其实就是变量a了,而a由函数I(n,e)生成:
其中,n就是V.getUrl生成,e就是传进去的参数:
那取消刚才的断点,重新打上断点看看:
此时,可能你在调试的时候,有时候会出现滑块验证:
这个暂时不管,以后再系统的搞滑块哈
此时发现断上了:
跟进去,发现V.getUri进入到如下,感觉是在处理参数,不知道有没有我们要的sign
怎么确定有没有,放开断点往下走,如果出现了那就是了,如果没有出现,那多半就不是了,如下:
这个n的值明显没有sign,那就不是了
当然这个理论在这里行得通,但不绝对哈
好,接着看I,跟进去,发现如下,这里的e就是上面生成的n,t就是上面传进来的参数e,就是而且看到里面有sign相关的变量,90%是了
单步调试,一点一点跟着走看看:
找到关键点
发现上面都是些没有什么用的配置,就到了倒数第二行,貌似才有关键的东西,而且sign也在这一行里,先在这一行打个断点,然后继续走,一点放行,发现走到一个新的js里:
大概的看了一眼,应该是个加密算法,那是不是就是我们要的sign呢?不好说啊,直接点这个跳出去吧:
跳出去之后发现,变量o出现了一个很长的字段
拿着跟之前浏览器抓包看的_signature对比下长度,发现一致,那就是这个了,而实际的加密逻辑就是刚才进入的新的js文件alcrawler.js里
关键点找到了,那怎么把核心的加密逻辑扣出来呢?
我大概看了下,这里好像还不好单独把加密的逻辑抠出来,因为有很长的参数调用,而且我抠了下,不好扣,索性整个拿出来吧,结果发现整个也不多,就几百行,复制到本地吧
代码调试
放在本地,取名crawler,用node执行下看看:
发现报了个这个:
什么referrer,那我们搞爬虫的,再熟悉不过了,但是这个是在js里面啊,这就是涉及到补环境了,那么referrer属于哪个js对象里的呢,这个没法展开说了,我就直接说,referrer是document对象里的,js的全局对象有,window,doucument,navigator,global,location
行,这里补齐如下,地址给个主站的地址就行了:
继续执行,报错了:
但其实,懂js的朋友应该知道,其实window.document可以简写成document,这个就你们自己去研究为什么了,如下写,执行立马不报错了:
当然也可以把window也补一下:
就不会报错了:
那现在我们要把那个生成sign的逻辑拿出来用下,怎么用呢?回到上面这个关键的有sign字段的那一步:
1 2 |
|
这个懂点js的都不陌生,我们拆开来看:
先看最外层,最外层的括号,如果括号里没有值,那就给o一个空字符串
那根据上面的断点逻辑,肯定不会是空的,直接省略下,变成如下:
先把var o 删了:
再通过||符号拆下:
第一行,null肯定不会全等于(n=window.byted_acrawler)的,所以会走后面的逻辑,但是这一步,同时把window.byted_acrawler复制给了变量n
再看第二行,第二行是个三目运算,首先,0 ==== n肯定是不成立的,直接走后面的null=== (a = n.sgin),这个逻辑就跟第一行类似了,反正最后会把n.sign复制给变量a
再看第三行,这个跟第二行类似,同样的,会走到最后a.call(n,i)
不信可以看看这个下面:
先做简单的替换,本质的运算逻辑是没有区别的
意思就是,那么长一句,最后会直接执行:window.byted_acrawler.sign.call(n, i)
那么,这两个参数,n,i是啥,先看看n:
再看看i,i就是个url的路径,没有带参数的那种
ok,i变量好说,这个n变量就有点不好搞了,这样,直接在控制台看下需要啥参数:
这个报错就很有价值了,它只需要一个url就行了,根本不需要那个什么n变量,那就好说了
如下测试,发现不行,需要一个带有url属性的object对象
那行,整一个:
芜湖,出来了,行的,就是这么调用,放到本地掉就完了
结果一执行,完蛋,卧槽
报错的意思就是,这个对象没有sign属性,很奇怪啊,在控制台都可以用的,在node里不能用,那说明有检测环境的,把那个检测环境的部分改下试试,先把代码缩一下:
先看那个三目运算,复制到控制台执行看看:
实际就还是window,那就改成window:
卧槽,这里才看到是jsvmp啊,这他妈,大名鼎鼎啊,说实话我有点慌了,本篇博文到此结束?
不不不,还是要挣扎下的,先把它当作普通的函数看待,先看,上面主要的两段代码,第一段是定义,第二段是调用,最后的console打印是我自己加的
那行,那看看参数有没有问题:
定义的时候用的b,e,f
看看下面穿的参数是啥,好家伙,不看不知道,一看传了这么多的东西,用sublime 打开看到:
上面一大段全是b变量,后面的中括号里的值,最后会变成e和f变量,而这里面又有三目运算符
把三目运算符整理下,先看第一个:
那说明,这个三目运算符就是void 0了,把这相关的都替换成void 0,搜索看,只有一个,
替换之后再执行,貌似刚才那个sign属性解决了,但是又出现了新的错
这个一看还是补环境的问题了,把这个补了,href是location对象里的,补完又发现新的报错
到这一步的时候,因为报length的话,大概率是补环境除了问题,那么说明刚才的href没有补对,那我们直接再目标网站的控制台copy一下,
回车即可,一定要在目标网站的控制台里copy,copy完执行,至少当前的问题解决了,再搞新的问题
这个userAgent就再熟悉不过了,咋办呢?也直接copy吧,因为userAgent属于navigator,直接如下copy:
再次强调,目标网站控制台里执行
copy完放到代码里执行看看:
发现,卧槽,终于tmd没报错,而且有结果了
但是,这个长度好像不大对劲,短这么多,好像差点啥,到底差什么东西呢
仔细推敲,网上也查了相关的,有说补齐cookie的,我补齐之后执行的结果还是很短,所以,应该还有什么东西没有注意到的
在目标网站的控制台里执行,就是可以拿到很长的字段,这就很骚了
那我觉得应该还是环境的问题,应该有个我们忽视了的地方
先打印window看看:
location基本没有太大区别:
不一样的主要是window.document和window.navigator,以及window.localStorage,但是恰恰这三个对象是没法直接copy的:
因为你发现,粘贴出来的要嘛是undefined,要嘛是{}:
这他妈就很秀了,难道这就是jsvm的威力吗?
我另开一个浏览器标签,把刚才抠出来的代码放到控制台执行,然后测试看看:
首先,至少说明,补的基础环境没问题,就差一些特征值了
再看,目标控制台里的这个arguments,
新开的控制台的这个arguments的值:
所以这里就看出区别了,目标控制台里多了个这个:
但是就不知道是不是这里不同导致的原因了。
跟着断点接着走,新开控制台:
看这个c值
目标的控制台里的:
看这个c值:
差距也太大了,而且c就是window.document对象,也就是上面没法copy对象其一
而且,新开标签页,走到后面进入到了这里:
目标控制台,进入到了这里:
能走不一样的原因就是,这里的B[e]
目标控制台的B[e]是空的,所以,G穿的最后一个值是0,而新开控制台的B[e]有值,所以传的最后一个参数是1,也就导致上面走了不同的逻辑
那么这个B到底是啥:
我去,这他妈的,最后经过我的调试,发现,主要是穿的这个参数的不同:
导致取值不同,上面是目标控制台的,下面是新标签页控制台的:
但是这一个值的变化,不是我们能控制的,写死也是没用的,唉,这就是jsvmp的强大吗?唉,想想后怕了。
但是中途放弃不是我的作风,我就不信了,我开始在漫无目的的找特征,回到最底部调用部分看这个window对象,突然的看到localStorage部分,我激动了,这个是目标网站里的:
新标签的控制台,window部分,明显感觉有问题对吧,
但是,刚才我们分析的,就是那个this里的window对象不一样,那么我们尽量的去贴靠原网站的window里需要的值,我们给赋值下localstorage,用copy看看呢:
哎,发现这个倒是可以复制哈
把这段封装成一个自执行函数:
放到新标签的控制台里,然后放到控制台里执行,回车,再访问下验证是否成功了,发现可行的
好,现在再在控制台执行下sign:
把localStorage部分放进去之后,再次执行:
卧槽,说实话,有点小激动,至少这个长度看着很像了,就不知道能不能用了,在代码里看看呢?
直接复制刚才的sign生成好的字段,执行测试,卧槽,牛逼啊,数据结构终于有了
还没完哈,现在要搞一个在本地能够直接生成的,而不是每次生成需要去浏览器的控制台执行再复制出来的
当把那段自治性函数放到node环境里执行的时候:
很奇怪,提示的是没有setItem这个属性,这咋办呢?
尝试jsdom
理一下思路,目前就差一个localstorage的赋值了,但是上面的代码的setItem无法用,因为localstorage对象是window对象里的,那么我们直接用node伪造一个window吧,咋伪造呢?用jsdom,安装nodejs就不说了,网上一堆教程
在本地搞一个node项目,npm init命令初始化后,然后执行命令npm install jsdom安装jsdom,具体过程也省略了,网上教程同样一堆
现在创建一个js文件,把window对象引入,这里注意一下,因为我们要用localstorage,new JSDOM的时候必须要给个主域名,不然没法用localstorage
测试下现在setItem成功没有:
ok了,现在把刚才抠出来的代码整合到一起,结果出现了这个,卧槽,心累啊
说明这段代码还验证了其他很多东西导致这个sign属性没有正常赋值,换路子吧
本地html文件生成
把抠出来的代码放到一个html文件里,同时要注意的,url里的时间戳,必须要跟sign生成时传进去的url里的时间戳保持一致,不然用不了
ok,用pycharm自带的轻量服务器执行查看:
点击那个谷歌浏览器图标,自动打开并展示如下页面:
拿到这两个值去请求测试,哭了,这他妈终于有数据了
那会过头想想,这个没法运用到实际啊,这个第一,还是用了浏览器自带的window对象,第二,这个服务端是pycharm,还不好控制,就算把这一部换成flask,用requests去请求这个接口,拿结果?也不行啊,为啥,因为请求拿到的是源码,这里的时间戳和sign是js生成的
要走这条路的话,只有用浏览器驱动,puppeter或者selenium了,那这里就会有人说了,这都上浏览器驱动了,那还抠啥代码啊,直接一开始就用浏览器驱动了呗,是的,所以这套路也不是我喜欢的
怎么办
构造localStorage对象
上面试了两个路子都不行,那究其原因就还是那个setItem没法用,没法用的原因是我们构造的window对象里的localStorage不是正确的对象,这里构造一个出来,行不行呢?理论上是可以,试下:
1 2 3 4 5 6 7 8 9 10 11 |
|
把这段代码放到最开始抠出来的代码里,并在执行setItem前面,代码如下:
执行看看,激动万分啊,这个长度,看着就跟目标网站出来的sign长度一致了
放到程序里执行测试:
执行,哇的一声就哭出来了,ok
标签:执行,这个,Python,sign,扣出,window,控制台,js From: https://blog.csdn.net/2401_86078658/article/details/140850069