网络爬虫反反爬小技巧(三)JS 逆向

上一节说到的神器 Pyppeteer 也是有不足的地方的,最大的劣势就是相比面向接口爬虫效率很低,就算是无头的 Chromium,那也会占用相当一部分内存。另外额外维护一个浏览器的启动、关闭也是一种负担。所以对于 Ajax 接口包含加密参数的问题,我们可以尝试去深挖其中的 JS 构造逻辑。这个过程中我们可能会遇到很多坑。

第一个坑:接口加密

一般来说会使用到各种加密和编码算法,如 Base64、Hex 编码,MD5、AES、DES、RSA 等加密。如果网站没有对 JS 代码做任何保护的话,我们可以很容易看到 JS 源码,从而复现加密逻辑。但往往目标网站会对 JS 代码进行压缩、混淆、加密等操作。

第二个坑:JS 代码压缩

目前主流的前端开发技术大多都会利用 Webpack 进行打包,Webpack 会对源代码进行编译和压缩,输出几个打包好的 JS 文件,其中我们可以看到输出的 JS 文件名带有一些不规则字符串,同时文件内容可能只有几行内容,变量名都是一些简单字母表示。这其中就包含 JS 压缩技术,比如一些公共的库输出成 bundle 文件,一些调用逻辑压缩和转义成几行代码。另外其中也包含了一些很基础的 JS 混淆技术,比如把变量名、方法名替换成一些简单字符,降低代码可读性。

第三个坑:JS 代码混淆

JS 混淆技术主要有以下几种:

1、变量混淆:将带有含意的变量名、方法名、常量名随机变为无意义的类乱码字符串,降低代码可读性,如转成单个字符或十六进制字符串。

2、字符串混淆:将字符串阵列化集中放置、并可进行 MD5 或 Base64 加密存储,使代码中不出现明文字符串,这样可以避免使用全局搜索字符串的方式定位到入口点。

3、属性加密:针对 JS 对象的属性进行加密转化,隐藏代码之间的调用关系。

4、控制流平坦化:打乱函数原有代码执行流程及函数调用关系,使代码逻变得混乱无序。

5、僵尸代码:随机在代码中插入无用的僵尸代码、僵尸函数,进一步使代码混乱。

6、调试保护:基于调试器特性,对当前运行环境进行检验,加入一些强制调试 debugger 语句,使其在调试模式下难以顺利执行 JavaScript 代码。

7、多态变异:使 JS 代码每次被调用时,将代码自身即立刻自动发生变异,变化为与之前完全不同的代码,即功能完全不变,只是代码形式变异,以此杜绝代码被动态分析调试。

8、锁定域名:使 JS 代码只能在指定域名下执行。

9、反格式化:如果对 JS 代码进行格式化,则无法执行,导致浏览器假死。

10、特殊编码:将 JS 完全编码为人不可读的代码,如表情符号、特殊表示内容等等。

在前端开发中,现在 JS 混淆主流的实现是 javascript-obfuscator 这个库,利用它我们可以非常方便地实现页面的混淆,它与 Webpack 结合起来,最终可以输出压缩和混淆后的 JS 代码,使得可读性大大降低,难以逆向。

第四个坑:JS 代码加密

不同于 JS 混淆技术,JS 加密技术可以说是对 JS 混淆技术防护的进一步升级,其基本思路是将一些核心逻辑使用诸如 C/C++ 语言来编写,并通过 JS 调用执行,从而起到二进制级别的防护作用。其加密的方式现在有 Emscripten 和 WebAssembly 等,其中后者越来越成为主流。

以上,我们就介绍了接口加密技术和 JS 的压缩、混淆和加密技术,知己知彼方能百战不殆,了解了原理,我们才能更好地去实现 JS 逆向。

这里简单介绍三种寻找入口的方式:

1、全局搜索标志字符串

一些关键的字符串通常会作为找寻 JS 混淆入口的依据,我们可以通过全局搜索的方式来查找,然后根据搜索到的结果大体观察是否是我们想找的入口。

2、设置 Ajax 断点

对于要搜索的字符串可能会被混淆成类似 Unicode、Base64、RC4 的一些编码形式,这样我们就没法轻松搜索到了。这里我们可以利用 XHR 断点,顾名思义,就是在发起 XHR 的时候进入断点调试模式,JS 会在发起 Ajax 请求的时候停住,这时候我们可以通过当前的调用栈的逻辑顺着找到入口。怎么设置呢?我们可以在 Sources 选项卡的右侧,XHR/fetch Breakpoints 处添加一个断点选项。

3、Hook 技术

它就是在程序运行的过程中,对其中的某个方法进行重写,在原有的方法前后加入我们自定义的代码。相当于在系统没有调用该函数之前,钩子程序就先捕获该消息,可以先得到控制权,这时钩子函数便可以加工处理(改变)该函数的执行行为。

你可能感兴趣的:(Spider,python,javascript,爬虫,反爬,Pyppeteer)