JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

03-11 1958阅读

目录:

  • 每篇前言:
  • 引子——本篇目的
  • 1、 代码混淆和还原
    • (1)单独替换:
    • (2)整个js文件替换:
    • 2、算法入口分析
    • 3、 深入分析
        • (0)整体分析:
        • (1)_0x4dd553:
        • (2)_0x15c356:
        • (3)_0x4fb8ac:
        • (4)_0x34877a:
        • (5)_0x5ad2bb:
        • (6)_0xc21476:
        • (7)_0x34c54c:
        • (8)至此,结束:
        • 4、Python还原算法
        • 5、整体测试

          每篇前言:

          • 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者

          • 🔥🔥本文已收录于爬虫进阶+实战系列教程专栏:《爬虫进阶+实战系列教程》
          • 🔥🔥热门专栏推荐:《Python全栈系列教程》、《爬虫从入门到精通系列教程》、《爬虫进阶+实战系列教程》、《Scrapy框架从入门到实战》、《Flask框架从入门到实战》、《Django框架从入门到实战》、《Tornado框架从入门到实战》、《前端系列教程》。
          • 📝​📝本专栏面向广大程序猿,为的是大家都做到Python全栈技术从入门到精通,穿插有很多实战优化点。
          • 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
          • 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!
            JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

            引子——本篇目的

            在中篇其实已经通过补浏览器环境的方式破解出了bella参数,但是如果补浏览器环境不行的时候该怎么办呢?

            这就得一点点扣js了!

            所以,本篇文章来扣一波!

            逆向分析出bella参数的加密算法,全部基于Python来实现!!!

            1、 代码混淆和还原

            分析这个js文件,有很多形如_0x5a69('0x0'),_0x5a69('0x1')这样的代码,其实这些最终得到的就是一个个对应的字符串。

            很入门级的代码混淆,这时候要做的就是尝试解混淆,将这个js文件中这样的代码替换为对应的字符串,这样看着就会直观了!

            JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

            上述红框部分就是代码混淆的实现逻辑;而下述整个try部分就是整个加密逻辑。

            【很明显,这些最终的字符串,即上图红框中那个大数组中的值,都经过base64加密~】

            (1)单独替换:

            解这种混淆也非常简单,我们直接执行对应的函数,如_0x5a69('0x0')就可以得到其对应的字符串:

            JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

            JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

            pyexecjs执行:

            JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

            (2)整个js文件替换:

            只需要处理整个try部分代码(放到js3.js文件中)即可~

            import re
            import execjs
            with open('js2.js', 'r') as f:
                JS = execjs.compile(f.read())
                res = JS.call("_0x5a69", "0x0")
                print(res)
            with open("js3.js", 'r', encoding='utf-8') as f1, open("js4.js", 'w', encoding='utf-8') as f2:
                for line in f1:
                    match_list = re.findall(r"_0x5a69\(.*?\)", line)
                    if not match_list:
                        f2.write(line)
                        continue
                    for mt_str in match_list:
                        try:
                            # arg = str(re.findall(r"\('(.*?)'\)", mt_str)[0])
                            arg = mt_str[9: -2]
                            line = line.replace(mt_str, f'"{JS.call("_0x5a69", arg)}"')
                        except Exception as e:
                            pass
                    f2.write(line)
                    print(line.strip())
            

            上述代码try的作用:

            • 这个js代码这么多,上述简单的替换逻辑肯定会有报错的时候,但是报错又没事,何必一个个扣报错,然后完善逻辑呢?

              等下面具体分析这部分js代码的时候,如果分析到了未替换成功的代码块,手动单独替换下不更方便吗?

              2、算法入口分析

              直接分析处理后的js文件即可~

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              分析,形参_0x29235d接收的是slideToken:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              但是上一个调用栈其实是传过来了两个参数:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              这就是JavaScript的一个神奇之出,当传给js函数的参数多于js函数的形参时并不会报错,而且在函数内部可以通过arguments加索引的方式取得对应的参数:

              var _0x5d0961 = arguments["length"] > 0x1 && arguments[0x1] !== undefined ? arguments[0x1] : '';
              

              所以上述这个三元运算就会赋值{v: 2}给_0x5d0961。

              继续分析:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              执行try的时候,第一句delete删除参数_0x29235d中的Bella,第二句_0x398212(_0x29235d, _0x5d0961)就是生成Bella的函数;

              如果捕获到异常,就直接返回_0x2e61cb,而这是个固定值,我直接将Bella写死为这个值,也是没问题的!

              【为啥会有这种奇怪的代码,直接写死就可以,这不就是个漏洞吗?

              这是因为核心加密逻辑可能需要读取各种浏览器参数,而浏览器千千万,有些浏览器也许不适配,那么就会报错,但是不能影响到用户使用,所以就有了这个try】

              下面深入剖析Bella的加密逻辑:

              3、 深入分析

              (0)整体分析:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              分析都在注释:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              (1)_0x4dd553:

              var _0x4dd553 = _0x318499(_0x481ca8);
              

              入参是:{slideToken: "80ed997a295a75f57e6d8cbe88d77a8b"}

              结果是:

              {
                  "bParam": "80ed997a295a75f57e6d8cbe88d77a8b",
                  "keyArray": [
                      "slideToken"
                  ]
              }
              

              (2)_0x15c356:

              var _0x15c356 = (0x0, _0x5b06ff["default"])();
              解读:
              var _0x15c356 = _0x5b06ff["default"]();
              

              对应js函数:

              function _0x9beb5a() {
                          var _0x2bb251 = document[_0x5a69('0xf9')](_0x5a69('0xfa'));
                          var _0x4ba4c2 = _0x2bb251 && _0x2bb251[0x0] && _0x2bb251[0x0][_0x5a69('0xfb')];
                          var _0x5a5787 = document['getElementsByName'](_0x5a69('0xfc'));
                          var _0x4030ec = _0x5a5787 && _0x5a5787[0x0] && _0x5a5787[0x0][_0x5a69('0xfb')];
                          var _0x5a2ba8 = document[_0x5a69('0xfd')];
                          return [{
                              'key': _0x5a69('0xfe'),
                              'value': document['referrer'][_0x5a69('0xb7')]('?')[0x0][_0x5a69('0xd4')](/^http(s)?:\/\//, '')[_0x5a69('0xff')](0x0, 0x14) || ''
                          }, {
                              'key': _0x5a69('0x100'),
                              'value': _0x89ccfe()
                          }, {
                              'key': _0x5a69('0x101'),
                              'value': window['shirley'] || _0xd6c5e7[_0x5a69('0x8a')]['string']
                          }, {
                              'key': _0x5a69('0xfd'),
                              'value': _0x5a2ba8 && _0x5a2ba8['slice'](-0xa) || _0xd6c5e7[_0x5a69('0x8a')][_0x5a69('0xcb')]
                          }, {
                              'key': _0x5a69('0xfa'),
                              'value': _0x4ba4c2 && _0x4ba4c2[_0x5a69('0x1f')](-0xa) || _0xd6c5e7[_0x5a69('0x8a')]['string']
                          }, {
                              'key': _0x5a69('0xfc'),
                              'value': _0x4030ec && _0x4030ec[_0x5a69('0xff')](0x0, 0x14) || _0xd6c5e7['default'][_0x5a69('0xcb')]
                          }, {
                              'key': _0x5a69('0x102'),
                              'value': window[_0x5a69('0xd0')][_0x5a69('0x102')][_0x5a69('0xd4')](/^http(s)?:\/\//, '')[_0x5a69('0xff')](0x0, 0x14) || _0xd6c5e7[_0x5a69('0x8a')][_0x5a69('0xcb')]
                          }, {
                              'key': _0x5a69('0x103'),
                              'value': _0x1916ab() || _0xd6c5e7[_0x5a69('0x8a')][_0x5a69('0xcb')]
                          }];
                      }
              

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              分析piccolo:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              生成_0x113a55中随机16个字符拼接而成的字符串~

              此参数结果:

              [
                  {
                      "key": "referer",
                      "value": ""
                  },
                  {
                      "key": "piccolo",
                      "value": "5879##420347A09BF3F723##1708962151096"
                  },
                  {
                      "key": "shirley",
                      "value": "unknown"
                  },
                  {
                      "key": "title",
                      "value": "unknown"
                  },
                  {
                      "key": "keywords",
                      "value": "unknown"
                  },
                  {
                      "key": "description",
                      "value": "unknown"
                  },
                  {
                      "key": "host",
                      "value": "user.qunar.com"
                  },
                  {
                      "key": "scriptSrc",
                      "value": [
                          "qimgs.qunarzz.co",
                          "q.qunarzz.com/ho"
                      ]
                  }
              ]
              

              (3)_0x4fb8ac:

              此参数结果:

              {
                  "referer": "",
                  "piccolo": "5879##420347A09BF3F723##1708962151096",
                  "shirley": "unknown",
                  "title": "unknown",
                  "keywords": "unknown",
                  "description": "unknown",
                  "host": "user.qunar.com",
                  "scriptSrc": [
                      "qimgs.qunarzz.co",
                      "q.qunarzz.com/ho"
                  ]
              }
              

              (4)_0x34877a:

              var _0x34877a = (0x0, _0xd98ca5["default"])();
              

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              生成_0x24b4d9中随机21个字符拼接而成的字符串~

              此参数结果:

              dWre6Dts7TLT1O2GkSeTZ
              

              (5)_0x5ad2bb:

              var _0x5ad2bb = _0x4dd553["bParam"] + _0x34877a + JSON["stringify"](_0x4dd553['keyArray']);
              

              唯一注意的就是JSON["stringify"](_0x4dd553['keyArray'])的值是["slideToken"]。

              此参数结果:

              3d8b8860db2bf9a6aef7f872979113dedWre6Dts7TLT1O2GkSeTZ["slideToken"]
              

              (6)_0xc21476:

              var _0xc21476 = _0x5625ac['default']["signature"](_0x5ad2bb);
              

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              很明显是将入参_0x5ad2bb使用sha1加密,最终将结果转换为十六进制字符串。

              加密秘钥16进制表示为:

              JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

              Python实现:

              import binascii
              import hmac
              from hashlib import sha1
              key_str = '68386673614b337771652b696f4d7673'
              key = binascii.a2b_hex(key_str)
              data = 'b363b3f511bf0e3e556c29cb56dcf4c9hLHNl1SVxE8UR2ONt1-N9["slideToken"]'
              hmac_code = hmac.new(key, data.encode('utf-8'), sha1)
              res = hmac_code.hexdigest()
              print(res)
              

              此参数结果:

              df95bd703794a4cc96e611da8a53b87f2aadcb40
              

              (7)_0x34c54c:

              var _0x34c54c = (0x0, _0x38cd63["default"])(JSON["stringify"](_0x4fb8ac), _0x3d0fe0["default"]);
              等价于:
              var _0x34c54c = _0x38cd63["default"](JSON["stringify"](_0x4fb8ac), _0x3d0fe0["default"])
              
              • 函数第一个参数:

                将上述得到的_0x4fb8ac序列化;

              • 函数第二个参数:

                多次测试为固定值:

                [
                    "B6F1YrNm+OA=sw",
                    "n8xbeLlzQ",
                    "p5M02SUHt/dog",
                    "cyfj-9kPKu",
                    "EX7VWaqJi",
                    "3CIGDRhTv4"
                ]
                

                分析此函数:

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                看看_0x21da9c函数:

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                内部又调用_0x2d06ba函数,先来看看第一个参数:

                _0x1414cd["charCodeAt"]()['toString'](0x2)
                

                获得传进来的参数的unicode编码,toString后得到对应二进制字符串。

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                多次调试可发现_0x2d06ba函数的作用就是对传进来的第一个参数左边补0达到八位。

                继续看_0x26cf34函数:

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                上述使用js列表的some方法,会对列表中的每个值执行给定函数,但凡有一个返回True则整体为True。

                window["location"]["href"]
                获取浏览器当前url。
                再.include("x")就是判断浏览器当前url中是否含有x。
                

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                (8)至此,结束:

                拓展:js字符串和数组拼接知识点~

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                在JavaScript中,当你使用 + 运算符连接一个字符串和一个数组时,数组会被转换为字符串,并与原始字符串连接。这个过程被称为字符串拼接。

                在上图中,"GuHanZhe" 是一个字符串,["Cool"] 是包含一个字符串元素的数组。当它们相加时,JavaScript会将数组转换为字符串,然后进行字符串拼接。这导致了结果 'GuHanZheCool'。

                4、Python还原算法

                import binascii
                import hmac
                import json
                import random
                import string
                import time
                from hashlib import sha1
                from urllib.parse import quote_plus
                def hmac_sha1(data_string):
                    key_str = "68386673614b337771652b696f4d7673"
                    key = binascii.a2b_hex(key_str)
                    # data_string = 'b363b3f511bf0e3e556c29cb56dcf4c9hLHNl1SVxE8UR2ONt1-N9["slideToken"]'
                    hmac_code = hmac.new(key, data_string.encode('utf-8'), sha1)
                    return hmac_code.hexdigest()
                def _0x26cf34(_0x4800e6, _0x572efb):
                    _0x5ee954 = ['qunar', 'tujia']
                    _0x403118 = "B6F1YrNm+OA=sw"
                    _0x501116 = "n8xbeLlzQ"
                    _0x3b5454 = "p5M02SUHt/dog"
                    _0x251b31 = "cyfj-9kPKu"
                    _0x222d7d = "EX7VWaqJi"
                    _0x47c310 = "3CIGDRhTv4"
                    _0x3af887 = "".join(_0x572efb) + (_0x403118 + _0x501116 + _0x3b5454 + _0x251b31 + _0x222d7d + _0x47c310);
                    _0x3af887 = list(_0x403118 + _0x501116 + _0x3b5454 + _0x251b31 + _0x222d7d + _0x47c310)
                    _0x4800e6 = quote_plus(_0x4800e6)
                    while len(_0x4800e6) % 0x3 != 0x0:
                        _0x4800e6 += '\x20'
                    _0x933810 = [format(ord(i), "0>8b") for i in _0x4800e6]
                    _0x2e4d85 = []
                    for i in range(0, len(_0x933810), 3):
                        end_index = min(i + 3, len(_0x933810))
                        group = _0x933810[i: end_index]
                        _0x2e4d85.append(group)
                    _0x2a779b = ''
                    for _0x28ee6c in _0x2e4d85:
                        _0x572061 = "".join(_0x28ee6c)
                        _0x351bb8 = []
                        for j in range(0, len(_0x572061), 6):
                            end_idx = min(j + 6, len(_0x572061))
                            _0x351bb8.append(_0x572061[j: end_idx])
                        new_0x351bb8 = []
                        for _0x2a9721 in _0x351bb8:
                            _0x2a9721 = "".join(["0" if char == "1" else "1" for char in _0x2a9721])
                            idx = int(_0x2a9721, base=2)
                            part = _0x3af887[idx]
                            new_0x351bb8.append(part)
                        _0x2a779b += "".join(new_0x351bb8)
                    return _0x2a779b
                def run():
                    slide_token = "d8cc3d473f4d895b3af483e122f1ddc061ccb250"
                    _0x4dd553 = {"KeyArray": ["slideToken"], "bParam": slide_token}
                    total_string = string.digits + string.ascii_letters
                    random_string = "".join([random.choice(total_string) for _ in range(16)])
                    _0x4fb8ac = {
                        "referer": "",
                        "piccolo": f"{random.randint(1000, 9999)}##{random_string}##{int(time.time() * 1000)}",
                        "shirley": "unknown",
                        "title": "unknown",
                        "keywords": "unknown",
                        "description": "unknown",
                        "host": "user.qunar.com",
                        "scriptSrc": ["qimgs.qunarzz.co", "q.qunarzz.com/ho"]
                    }
                    total_string = '-_zyxwvutsrqponmlkjihgfedcba9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA'
                    _0x34877a = "".join([random.choice(total_string) for _ in range(21)])
                    _0x5ad2bb = slide_token + _0x34877a + json.dumps(_0x4dd553['KeyArray'])
                    _0xc21476 = hmac_sha1(_0x5ad2bb)
                    _0x4fb8ac["sign"] = _0xc21476
                    _0x4fb8ac["randomNum"] = _0x34877a
                    _0x4fb8ac["t"] = int(time.time() * 1000)
                    _0x572efb = [
                        "B6F1YrNm+OA=sw",
                        "n8xbeLlzQ",
                        "p5M02SUHt/dog",
                        "cyfj-9kPKu",
                        "EX7VWaqJi",
                        "3CIGDRhTv4"
                    ]
                    _0x34c54c = _0x26cf34(json.dumps(_0x4fb8ac, separators=(',', ':')), _0x572efb)
                    june_v = "1683616182042"
                    _0x112026 = june_v + '##' + _0xc21476 + '##' + _0x34c54c + '##' + _0x34877a + '##' + 'slideToken'
                    print(_0x112026)
                if __name__ == '__main__':
                    run()
                

                JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑&Python生成】

                5、整体测试

                很简单~

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]