记一次爬虫-js逆向解析学习

NightTeam微信公众号上看见大佬一篇文章听说你碰到这种反爬就歇菜了?手把手教你秒杀它!
大佬具体扣代码没写,很是受伤,于是自己摸索了大半天,捋顺了大部分逻辑,写出来分享一下
ps:发送消息「隐式Style-CSS」到大佬微信公众号「NightTeam」即可获取样例地址~
前面分析,大神写的非常详细,具体看大神写的就好
记一次爬虫-js逆向解析学习_第1张图片
记一次爬虫-js逆向解析学习_第2张图片

  • 观察与分析977行和1133行代码
    977处代码定义了变量_0xa12e1133处代码是一段for循环,经过观察1133处代码较为复杂,有许多未知变量:words,_0xea12, document,打上断点调试一下
  • 调试结果
    首先for函数主体for (var i = 0x0; i < words[_0xea12('0x18')]; i++) {
    iwords[_0xea12('0x18')]明显为数字,用来控制函数循环次数
    把鼠标移动到words上
    记一次爬虫-js逆向解析学习_第3张图片
    可以看到words被替换的单词数组记一次爬虫-js逆向解析学习_第4张图片跳转之后的函数
    记一次爬虫-js逆向解析学习_第5张图片
    可以看到 var _0xea12 = function (_0x56430f, _0x7f6841)
    传递了2个参数_0x56430f, _0x7f6841 又定义了一个变量 _0x4f7a0f接受 _0xa12e函数_0x56430f处理的结果
    var _0x4f7a0f = _0xa12e[_0x56430f]最后返回 _0x4f7a0f
    来看看_0xa12e
    记一次爬虫-js逆向解析学习_第6张图片可看到上面代码定义了_0xa12e,经过函数变换之后结果如图所示。为长度48的数组
  • 回过头来看1133行代码
    一点一点的利用Console来进行测试,首先分析words[_0xea12('0x18')]
    记一次爬虫-js逆向解析学习_第7张图片
    可以看到0x18结果为24,之后_0xea12函数(返回结果为数组)取下标为24的元素,结果为length,之后words数组调用length方法,取得words数组的长度结果为24
    所以for函数变为了for (var i = 0x0; i < 24; i++) {
    同理,替换之后的函数变为
for (var i = 0x0; i <24; i++) {
     
            try {
     
                document["styleSheets"][0x0]["addRule"]('.context_kw' + i + "::before", 'content:\x20\x22' + words[i] + '\x22');
            } catch (_0x527f83) {
     
                document['styleSheets'][0x0]['insertRule'](".context_kw" + i + "::before{content: "" + words[i] + '\x22}', document["styleSheets"][0x0]["cssRules"]["length"]);
            }
        }

此处CSSStyleSheet.insertRule()方法用来给当前样式表插入新的样式规则. 语法stylesheet.insertRule(rule, index)
参数
rule: 一个包含了将要插入的规则的 DOMString。规则字符串必须包含的内容取决于它的类型
For rule-sets, both a selector and a style declaration.
For at-rules, both an at-identifier and the rule content.

index 可选
小于或等于stylesheet.cssrules.length的正整数,表示新插入的规则在cssstylesheet.cssrules中的位置。默认值为0。(在旧的实现中,这是必需的。有关详细信息,请参见浏览器兼容性。)

ps:此处我没有搞懂catch (_0x527f83) 是怎么触发的。。知道的请务必留言告诉我

  • 了解了上方for函数体逻辑之后,再来捋一捋words参数
    再上面说到words是被替换的字的数组,那么它是如何实现替换的呢?我们来研究一下
    记一次爬虫-js逆向解析学习_第8张图片
    经过页内搜索,成功找到定义变量words的代码,如图所示。
    经过同上思路的调试,var words = new Array(secWords[_0xea12('0x18')]);
    _0xea12('0x18')lenghtsecWords长度24的数组

所以此处代码意思为定义一个名为words 长度为24的 空数组

  • 空数组,到后面为替换字的数组,中间肯定有赋值过程,查看两者之间的代码段
    找到如下代码:
    记一次爬虫-js逆向解析学习_第9张图片
    此处有赋值语句,仔细检查一番

  • 调试代码
    条件语句中,secWords[_0xea12('0x18')]调试结果为24
    函数体中:
    var _0x5420ee = '3|5|2|4|0|1'[_0xea12('0x17')]('|')调试结果为["3", "5", "2", "4", "0", "1"]
    _0x9ff9d9 = 0x0 --> _0x9ff9d9 = 0
    while (!![]) { --> while (true) { 显然是死循环

    接下来看循环内部:
    内部是一个switch case 语句,case值为0,1,2,3,4,5。而每一句都有结束时都有一个continue关键字

    switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支
    switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断
    break 语句用于跳出循环。
    continue 用于跳过循环中的一个迭代。

    switch (_0x5420ee[_0x9ff9d9++]) { ,上方定义了 _0x9ff9d9 = 0,而后面 带有++ 自增 显然是循环 将值赋给_0x5420ee( 数组 --> [“3”, “5”, “2”, “4”, “0”, “1”]),获得其对应下标的值。
    综上所诉,我们知道了循环处理顺序:3,5,2,4,0,1

  • 逐步分析case语句
    case '3':var _0x423190 = secWords[i];第一次循环时i = 0,此时 _0x423190 = secWords[i] = 65291

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;

先从return看起,分析得出_0x3e40d1[_0xea12('0x28')] --> mPDrG;
_0x3e40d1[_0xea12('0x29')] --> DWwdv,所以 此处返回的是自身定义的函数处理结果。将变量带入,来看看

case '5':
     var _0x3e8e1e = function (_0xd024e1) {
     
     var _0x3e40d1 = {
     
         'mPDrG': function _0x411e6f(_0xd024e1, 0x2) {
     
          return _0xd024e1 % 0x2;
           },
           'DWwdv': function _0x1e0293(_0xd024e1, 0x2) {
     
           return _0xd024e1 - 0x2;
    }
          };
      return mPDrG(_0xd024e1, 0x2) ? DWwdv(_0xd024e1, 0x2) : _0xd024e1 - 0x4;
      };
      continue;

结果清晰明了,case5 是将传入的参数_0xd024e1 进行处理从而得出结果。此处暂无参数 ,继续看循环case2:

   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')));
       };

依旧先从return看起,_0x1532b6[_0xea12('0x26')]结果为 ifLSL,由于不懂!(typeof document === _0xea12('0x27'))。利用console进行测试。得到结果为true。true为1 所以处理函数,将其变换为

   case '2':
        var _0x5796d9 = function (_0x490c80) {
     
        var _0x1532b6 = {
     
            'ifLSL': function _0x256992(_0x490c80, 0x3 * + 1) {
     
             return _0x490c80 +  0x3 * + 1;
                    }
                };
        return ifLSL(_0x490c80, 0x3 * + 1);
       };

逻辑与case5 类型得到一个关于_0x490c80参数的函数,继续看循环4:

case '4':
    _0x423190 = _0x3e8e1e(_0x423190);

经过case3 我们知道_0x423190 = secWords[i] = 65291,case5中我们知道了_0x3e8e1e函数的处理数字的方式,运算过程如下:

// 将_0x423190代入函数
return('mPDrG')(65291, 0x2) ?_0x3e40d1('DWwdv')(65291, 0x2) : 65291 - 0x4;
return 165289 : 65287;
// console 调试 1 ?65289 : 65287

所以得到结果_0x423190 = 65289。继续循环,看case0:

 case '0':
        _0x423190 = _0x5796d9(_0x423190);

将case4结果_0x423190 = 65289 代入,console调试得到结果_0x423190 = 65292。最后一个case1:

case '1':
      words[i] = String[_0xea12('0x25')](_0x423190);

显而易见,此处是给word(24位空数组)赋值,此时第一次while循环 i = 0,

case '1':
      words[0] = String[_0xea12('0x25')](65292);

记一次爬虫-js逆向解析学习_第10张图片
结果刚好对应!!!!

  • 至此 js 逻辑基本走通,剩下的23 字处理基本一致。
  • 下一步是替换js,改造成python爬虫。咕咕咕

最后,写作不易,点个关注,点个赞呗5555

你可能感兴趣的:(技术,js逆向解析,爬虫,python,JS,爬虫)