一次逆向网页内容加密
一次逆向网页内容加密
以往爬取网页内容复杂点的,一般就是处理下页面内容动态载入,动态载入的内容可能会要求复杂奇怪的参数,或者找到这个动态载入的HTTP接口在哪里麻烦点。但是这次要爬去的网页不同。
类似如下内容:
1 | <td class="omission" width="20%"> |
最终希望得到的内容其实是江苏先思达生物科技有限公司,但是得到的网页确实乱序后的字符串,并且每次刷新得到的乱序还不一样,试过几次也看不出规律。
按照以往的思路,猜测肯定是某个js文件中包含了还原算法,我的目标就是找出这个算法,在爬虫程序中实现这个算法,以还原出可读的字符串。
js中要完成这样的事,首先得找到网页元素,包括:根据外层span name="record:shenqingrxm";根据再外层的table;根据内层span class='nlkfqirnlfjerldfgzxcyiuro'。以前一直想要个工具,可以在某网页载入的所有js文件中搜索特定字符串,从而帮助逆向,但是一直没有这个工具。所以这次也只有人肉看每个js。根据js的名字猜测这个逻辑会放在哪里。
看了几个可能的js文件,在文件中都没有搜索出认为可能的字符串。于是又人肉搜索其他不太可能的js文件,均未果。此时陷入死胡同。
网页文件末尾会有个超长id的span元素,类似:
1 | <span style="display: none" id="65356430316133353f6d6c3c38683b3b717222202422247120782d787a2a292a0c184011154414101c4d4c1e1f191d4c06535152560c57045e015f5d045f0e0f236d2670202123257c7d7b2d757e7a2c6935303560626060396f3c686f38383a02024e5055040402510c5c5b5c095d5b4743404a474746121a1d4c1f1f1f1a4db5e0b7afb3 |
这个字符串不像base64加密,看这个网页带了md5的js,怀疑跟md5有关,但md5不应该用来加密字符内容,js文件中也未看到可能的API。
后来发现乱序的字符串中有些字符是不显示的,通过这个css控制:
1 | nlkfqirnlfjerldfgzxcyiuro { |
网页载入经过js处理后,显示出来的字符看起来是相同的css class : nlkfqirnlfjer1dfgzxcyiuro,开始觉得奇怪,研究了下这个的差异。折腾了好久发现被人戏弄了:nlkfqirnlfjer1dfgzxcyiuro与nlkfqirnlfjerldfgzxcyiuro,前一个是r1d后一个是rld,分别是数字1和字母L!
原始网页中所有字符的css class都是不显示的,所以可以推测js中经过一定算法将需要显示的字符改了css class。但是此刻还是没有思路。
后来尝试了chrome的DOM breakpoint,可以在DOM元素被改变时断点,但是用起来不是特别好用,没有带来任何帮助。
绝望之际把整个网页另存下来,另存下来的网页是经过js处理后的,手工将css改回原始内容,本地载入网页发现还是可以正常显示,证明处理逻辑真的还在js文件中。然后我逐个删除每一个js文件,还是想找出具体是哪个js文件包含了这个还原算法。
然后发现竟然是jquery-1.7.2.min.js。但我想这不能说明问题,因为作者肯定是通过jQuery来获取元素的,删除jQuery作者的代码不能工作,当然就显示不出来。这时候开始清理html中的js代码,发现所有js代码都被清除完后,网页内容依然可以还原,所以断定还原算法就在jQuery.js中。然而这个文件是min版本的,用sublime text的html pretty插件重新格式化方便阅读。
但是此刻发现在这个文件中依然搜索不到可能的字符串,例如前面提到的找元素的一些线索,如span css,如span name等等。此时重新通过chrome的DOM断点来获取调用堆栈。这次直接断css class会被改变的span元素,竟然发现可行。此时无非是断点,看效果,继续下更精确的断点,最后发现源头:
1 | b(function() { |
首先看到的是"s" + "p" + "a" + "n",这不就是span!看前面几行代码很快就明白这是在取网页的最后一个span元素,也就是那个包含超长id属性的span元素。此时需要提下,之前也是对这个页尾span元素做过实验,发现必须是span元素且为最后一个元素才能正确还原网页内容,可以推断这个span是多么关键的一个线索。感兴趣的可以把这个网页的jQuery-1.7.2.min.js还原后查看mix函数实现。
翻译过来还原函数非常简单,写一个java版本:
1 | public static String parseSipoIds(String enStr) { |
即这个span元素就是需要显示出来的span元素id集合,以逗号分隔。
作者把还原算法写到jQuery.js里,也真是够够的了😓。