美文网首页大数据 爬虫Python AI SqlIT@程序员猿媛
解密红薯中文网手机站点升级版CSS反爬

解密红薯中文网手机站点升级版CSS反爬

作者: Jkanon | 来源:发表于2019-07-19 23:32 被阅读104次

今日有网友抛出一个小说网站,说是爬虫遇到了点障碍,兴趣使然我也去凑了个热闹,结果发现这个网站的反爬也是我平生第一次所见,在此记录下详细的破解过程。

问题

站点链接:传送门

  • 我们发现最终呈现在浏览器上的页面内容是有些差异,比如页面上的“地皇元年”,而我们在html返回的数据中只能看到“皇元年”,说到这里我们也很容易想到这可能是一个CSS反爬的页面。
  • 打开Elements页签查看源代码,果不其然,事实上确实是通过::before伪元素来实现的CSS渲染,这也是一种常见的反爬手段。
  • 但接下来就发现了事情没有那么简单,那就是竟然无法找到这个伪元素样式定义的源头,通常情况下,我们可以从控制面板看出这些样式是哪里定义的,可能是来自外联CSS,也可能是内联style。然而此处我们却碰壁了,控制面板上只有<style>寥寥数字,点击style跳转到了一个空的style链接,同时我们发现页面返回的源码并不包含此style节点。
    无法找到样式源头
    空的style节点

思路分析

  • 猜想查找
    在这种情况下我虽然不太清楚怎么实现的,但是第一感觉告诉我这和JS有关,我试着全局搜索如context_kw(class属性前缀), , ::(伪元素前缀),最后终于在页面内的一处JS代码出发现了伪元素相关的字符。
    猜想查找的过程
  • JS解析
    • JS格式化
      为了更好地对代码进行分析,网上找个在线的JS格式化工具进行格式化。


      格式化后的代码一览
    • 粗略解读JS代码
      粗略看过代码之后,我们看到了几个关键词:crypto, decrypted, secWords, words, createElement, text/css
      很快,我们可以猜想这段JS代码必定是与解密相关的,并且操纵了DOM树(这边猜想就是上面那个空的style节点)。
      我们发现,这段代码没有闭包,这意味这段代码中的变量都是全局变量,我们直接在console查看变量的数据,并且可以将其中一些关键代码在console中重新执查看。
      从下图中我们就可看出words就是伪元素中的content

    • 细读JS代码
      1.第一次解密
      _0xa12e数组下标为0xc(即12)的元素,用AES解密成字符串之后,用,分割成数组,最终得到secWords

["65291", " 30339", " 12289", " 21015", " 20153", " 19967", " 20181", " 26160", " 19982", " 22311", " 26378", " 20101", " 30527", " 8222", " 8219", " 31167", " 22824", " 19977", " 36948", " 27461", " 20009", " 21518", " 19980", " 22319"]

    2.第二次解密
以下代码就是将secWords解密为最终的文字并保存到words数组中。
总结起来就是对于secWords的每个元素进行以下操作:
假设输入n,则输出

伪代码
var t = (n+3) % 2 === 0 ? (n+3)-2 : (n+3)-4       ==>    n % 2 === 0 ? n - 1 : n + 1
String.fromCharCode(t)
输出示例
secWords[0] => 65291 => 65292(65291+1) => ','(String.fromCharCode('65292'));
secWords[1] => 30339 => 30340(30339+1) => '的'(String.fromCharCode('30340'));
源代码
for (var i = 0x0; i < secWords[_0xea12('0x18')]; i++) {
    var _0x5420ee = '3|5|2|4|0|1' [_0xea12('0x17')]('|'),
    _0x9ff9d9 = 0x0;
    while ( !! []) {
        switch (_0x5420ee[_0x9ff9d9++]) {
        case '0':
            _0x423190 = _0x5796d9(_0x423190);
            continue;
        case '1':
            words[i] = String[_0xea12('0x25')](_0x423190);
            continue;
        case '2':
            var _0x5796d9 = function(_0x490c80) {
                var _0x1532b6 = {
                    'ifLSL': function _0x256992(_0x118bb, _0x36aa09) {
                        return _0x118bb + _0x36aa09;
                    }
                };
                return _0x1532b6[_0xea12('0x26')](_0x490c80, 0x3 * +!(typeof document === _0xea12('0x27')));
            };
            continue;
        case '3':
            var _0x423190 = secWords[i];
            continue;
        case '4':
            _0x423190 = _0x3e8e1e(_0x423190);
            continue;
        case '5':
            var _0x3e8e1e = function(_0xd024e1) {
                var _0x3e40d1 = {
                    'mPDrG': function _0x411e6f(_0xa8939, _0x278c20) {
                        return _0xa8939 % _0x278c20;
                    },
                    'DWwdv': function _0x1e0293(_0x5b15eb, _0x443876) {
                        return _0x5b15eb - _0x443876;
                    }
                };
                return _0x3e40d1[_0xea12('0x28')](_0xd024e1, 0x2) ? _0x3e40d1[_0xea12('0x29')](_0xd024e1, 0x2) : _0xd024e1 - 0x4;
            };
            continue;
        }
        break;
    }
}

    3.设置style
这一步就是样式设置的关键所在了,将根据上一步得到的words数组添加到styleSheets中(就是这一步导致了控制板面板上无法看到样式定义的源头

源代码
for (var i = 0x0; i < words[_0xea12('0x18')]; i++) {
    try {
        //document.styleSheets[0].addRule('.context_kw'+i + '::before',  'content:\x20\x22' + words[i] + '\x22')
        document[_0xea12('0x2a')][0x0][_0xea12('0x2b')]('.context_kw' + i + _0xea12('0x2c'), 'content:\x20\x22' + words[i] + '\x22');
    } catch(_0x527f83) {
        document['styleSheets'][0x0]['insertRule'](_0xea12('0x2d') + i + _0xea12('0x2e') + words[i] + '\x22}', document[_0xea12('0x2a')][0x0][_0xea12('0x2f')][_0xea12('0x18')]);
    }
}

爬虫思路

换了几个页面之后,我发现这个words列表并不是固定不变的,因此我们得寻找到一种方法得到words数组。

  • 遍历<Script>节点,获取其中包含CryptoJS文本的节点
  • 截取var words =之前的代码,用JS引擎执行得到secWords
  • 用相应的爬虫语言实现secWordswords的转变(上述思路分析已详细讲解)
  • 之后就变成了普通的css伪元素反爬的处理(这一部分不是这篇文章的重点,不再展开)

PC站点会更加复杂点,需要先通过ajax加载文章内容,然后解密文章文本,余下步骤与手机版一致。

相关文章

网友评论

    本文标题:解密红薯中文网手机站点升级版CSS反爬

    本文链接:https://www.haomeiwen.com/subject/ttfelctx.html