[
  {
    "path": ".idea/.gitignore",
    "content": "\n# Default ignored files\n/workspace.xml"
  },
  {
    "path": ".idea/crawler-guide-code.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"PYTHON_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\">\n    <content url=\"file://$MODULE_DIR$\" />\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n  <component name=\"TestRunnerService\">\n    <option name=\"projectConfiguration\" value=\"pytest\" />\n    <option name=\"PROJECT_TEST_RUNNER\" value=\"pytest\" />\n  </component>\n</module>"
  },
  {
    "path": ".idea/inspectionProfiles/profiles_settings.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <settings>\n    <option name=\"USE_PROJECT_PROFILE\" value=\"false\" />\n    <version value=\"1.0\" />\n  </settings>\n</component>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"JavaScriptSettings\">\n    <option name=\"languageLevel\" value=\"ES6\" />\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" project-jdk-name=\"Python 3.7\" project-jdk-type=\"Python SDK\" />\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/crawler-guide-code.iml\" filepath=\"$PROJECT_DIR$/.idea/crawler-guide-code.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "readme.md",
    "content": "\n# 《爬虫逆向进阶实战》书籍代码库 （视频教程背面扫码！）\n\n书籍内容介绍：http://t.csdn.cn/Y1wsV    （视频教程在书背面扫码！）\n\n官方旗舰店：https://item.jd.com/10050499209765.html\n\n![爬虫逆向进阶实战](https://img-blog.csdnimg.cn/de25338bca1f45cebfe0acf8a81d1438.png?)\n\n\n## 更新说明\n\n01、（2022-05-23）因为某些在线工具下架了，给大家做了一个：http://cnlans.com/lx/tools\n\n02、（2022-05-25）案例3.9.2，网站调整为wss协议，最新教程和代码已更新。\n\n03、（2022-06-01）案例3.9.3，网站请求接口调整，最新教程和代码已更新。\n\n04、（2022-06-02）新增3.9.0，新增附录，增加书外案例。\n\n05、（2022-06-06）案例更新的代码在本代码库中，更新的视频在b站:[考古学家lx](https://space.bilibili.com/390499740)。\n\n06、（2022-06-12）更新视频教程：[webpack逆向案例一](https://www.bilibili.com/video/BV1QS4y1i7vp?spm_id_from=333.999.0.0)\n\n07、（2022-06-16）更新10.2.1代码。[邮箱滑块验证](https://www.bilibili.com/video/BV1ZB4y1W7nS)\n\n08、（2022-06-18）增加案例 [某图片混淆的滑块协议验证](https://www.bilibili.com/video/BV16L4y1N7kk?)、[某站反调试和加解密](https://www.bilibili.com/video/BV1iB4y1S7Pk?)\n\n09、（2022-07-14）增加第八章及部分内容。\n\n10、（2022-07-23）增加视频教程：[webpack逆向案例二](https://www.bilibili.com/video/BV1Da411M7k7?spm_id_from=333.999.0.0)\n\n11、（2022-07-24）增加视频教程：[webpack逆向案例三](https://www.bilibili.com/video/BV1MB4y1h7nK/?spm_id_from=333.999.0.0)\n\n12、（2026-01-26）在原有目录中增加了一些内容，更新了一些逆向分析工具。\n\n## 加群\n\n可关注 **《pythonlx》公众号** 获取群聊二维码，购书的同学可以扫码背面二维码加客服进入读者群。\n\n代码库中有需要补充的内容可以提Issues或者加群联系我。\n\npython、java、nodejs等环境大家自己安装一下。\n\n\n\n# 案例涉及的APK\n\n一些APK的下载链接: https://pan.baidu.com/s/1odDoOh2JKlpF5t7MmH1QJg?pwd=n7ug \n\n# 逆向相关工具\n\n### 查壳反编译\n\n- [查壳小工具](https://pan.baidu.com/s/1s1BoElAyQCnPaxb2T3QpEw?pwd=tmbs) \n\n- [AndroidKiller](https://down.52pojie.cn/Tools/Android_Tools/) \n\n- [Apktools2.5.0](https://pan.baidu.com/s/12qB4N_2Fg-IsTB2BcQuiDw?pwd=gjqs) \n\n- [jadx](https://github.com/skylot/jadx)\n\n- [jadx-gui-ai](https://github.com/cncsnet1/jadx-gui-ai)\n\n- [IDAPro7.0 调试工具Windows版本](https://pan.baidu.com/s/1_-PorRCwHDMpmUI1t_cKcQ?pwd=t39m)\n\n- [ddms](https://pan.baidu.com/s/1wdsZvTA-fAZ12o53Exw80A?pwd=wk3d)\n\n- [JEB3.0中文版](https://pan.baidu.com/s/1kCjw8dP9tq7kLBWkublHag?pwd=k2s4)\n\n- [JEB2.3.7(out)](https://pan.baidu.com/s/1HgyyEomL72jLWY1XMtHv8g?pwd=zpha)\n\n- [超级Jadx(out)](https://pan.baidu.com/s/1SHsJGfnGJJmcPfgcC_lnYA?pwd=9999)\n\n### 脱壳工具\n\n- [FDex2](https://pan.baidu.com/s/1e0zcp1IzA-u7UC-A3gaj8g?pwd=yds2)\n\n- [反射大师](https://pan.baidu.com/s/170oS04qoFdd-Btu9DanHfg?pwd=an39) \n\n- [BlackDex3.1.0](https://pan.baidu.com/s/18gijmyy5dgUCbwi-hnqtpg?pwd=433u) \n\n- [DumpDex](https://github.com/WrBug/dumpDex)\n\n- [FRIDA-DEXDump](https://github.com/hluwa/FRIDA-DEXDump)\n\n### HOOK工具\n\n- [Frida](https://github.com/frida/frida)\n\n- [Xposed](https://pan.baidu.com/s/15WnJD8qj9UzSss55DWLNfA?pwd=7sgb)\n\n- [VAExposed](https://pan.baidu.com/s/1fd0r2fy4mm4jUArGE4MZvA?pwd=mu9q)\n\n- [Inspeckage](https://pan.baidu.com/s/1WfnVM7hKE76jNpQc3FnKWg?pwd=pvcs)\n\n- [SSLUnpinning 20](https://pan.baidu.com/s/1EZuv-JK0a-TLHhw4v6SkvQ?pwd=dsfj)  \n\n- [fridaManager](https://pan.baidu.com/s/1u_P2P_kd_H2n2SYTaLB0hA?pwd=jovi)\n\n- [算法助手]，作者: 军哥\n\n### 抓包工具\n\n- [httpCanary 安卓抓包工具](https://pan.baidu.com/s/1mdHHaXulnsM6Zxf335yMHA?pwd=tfhx)\n\n- [Postern安卓抓包工具](https://pan.baidu.com/s/1A-2kIVnYSxpgHqiDn4mqnw?pwd=1e5k)  \n\n- [Drony_113](https://pan.baidu.com/s/14d6ezZXRWDQayL73d2E8gw?pwd=tyk7)  \n\n- [HttpAnalyzerStd V7](https://pan.baidu.com/s/1p3ThL5yqqc5XwTrDdmmGCg?pwd=x9hg)\n\n- [Reqable](https://reqable.com/)\n\n- [Dexterceptor: LSPosed插件-okhttp拦截器](https://github.com/errorman-awful/Dexterceptor)\n\n## chrome插件\n- [request-hook](https://pan.baidu.com/s/1OmMiE4rJrTNwarw3EJbz0A?pwd=thyl)\n\n- [Trace-dist](https://github.com/L018/Trace)\n\n- [v_jstools](https://github.com/cilame/v_jstools)\n\n- [AntiDebug Breaker](https://github.com/0xsdeo/AntiDebug_Breaker)\n\n- [油猴-控制台防检测](https://greasyfork.org/zh-CN/scripts/523792-%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8E%A7%E5%88%B6%E5%8F%B0%E9%98%B2%E6%A3%80%E6%B5%8B)\n\n\n### 微信小程序\n\n- [UnpackMiniApp](https://pan.baidu.com/s/1dwUehOAnPka9eHjXN6Y-Lg?pwd=unp7)\n\n- [CrackMinApp](https://github.com/Cherrison/CrackMinApp)\n\n\n\n\n# 其他常用工具\n\n- [FontCreator英文版](https://pan.baidu.com/s/1Ek34ePZpJYTkmiCuKsqIMQ?pwd=hnku)\n\n- [鬼鬼JS调试工具](https://pan.baidu.com/s/1hjdgx3DOTJMp0wtYGAa67A?pwd=1s67)\n\n- [MT 管理器](https://pan.baidu.com/s/1AfBDHVvini4bweDOD9GoIw?pwd=9999)\n\n- [NP 管理器](https://pan.baidu.com/s/1X5g8loORq_WS0HLqeasLbg?pwd=9jk7)\n\n- [Autojs](https://pan.baidu.com/s/1bbjFWMjFU5m2RupRyIZcGw?pwd=4ikp)\n\n- [AppSignGet](https://pan.baidu.com/s/1_j2QTVFD6qHP3FKp_FVeCw?pwd=6qmu)\n\n\n"
  },
  {
    "path": "update.txt",
    "content": "\n##  Unable to access ... 443: Timed out\n\n##  OpenSSL SSL_connect: Connection was reset in connection to github.com:443\n\n取消全局解决：\n\ngit config --global --unset http.proxy\n\ngit config --global --unset https.proxy\n\n给pycharm挂上vpn再push\n\n\n或者当前项目设置代理：(global,local)\n\ngit config --local http.proxy 127.0.0.1:15732\ngit config --local https.proxy 127.0.0.1:15732\n\n\n## Unable to access xxx OpenSSL SSL_read: Connection was reset, errno 10054\n\ngit config --global http.sslBackend \"openssl\"\n\n---\n\ngit config --global -l\n"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/js3.10.2.1.py",
    "content": "{\n    \"currentPage\": 1,\n    \"pageSize\": 20,\n    \"searchFilter\": [0],\n    \"searchScope\": 0,\n    \"searchSort\": None,\n    \"searchType\": \"paper\",\n    \"searchWord\": \"lxlx\"\n}\n\nimport s_pb2 as pb\nsearch_request = pb.SearchService.SearchRequest()\nsearch_request.commonrequest.searchType = \"paper\"\nsearch_request.commonrequest.searchWord = 'lxlx'\nsearch_request.commonrequest.searchScope = 0\nsearch_request.commonrequest.currentPage = 1\nsearch_request.commonrequest.pageSize = 20\nsearch_request.commonrequest.searchFilter.append(0)\nbytes_body = search_request.SerializeToString()\nbytes_head = bytes([0, 0, 0, 0, len(bytes_body)])\nprint((bytes_body+bytes_head).decode())\n\nimport requests,re\nurl = 'https://s.wanfangdata.com.cn/SearchService.SearchService/search?'\nheaders = {\n    'Content-Type': 'application/grpc-web+proto',\n}\nresp = requests.post(url=url,data=bytes_head+bytes_body,headers=headers)\nprint(resp.text)\n\n# 解析可参考 parent_sample.py"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/parent_sample.py",
    "content": "# -*- coding: utf-8 -*-\n# @Author  : lx\n\n# 专利详情页解析示例\n\nimport requests\nimport s_parent_pb2 as pb\nfrom lxpy import copy_headers_dict\n\nparent_id ='ChJQYXRlbnROZXdTMjAyMjAzMjMSEENOMjAyMDEwNjYxNDM1LjYaCGZ6YW1hbTNw'\n\nsearch_request = pb.SearchService2.CommonRequest()\nsearch_request.resourcetype = \"Patent\"\nsearch_request.id = parent_id\nsearch_request.referer = \"\"\nsearch_request.md5id = \"\"\nsearch_request.transaction = \"\"\nbytes_body = search_request.SerializeToString()\nbytes_head = bytes([0, 0, 0, 0, len(bytes_body)])\ndata=bytes_head+bytes_body\n\nurl = 'https://d.wanfangdata.com.cn/Detail.DetailService/getDetailInFormation'\npatent_headers = copy_headers_dict('''\naccept: */*\naccept-encoding: gzip, deflate, br\naccept-language: zh-CN,zhq=0.9\ncache-control: no-cache\ncontent-type: application/grpc-web+proto\ncookies: CASTGC=CASTGCSpecial=\norigin: https://d.wanfangdata.com.cn\npragma: no-cache\nreferer: https://d.wanfangdata.com.cn/patent/ChJQYXRlbnROZXdTMjAyMjAzMjMSEENOMjAyMDEwNjYxNDM1LjYaCGZ6YW1hbTNw\nsec-ch-ua: \" Not ABrand\"v=\"99\", \"Chromium\"v=\"99\", \"Google Chrome\"v=\"99\"\nsec-ch-ua-mobile: ?0\nsec-ch-ua-platform: \"Windows\"\nsec-fetch-dest: empty\nsec-fetch-mode: cors\nsec-fetch-site: same-origin\nuser-agent: Mozilla/5.0 (Windows NT 10.0 Win64 x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36\nx-grpc-web: 1\nx-user-agent: grpc-web-javascript/0.1\n''')\ndetail_resp = requests.post(url=url,data=data,headers=patent_headers).content\n\nfrom blackboxprotobuf import protobuf_to_json\nimport struct,json\ndata_len = struct.unpack(\">i\", detail_resp[1:5])[0]\ndata = json.loads(protobuf_to_json(detail_resp[5: 5 + data_len])[0])['1']['5']\nprint(data)"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s.proto",
    "content": "syntax = \"proto3\";\n\nmessage SearchService {\n    enum SearchScope {\n        A = 0;\n    }\n    enum SearchFilter {\n        B = 0;\n    }\n\n    message CommonRequest {\n        string searchType = 1;\n        string searchWord = 2;\n        int32 currentPage = 3;\n        int32 pageSize = 4;\n        SearchScope searchScope = 5;\n        repeated SearchFilter searchFilter = 6;\n    }\n\n    message SearchRequest {\n        CommonRequest commonrequest = 1;\n    }\n}"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s_parent_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: s_parent.proto\n\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n  name='s_parent.proto',\n  package='',\n  syntax='proto3',\n  serialized_options=None,\n  create_key=_descriptor._internal_create_key,\n  serialized_pb=b'\\n\\x0es_parent.proto\\\"\\xbf\\x01\\n\\x0eSearchService2\\x1a\\x66\\n\\rCommonRequest\\x12\\x14\\n\\x0cresourcetype\\x18\\x01 \\x01(\\t\\x12\\n\\n\\x02id\\x18\\x02 \\x01(\\t\\x12\\x0f\\n\\x07referer\\x18\\x03 \\x01(\\t\\x12\\r\\n\\x05md5id\\x18\\x04 \\x01(\\t\\x12\\x13\\n\\x0btransaction\\x18\\x05 \\x01(\\t\\x1a\\x45\\n\\rSearchRequest\\x12\\x34\\n\\rcommonrequest\\x18\\x01 \\x01(\\x0b\\x32\\x1d.SearchService2.CommonRequestb\\x06proto3'\n)\n\n\n\n\n_SEARCHSERVICE2_COMMONREQUEST = _descriptor.Descriptor(\n  name='CommonRequest',\n  full_name='SearchService2.CommonRequest',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='resourcetype', full_name='SearchService2.CommonRequest.resourcetype', index=0,\n      number=1, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='id', full_name='SearchService2.CommonRequest.id', index=1,\n      number=2, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='referer', full_name='SearchService2.CommonRequest.referer', index=2,\n      number=3, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='md5id', full_name='SearchService2.CommonRequest.md5id', index=3,\n      number=4, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='transaction', full_name='SearchService2.CommonRequest.transaction', index=4,\n      number=5, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=37,\n  serialized_end=139,\n)\n\n_SEARCHSERVICE2_SEARCHREQUEST = _descriptor.Descriptor(\n  name='SearchRequest',\n  full_name='SearchService2.SearchRequest',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='commonrequest', full_name='SearchService2.SearchRequest.commonrequest', index=0,\n      number=1, type=11, cpp_type=10, label=1,\n      has_default_value=False, default_value=None,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=141,\n  serialized_end=210,\n)\n\n_SEARCHSERVICE2 = _descriptor.Descriptor(\n  name='SearchService2',\n  full_name='SearchService2',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n  ],\n  extensions=[\n  ],\n  nested_types=[_SEARCHSERVICE2_COMMONREQUEST, _SEARCHSERVICE2_SEARCHREQUEST, ],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=19,\n  serialized_end=210,\n)\n\n_SEARCHSERVICE2_COMMONREQUEST.containing_type = _SEARCHSERVICE2\n_SEARCHSERVICE2_SEARCHREQUEST.fields_by_name['commonrequest'].message_type = _SEARCHSERVICE2_COMMONREQUEST\n_SEARCHSERVICE2_SEARCHREQUEST.containing_type = _SEARCHSERVICE2\nDESCRIPTOR.message_types_by_name['SearchService2'] = _SEARCHSERVICE2\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nSearchService2 = _reflection.GeneratedProtocolMessageType('SearchService2', (_message.Message,), {\n\n  'CommonRequest' : _reflection.GeneratedProtocolMessageType('CommonRequest', (_message.Message,), {\n    'DESCRIPTOR' : _SEARCHSERVICE2_COMMONREQUEST,\n    '__module__' : 's_parent_pb2'\n    # @@protoc_insertion_point(class_scope:SearchService2.CommonRequest)\n    })\n  ,\n\n  'SearchRequest' : _reflection.GeneratedProtocolMessageType('SearchRequest', (_message.Message,), {\n    'DESCRIPTOR' : _SEARCHSERVICE2_SEARCHREQUEST,\n    '__module__' : 's_parent_pb2'\n    # @@protoc_insertion_point(class_scope:SearchService2.SearchRequest)\n    })\n  ,\n  'DESCRIPTOR' : _SEARCHSERVICE2,\n  '__module__' : 's_parent_pb2'\n  # @@protoc_insertion_point(class_scope:SearchService2)\n  })\n_sym_db.RegisterMessage(SearchService2)\n_sym_db.RegisterMessage(SearchService2.CommonRequest)\n_sym_db.RegisterMessage(SearchService2.SearchRequest)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: s.proto\n\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n  name='s.proto',\n  package='',\n  syntax='proto3',\n  serialized_options=None,\n  create_key=_descriptor._internal_create_key,\n  serialized_pb=b'\\n\\x07s.proto\\\"\\xc7\\x02\\n\\rSearchService\\x1a\\xc2\\x01\\n\\rCommonRequest\\x12\\x12\\n\\nsearchType\\x18\\x01 \\x01(\\t\\x12\\x12\\n\\nsearchWord\\x18\\x02 \\x01(\\t\\x12\\x13\\n\\x0b\\x63urrentPage\\x18\\x03 \\x01(\\x05\\x12\\x10\\n\\x08pageSize\\x18\\x04 \\x01(\\x05\\x12/\\n\\x0bsearchScope\\x18\\x05 \\x01(\\x0e\\x32\\x1a.SearchService.SearchScope\\x12\\x31\\n\\x0csearchFilter\\x18\\x06 \\x03(\\x0e\\x32\\x1b.SearchService.SearchFilter\\x1a\\x44\\n\\rSearchRequest\\x12\\x33\\n\\rcommonrequest\\x18\\x01 \\x01(\\x0b\\x32\\x1c.SearchService.CommonRequest\\\"\\x14\\n\\x0bSearchScope\\x12\\x05\\n\\x01\\x41\\x10\\x00\\\"\\x15\\n\\x0cSearchFilter\\x12\\x05\\n\\x01\\x42\\x10\\x00\\x62\\x06proto3'\n)\n\n\n\n_SEARCHSERVICE_SEARCHSCOPE = _descriptor.EnumDescriptor(\n  name='SearchScope',\n  full_name='SearchService.SearchScope',\n  filename=None,\n  file=DESCRIPTOR,\n  create_key=_descriptor._internal_create_key,\n  values=[\n    _descriptor.EnumValueDescriptor(\n      name='A', index=0, number=0,\n      serialized_options=None,\n      type=None,\n      create_key=_descriptor._internal_create_key),\n  ],\n  containing_type=None,\n  serialized_options=None,\n  serialized_start=296,\n  serialized_end=316,\n)\n_sym_db.RegisterEnumDescriptor(_SEARCHSERVICE_SEARCHSCOPE)\n\n_SEARCHSERVICE_SEARCHFILTER = _descriptor.EnumDescriptor(\n  name='SearchFilter',\n  full_name='SearchService.SearchFilter',\n  filename=None,\n  file=DESCRIPTOR,\n  create_key=_descriptor._internal_create_key,\n  values=[\n    _descriptor.EnumValueDescriptor(\n      name='B', index=0, number=0,\n      serialized_options=None,\n      type=None,\n      create_key=_descriptor._internal_create_key),\n  ],\n  containing_type=None,\n  serialized_options=None,\n  serialized_start=318,\n  serialized_end=339,\n)\n_sym_db.RegisterEnumDescriptor(_SEARCHSERVICE_SEARCHFILTER)\n\n\n_SEARCHSERVICE_COMMONREQUEST = _descriptor.Descriptor(\n  name='CommonRequest',\n  full_name='SearchService.CommonRequest',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='searchType', full_name='SearchService.CommonRequest.searchType', index=0,\n      number=1, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='searchWord', full_name='SearchService.CommonRequest.searchWord', index=1,\n      number=2, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='currentPage', full_name='SearchService.CommonRequest.currentPage', index=2,\n      number=3, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='pageSize', full_name='SearchService.CommonRequest.pageSize', index=3,\n      number=4, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='searchScope', full_name='SearchService.CommonRequest.searchScope', index=4,\n      number=5, type=14, cpp_type=8, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='searchFilter', full_name='SearchService.CommonRequest.searchFilter', index=5,\n      number=6, type=14, cpp_type=8, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=30,\n  serialized_end=224,\n)\n\n_SEARCHSERVICE_SEARCHREQUEST = _descriptor.Descriptor(\n  name='SearchRequest',\n  full_name='SearchService.SearchRequest',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='commonrequest', full_name='SearchService.SearchRequest.commonrequest', index=0,\n      number=1, type=11, cpp_type=10, label=1,\n      has_default_value=False, default_value=None,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=226,\n  serialized_end=294,\n)\n\n_SEARCHSERVICE = _descriptor.Descriptor(\n  name='SearchService',\n  full_name='SearchService',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n  ],\n  extensions=[\n  ],\n  nested_types=[_SEARCHSERVICE_COMMONREQUEST, _SEARCHSERVICE_SEARCHREQUEST, ],\n  enum_types=[\n    _SEARCHSERVICE_SEARCHSCOPE,\n    _SEARCHSERVICE_SEARCHFILTER,\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=12,\n  serialized_end=339,\n)\n\n_SEARCHSERVICE_COMMONREQUEST.fields_by_name['searchScope'].enum_type = _SEARCHSERVICE_SEARCHSCOPE\n_SEARCHSERVICE_COMMONREQUEST.fields_by_name['searchFilter'].enum_type = _SEARCHSERVICE_SEARCHFILTER\n_SEARCHSERVICE_COMMONREQUEST.containing_type = _SEARCHSERVICE\n_SEARCHSERVICE_SEARCHREQUEST.fields_by_name['commonrequest'].message_type = _SEARCHSERVICE_COMMONREQUEST\n_SEARCHSERVICE_SEARCHREQUEST.containing_type = _SEARCHSERVICE\n_SEARCHSERVICE_SEARCHSCOPE.containing_type = _SEARCHSERVICE\n_SEARCHSERVICE_SEARCHFILTER.containing_type = _SEARCHSERVICE\nDESCRIPTOR.message_types_by_name['SearchService'] = _SEARCHSERVICE\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nSearchService = _reflection.GeneratedProtocolMessageType('SearchService', (_message.Message,), {\n\n  'CommonRequest' : _reflection.GeneratedProtocolMessageType('CommonRequest', (_message.Message,), {\n    'DESCRIPTOR' : _SEARCHSERVICE_COMMONREQUEST,\n    '__module__' : 's_pb2'\n    # @@protoc_insertion_point(class_scope:SearchService.CommonRequest)\n    })\n  ,\n\n  'SearchRequest' : _reflection.GeneratedProtocolMessageType('SearchRequest', (_message.Message,), {\n    'DESCRIPTOR' : _SEARCHSERVICE_SEARCHREQUEST,\n    '__module__' : 's_pb2'\n    # @@protoc_insertion_point(class_scope:SearchService.SearchRequest)\n    })\n  ,\n  'DESCRIPTOR' : _SEARCHSERVICE,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:SearchService)\n  })\n_sym_db.RegisterMessage(SearchService)\n_sym_db.RegisterMessage(SearchService.CommonRequest)\n_sym_db.RegisterMessage(SearchService.SearchRequest)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/js.py",
    "content": "from google.protobuf.json_format import MessageToDict\nfrom s_pb2 import *\nimport base64\n\ndef on_message(data):\n    danmu_resp = test()\n    danmu_resp.ParseFromString(data)\n    Message = MessageToDict(danmu_resp, preserving_proto_field_name=True)\n    for message in Message[\"message\"]:\n        method = message[\"method\"]\n        payload = bytes(base64.b64decode(message[\"payload\"].encode()))\n        if method == \"WebcastMemberMessage\":\n            menber_message = WebcastMemberMessage()\n            menber_message.ParseFromString(payload)\n            mes= MessageToDict(menber_message, preserving_proto_field_name=True)\n            print(mes)\n        elif method == \"WebcastLikeMessage\":\n            menber_message = WebcastLikeMessage()\n            menber_message.ParseFromString(payload)\n            mes = MessageToDict(menber_message, preserving_proto_field_name=True)\n            print(mes)\n\nwith open('s.txt','rb') as f:\n    data = f.read()\non_message(data)"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/s.proto",
    "content": "syntax = \"proto3\";\n\nmessage test{\n    repeated Message message =1;\n    string cursor =2;\n    uint64 fetchInterval=3;\n    uint64 now=4;\n    string internalExt=5;\n    int32 fetchType=6;\n}\n\nmessage Message{\n    string method=1;\n    bytes payload=2;\n    uint64 msgId=3;\n    int32 msgType=4;\n    uint64 offset=5;\n    int64 rankScore = 7;\n    int64 topUserNo = 8;\n    int64 enterType = 9;\n    int64 action = 10;\n    int64 userId = 12;\n    string popStr = 14;\n}\n\nmessage WebcastMemberMessage{\n    repeated Common common=1;\n    repeated User user=2;\n    uint64 memberCount=3;\n    repeated User operator=4;\n    bool isSetToAdmin=5;\n    bool isTopUser=6;\n}\n\nmessage WebcastLikeMessage{\n    repeated Common common=1;\n    uint64 count=2;\n    uint64 total=3;\n    uint64 color=4;\n    repeated User user=5;\n    string icon=6;\n}\n\nmessage WebcastChatMessage{\n    repeated Common common=1;\n    repeated User user=2;\n    string content=3;\n    bool visibleToSender = 4;\n    string fullScreenTextColor = 6;\n}\n\nmessage WebcastGiftMessage{\n    repeated Common common=1;\n    uint64 giftId=2;\n    uint64 fanTicketCount=3;\n    uint64 groupCount=4;\n    uint64 repeatCount=5;\n    uint64 comboCount=6;\n    repeated User user=7;\n    repeated User toUser=8;\n}\n\nmessage Common{\n    string method=1;\n    uint64 msgId=2;\n    uint64 roomId=3;\n    uint64 createTime=4;\n    int32 monitor=5;\n    bool isShowMsg=6;\n    string describe=7;\n    uint64 foldType=9;\n}\n\nmessage User{\n  int64 id = 1;\n  int64 shortId = 2;\n  string nickname = 3;\n  int32 gender = 4;\n  string signature = 5;\n  int32 level = 6;\n  int64 birthday = 7;\n  string telephone = 8;\n  bool verified = 12;\n  int32 experience = 13;\n  string city = 14;\n  int32 status = 15;\n  int64 createTime = 16;\n  int64 modifyTime = 17;\n  int32 secret = 18;\n  string shareQrcodeUri = 19;\n  int32 incomeSharePercent = 20;\n}"
  },
  {
    "path": "第三章：Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/s_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: s.proto\n\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n  name='s.proto',\n  package='',\n  syntax='proto3',\n  serialized_options=None,\n  create_key=_descriptor._internal_create_key,\n  serialized_pb=b'\\n\\x07s.proto\\\"}\\n\\x04test\\x12\\x19\\n\\x07message\\x18\\x01 \\x03(\\x0b\\x32\\x08.Message\\x12\\x0e\\n\\x06\\x63ursor\\x18\\x02 \\x01(\\t\\x12\\x15\\n\\rfetchInterval\\x18\\x03 \\x01(\\x04\\x12\\x0b\\n\\x03now\\x18\\x04 \\x01(\\x04\\x12\\x13\\n\\x0binternalExt\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tfetchType\\x18\\x06 \\x01(\\x05\\\"\\xc3\\x01\\n\\x07Message\\x12\\x0e\\n\\x06method\\x18\\x01 \\x01(\\t\\x12\\x0f\\n\\x07payload\\x18\\x02 \\x01(\\x0c\\x12\\r\\n\\x05msgId\\x18\\x03 \\x01(\\x04\\x12\\x0f\\n\\x07msgType\\x18\\x04 \\x01(\\x05\\x12\\x0e\\n\\x06offset\\x18\\x05 \\x01(\\x04\\x12\\x11\\n\\trankScore\\x18\\x07 \\x01(\\x03\\x12\\x11\\n\\ttopUserNo\\x18\\x08 \\x01(\\x03\\x12\\x11\\n\\tenterType\\x18\\t \\x01(\\x03\\x12\\x0e\\n\\x06\\x61\\x63tion\\x18\\n \\x01(\\x03\\x12\\x0e\\n\\x06userId\\x18\\x0c \\x01(\\x03\\x12\\x0e\\n\\x06popStr\\x18\\x0e \\x01(\\t\\\"\\x9b\\x01\\n\\x14WebcastMemberMessage\\x12\\x17\\n\\x06\\x63ommon\\x18\\x01 \\x03(\\x0b\\x32\\x07.Common\\x12\\x13\\n\\x04user\\x18\\x02 \\x03(\\x0b\\x32\\x05.User\\x12\\x13\\n\\x0bmemberCount\\x18\\x03 \\x01(\\x04\\x12\\x17\\n\\x08operator\\x18\\x04 \\x03(\\x0b\\x32\\x05.User\\x12\\x14\\n\\x0cisSetToAdmin\\x18\\x05 \\x01(\\x08\\x12\\x11\\n\\tisTopUser\\x18\\x06 \\x01(\\x08\\\"}\\n\\x12WebcastLikeMessage\\x12\\x17\\n\\x06\\x63ommon\\x18\\x01 \\x03(\\x0b\\x32\\x07.Common\\x12\\r\\n\\x05\\x63ount\\x18\\x02 \\x01(\\x04\\x12\\r\\n\\x05total\\x18\\x03 \\x01(\\x04\\x12\\r\\n\\x05\\x63olor\\x18\\x04 \\x01(\\x04\\x12\\x13\\n\\x04user\\x18\\x05 \\x03(\\x0b\\x32\\x05.User\\x12\\x0c\\n\\x04icon\\x18\\x06 \\x01(\\t\\\"\\x89\\x01\\n\\x12WebcastChatMessage\\x12\\x17\\n\\x06\\x63ommon\\x18\\x01 \\x03(\\x0b\\x32\\x07.Common\\x12\\x13\\n\\x04user\\x18\\x02 \\x03(\\x0b\\x32\\x05.User\\x12\\x0f\\n\\x07\\x63ontent\\x18\\x03 \\x01(\\t\\x12\\x17\\n\\x0fvisibleToSender\\x18\\x04 \\x01(\\x08\\x12\\x1b\\n\\x13\\x66ullScreenTextColor\\x18\\x06 \\x01(\\t\\\"\\xbe\\x01\\n\\x12WebcastGiftMessage\\x12\\x17\\n\\x06\\x63ommon\\x18\\x01 \\x03(\\x0b\\x32\\x07.Common\\x12\\x0e\\n\\x06giftId\\x18\\x02 \\x01(\\x04\\x12\\x16\\n\\x0e\\x66\\x61nTicketCount\\x18\\x03 \\x01(\\x04\\x12\\x12\\n\\ngroupCount\\x18\\x04 \\x01(\\x04\\x12\\x13\\n\\x0brepeatCount\\x18\\x05 \\x01(\\x04\\x12\\x12\\n\\ncomboCount\\x18\\x06 \\x01(\\x04\\x12\\x13\\n\\x04user\\x18\\x07 \\x03(\\x0b\\x32\\x05.User\\x12\\x15\\n\\x06toUser\\x18\\x08 \\x03(\\x0b\\x32\\x05.User\\\"\\x93\\x01\\n\\x06\\x43ommon\\x12\\x0e\\n\\x06method\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05msgId\\x18\\x02 \\x01(\\x04\\x12\\x0e\\n\\x06roomId\\x18\\x03 \\x01(\\x04\\x12\\x12\\n\\ncreateTime\\x18\\x04 \\x01(\\x04\\x12\\x0f\\n\\x07monitor\\x18\\x05 \\x01(\\x05\\x12\\x11\\n\\tisShowMsg\\x18\\x06 \\x01(\\x08\\x12\\x10\\n\\x08\\x64\\x65scribe\\x18\\x07 \\x01(\\t\\x12\\x10\\n\\x08\\x66oldType\\x18\\t \\x01(\\x04\\\"\\xbc\\x02\\n\\x04User\\x12\\n\\n\\x02id\\x18\\x01 \\x01(\\x03\\x12\\x0f\\n\\x07shortId\\x18\\x02 \\x01(\\x03\\x12\\x10\\n\\x08nickname\\x18\\x03 \\x01(\\t\\x12\\x0e\\n\\x06gender\\x18\\x04 \\x01(\\x05\\x12\\x11\\n\\tsignature\\x18\\x05 \\x01(\\t\\x12\\r\\n\\x05level\\x18\\x06 \\x01(\\x05\\x12\\x10\\n\\x08\\x62irthday\\x18\\x07 \\x01(\\x03\\x12\\x11\\n\\ttelephone\\x18\\x08 \\x01(\\t\\x12\\x10\\n\\x08verified\\x18\\x0c \\x01(\\x08\\x12\\x12\\n\\nexperience\\x18\\r \\x01(\\x05\\x12\\x0c\\n\\x04\\x63ity\\x18\\x0e \\x01(\\t\\x12\\x0e\\n\\x06status\\x18\\x0f \\x01(\\x05\\x12\\x12\\n\\ncreateTime\\x18\\x10 \\x01(\\x03\\x12\\x12\\n\\nmodifyTime\\x18\\x11 \\x01(\\x03\\x12\\x0e\\n\\x06secret\\x18\\x12 \\x01(\\x05\\x12\\x16\\n\\x0eshareQrcodeUri\\x18\\x13 \\x01(\\t\\x12\\x1a\\n\\x12incomeSharePercent\\x18\\x14 \\x01(\\x05\\x62\\x06proto3'\n)\n\n\n\n\n_TEST = _descriptor.Descriptor(\n  name='test',\n  full_name='test',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='message', full_name='test.message', index=0,\n      number=1, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='cursor', full_name='test.cursor', index=1,\n      number=2, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='fetchInterval', full_name='test.fetchInterval', index=2,\n      number=3, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='now', full_name='test.now', index=3,\n      number=4, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='internalExt', full_name='test.internalExt', index=4,\n      number=5, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='fetchType', full_name='test.fetchType', index=5,\n      number=6, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=11,\n  serialized_end=136,\n)\n\n\n_MESSAGE = _descriptor.Descriptor(\n  name='Message',\n  full_name='Message',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='method', full_name='Message.method', index=0,\n      number=1, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='payload', full_name='Message.payload', index=1,\n      number=2, type=12, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\",\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='msgId', full_name='Message.msgId', index=2,\n      number=3, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='msgType', full_name='Message.msgType', index=3,\n      number=4, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='offset', full_name='Message.offset', index=4,\n      number=5, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='rankScore', full_name='Message.rankScore', index=5,\n      number=7, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='topUserNo', full_name='Message.topUserNo', index=6,\n      number=8, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='enterType', full_name='Message.enterType', index=7,\n      number=9, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='action', full_name='Message.action', index=8,\n      number=10, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='userId', full_name='Message.userId', index=9,\n      number=12, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='popStr', full_name='Message.popStr', index=10,\n      number=14, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=139,\n  serialized_end=334,\n)\n\n\n_WEBCASTMEMBERMESSAGE = _descriptor.Descriptor(\n  name='WebcastMemberMessage',\n  full_name='WebcastMemberMessage',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='common', full_name='WebcastMemberMessage.common', index=0,\n      number=1, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='user', full_name='WebcastMemberMessage.user', index=1,\n      number=2, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='memberCount', full_name='WebcastMemberMessage.memberCount', index=2,\n      number=3, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='operator', full_name='WebcastMemberMessage.operator', index=3,\n      number=4, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='isSetToAdmin', full_name='WebcastMemberMessage.isSetToAdmin', index=4,\n      number=5, type=8, cpp_type=7, label=1,\n      has_default_value=False, default_value=False,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='isTopUser', full_name='WebcastMemberMessage.isTopUser', index=5,\n      number=6, type=8, cpp_type=7, label=1,\n      has_default_value=False, default_value=False,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=337,\n  serialized_end=492,\n)\n\n\n_WEBCASTLIKEMESSAGE = _descriptor.Descriptor(\n  name='WebcastLikeMessage',\n  full_name='WebcastLikeMessage',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='common', full_name='WebcastLikeMessage.common', index=0,\n      number=1, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='count', full_name='WebcastLikeMessage.count', index=1,\n      number=2, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='total', full_name='WebcastLikeMessage.total', index=2,\n      number=3, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='color', full_name='WebcastLikeMessage.color', index=3,\n      number=4, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='user', full_name='WebcastLikeMessage.user', index=4,\n      number=5, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='icon', full_name='WebcastLikeMessage.icon', index=5,\n      number=6, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=494,\n  serialized_end=619,\n)\n\n\n_WEBCASTCHATMESSAGE = _descriptor.Descriptor(\n  name='WebcastChatMessage',\n  full_name='WebcastChatMessage',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='common', full_name='WebcastChatMessage.common', index=0,\n      number=1, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='user', full_name='WebcastChatMessage.user', index=1,\n      number=2, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='content', full_name='WebcastChatMessage.content', index=2,\n      number=3, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='visibleToSender', full_name='WebcastChatMessage.visibleToSender', index=3,\n      number=4, type=8, cpp_type=7, label=1,\n      has_default_value=False, default_value=False,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='fullScreenTextColor', full_name='WebcastChatMessage.fullScreenTextColor', index=4,\n      number=6, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=622,\n  serialized_end=759,\n)\n\n\n_WEBCASTGIFTMESSAGE = _descriptor.Descriptor(\n  name='WebcastGiftMessage',\n  full_name='WebcastGiftMessage',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='common', full_name='WebcastGiftMessage.common', index=0,\n      number=1, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='giftId', full_name='WebcastGiftMessage.giftId', index=1,\n      number=2, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='fanTicketCount', full_name='WebcastGiftMessage.fanTicketCount', index=2,\n      number=3, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='groupCount', full_name='WebcastGiftMessage.groupCount', index=3,\n      number=4, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='repeatCount', full_name='WebcastGiftMessage.repeatCount', index=4,\n      number=5, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='comboCount', full_name='WebcastGiftMessage.comboCount', index=5,\n      number=6, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='user', full_name='WebcastGiftMessage.user', index=6,\n      number=7, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='toUser', full_name='WebcastGiftMessage.toUser', index=7,\n      number=8, type=11, cpp_type=10, label=3,\n      has_default_value=False, default_value=[],\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=762,\n  serialized_end=952,\n)\n\n\n_COMMON = _descriptor.Descriptor(\n  name='Common',\n  full_name='Common',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='method', full_name='Common.method', index=0,\n      number=1, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='msgId', full_name='Common.msgId', index=1,\n      number=2, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='roomId', full_name='Common.roomId', index=2,\n      number=3, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='createTime', full_name='Common.createTime', index=3,\n      number=4, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='monitor', full_name='Common.monitor', index=4,\n      number=5, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='isShowMsg', full_name='Common.isShowMsg', index=5,\n      number=6, type=8, cpp_type=7, label=1,\n      has_default_value=False, default_value=False,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='describe', full_name='Common.describe', index=6,\n      number=7, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='foldType', full_name='Common.foldType', index=7,\n      number=9, type=4, cpp_type=4, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=955,\n  serialized_end=1102,\n)\n\n\n_USER = _descriptor.Descriptor(\n  name='User',\n  full_name='User',\n  filename=None,\n  file=DESCRIPTOR,\n  containing_type=None,\n  create_key=_descriptor._internal_create_key,\n  fields=[\n    _descriptor.FieldDescriptor(\n      name='id', full_name='User.id', index=0,\n      number=1, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='shortId', full_name='User.shortId', index=1,\n      number=2, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='nickname', full_name='User.nickname', index=2,\n      number=3, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='gender', full_name='User.gender', index=3,\n      number=4, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='signature', full_name='User.signature', index=4,\n      number=5, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='level', full_name='User.level', index=5,\n      number=6, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='birthday', full_name='User.birthday', index=6,\n      number=7, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='telephone', full_name='User.telephone', index=7,\n      number=8, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='verified', full_name='User.verified', index=8,\n      number=12, type=8, cpp_type=7, label=1,\n      has_default_value=False, default_value=False,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='experience', full_name='User.experience', index=9,\n      number=13, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='city', full_name='User.city', index=10,\n      number=14, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='status', full_name='User.status', index=11,\n      number=15, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='createTime', full_name='User.createTime', index=12,\n      number=16, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='modifyTime', full_name='User.modifyTime', index=13,\n      number=17, type=3, cpp_type=2, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='secret', full_name='User.secret', index=14,\n      number=18, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='shareQrcodeUri', full_name='User.shareQrcodeUri', index=15,\n      number=19, type=9, cpp_type=9, label=1,\n      has_default_value=False, default_value=b\"\".decode('utf-8'),\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n    _descriptor.FieldDescriptor(\n      name='incomeSharePercent', full_name='User.incomeSharePercent', index=16,\n      number=20, type=5, cpp_type=1, label=1,\n      has_default_value=False, default_value=0,\n      message_type=None, enum_type=None, containing_type=None,\n      is_extension=False, extension_scope=None,\n      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),\n  ],\n  extensions=[\n  ],\n  nested_types=[],\n  enum_types=[\n  ],\n  serialized_options=None,\n  is_extendable=False,\n  syntax='proto3',\n  extension_ranges=[],\n  oneofs=[\n  ],\n  serialized_start=1105,\n  serialized_end=1421,\n)\n\n_TEST.fields_by_name['message'].message_type = _MESSAGE\n_WEBCASTMEMBERMESSAGE.fields_by_name['common'].message_type = _COMMON\n_WEBCASTMEMBERMESSAGE.fields_by_name['user'].message_type = _USER\n_WEBCASTMEMBERMESSAGE.fields_by_name['operator'].message_type = _USER\n_WEBCASTLIKEMESSAGE.fields_by_name['common'].message_type = _COMMON\n_WEBCASTLIKEMESSAGE.fields_by_name['user'].message_type = _USER\n_WEBCASTCHATMESSAGE.fields_by_name['common'].message_type = _COMMON\n_WEBCASTCHATMESSAGE.fields_by_name['user'].message_type = _USER\n_WEBCASTGIFTMESSAGE.fields_by_name['common'].message_type = _COMMON\n_WEBCASTGIFTMESSAGE.fields_by_name['user'].message_type = _USER\n_WEBCASTGIFTMESSAGE.fields_by_name['toUser'].message_type = _USER\nDESCRIPTOR.message_types_by_name['test'] = _TEST\nDESCRIPTOR.message_types_by_name['Message'] = _MESSAGE\nDESCRIPTOR.message_types_by_name['WebcastMemberMessage'] = _WEBCASTMEMBERMESSAGE\nDESCRIPTOR.message_types_by_name['WebcastLikeMessage'] = _WEBCASTLIKEMESSAGE\nDESCRIPTOR.message_types_by_name['WebcastChatMessage'] = _WEBCASTCHATMESSAGE\nDESCRIPTOR.message_types_by_name['WebcastGiftMessage'] = _WEBCASTGIFTMESSAGE\nDESCRIPTOR.message_types_by_name['Common'] = _COMMON\nDESCRIPTOR.message_types_by_name['User'] = _USER\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\ntest = _reflection.GeneratedProtocolMessageType('test', (_message.Message,), {\n  'DESCRIPTOR' : _TEST,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:test)\n  })\n_sym_db.RegisterMessage(test)\n\nMessage = _reflection.GeneratedProtocolMessageType('Message', (_message.Message,), {\n  'DESCRIPTOR' : _MESSAGE,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:Message)\n  })\n_sym_db.RegisterMessage(Message)\n\nWebcastMemberMessage = _reflection.GeneratedProtocolMessageType('WebcastMemberMessage', (_message.Message,), {\n  'DESCRIPTOR' : _WEBCASTMEMBERMESSAGE,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:WebcastMemberMessage)\n  })\n_sym_db.RegisterMessage(WebcastMemberMessage)\n\nWebcastLikeMessage = _reflection.GeneratedProtocolMessageType('WebcastLikeMessage', (_message.Message,), {\n  'DESCRIPTOR' : _WEBCASTLIKEMESSAGE,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:WebcastLikeMessage)\n  })\n_sym_db.RegisterMessage(WebcastLikeMessage)\n\nWebcastChatMessage = _reflection.GeneratedProtocolMessageType('WebcastChatMessage', (_message.Message,), {\n  'DESCRIPTOR' : _WEBCASTCHATMESSAGE,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:WebcastChatMessage)\n  })\n_sym_db.RegisterMessage(WebcastChatMessage)\n\nWebcastGiftMessage = _reflection.GeneratedProtocolMessageType('WebcastGiftMessage', (_message.Message,), {\n  'DESCRIPTOR' : _WEBCASTGIFTMESSAGE,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:WebcastGiftMessage)\n  })\n_sym_db.RegisterMessage(WebcastGiftMessage)\n\nCommon = _reflection.GeneratedProtocolMessageType('Common', (_message.Message,), {\n  'DESCRIPTOR' : _COMMON,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:Common)\n  })\n_sym_db.RegisterMessage(Common)\n\nUser = _reflection.GeneratedProtocolMessageType('User', (_message.Message,), {\n  'DESCRIPTOR' : _USER,\n  '__module__' : 's_pb2'\n  # @@protoc_insertion_point(class_scope:User)\n  })\n_sym_db.RegisterMessage(User)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "第三章：Web Js逆向/3.11 常见反调试/内存爆破.md",
    "content": "# 内存爆破\n\n在使用浏览器控制台（如 Chrome DevTools）或本地环境 调试 JavaScript 代码时，有时会遇到“内存爆破”（Memory Spike 或 Out of Memory）的问题。这通常发生在执行大量数据操作、递归调用、或在控制台中打印大型对象时。\n\n---\n\n## 一、什么是内存爆破\n\n**内存爆破**指的是 JavaScript 执行过程中，占用的内存突然激增，导致浏览器卡顿、崩溃或抛出 `Out of Memory` 错误。在控制台中调试时，常见的表现包括：\n\n*   控制台输出大量数据（如大型数组、对象）\n    \n*   递归函数未正确终止\n    \n*   数据结构存在循环引用\n    \n*   持续创建未释放的对象或闭包\n    \n\n---\n\n## 二、常见原因和解决方案\n\n### 1.开启控制台后内存溢出\n\n开启devtools后，调试过程中出现内存爆炸的情况，通常是站点的反调试机制。\n\n**方案**：在内存上涨时，点击控制台调试位置的暂停按钮。等自动跳转到对应代码位置后，分析检测点和溢出点，找到后可删除并覆盖对应JS代码。\n\n### 2. 控制台打印大型对象\n\n在控制台中直接打印大型对象（如 DOM 元素、大型数组、嵌套对象）会导致浏览器尝试将其结构完整加载到内存中进行渲染，从而引发内存激增。\n\n```javascript\nconsole.log(largeData); // largeData 是一个包含数百万条数据的对象或数组\n```\n\n**方案**：避免直接打印大型对象\n\n*   只打印关键字段或摘要信息\n    \n*   使用 `console.table()` 替代 `console.log()` 来查看结构化数据\n    \n*   使用 `JSON.stringify()` 限制打印深度\n    \n\n```javascript\nconsole.log(JSON.stringify(largeData, null, 2).substring(0, 1000)); // 只打印前1000字符\n```\n\n*   使用 `slice()` 截取部分数组\n    \n\n```javascript\nconsole.log(largeArray.slice(0, 100)); // 只打印前100项\n```\n\n### 3. 递归调用未终止\n\n无限递归会不断压栈，最终导致内存溢出。\n\n```javascript\nfunction infiniteRecursion() {\n    console.log(\"Calling...\");\n    infiniteRecursion();\n}\ninfiniteRecursion(); // 会爆栈并导致内存问题\n```\n\n**方案**：避免无限递归和深度递归\n\n*   增加递归终止条件\n    \n*   使用尾递归优化（ES6 支持）\n    \n*   改用循环结构替代递归\n    \n\n### 4. 内存泄漏（Memory Leak）\n\n*   未释放的闭包引用\n    \n*   未清理的事件监听器\n    \n*   缓存机制不当\n    \n\n**方案**：使用 DevTools 内存分析工具\n\nChrome DevTools 提供了强大的内存分析工具，可用于：\n\n*   查看内存快照（Memory Snapshot）\n    \n*   检测内存泄漏（Memory Leak Detection）\n    \n*   跟踪对象保留树（Retaining Tree）\n    \n\n路径：`DevTools -> Memory -> Take Snapshot`\n\n### 5. 数据结构存在循环引用\n\n在打印或序列化对象时，如果对象存在循环引用，可能导致无限递归或大量内存占用。\n\n```javascript\nlet obj = {};\nobj.self = obj;\nconsole.log(obj); // 控制台可能卡死或占用大量内存\n```\n\n**方案**：清理不必要的引用\n\n*   及时将不再使用的对象设为 `null`\n    \n*   移除事件监听器\n    \n*   使用弱引用（如 `WeakMap`、`WeakSet`）存储临时数据\n    \n\n```javascript\nlet cache = new WeakMap();\n\nfunction processElement(el) {\n    cache.set(el, \"processed\");\n}\n```\n\n### 6. 使用 `eval` 或动态代码执行\n\n某些调试技巧使用 `eval()` 执行字符串代码，可能导致不可预测的内存行为。\n\n**方案**：避免控制台中频繁执行大型脚本\n\n*   将调试逻辑封装到函数中，避免在控制台中直接运行复杂逻辑\n    \n*   使用断点替代 `console.log()` 进行变量查看\n    \n\n### 7. 使用 `try...catch` 捕获异常\n\n防止内存异常导致脚本崩溃：\n\n```javascript\ntry {\n    // 大型数据处理\n} catch (e) {\n    console.error(\"内存错误：\", e);\n}\n```\n---"
  },
  {
    "path": "第三章：Web Js逆向/3.11 常见反调试/开发者工具检测.md",
    "content": "# 开发者工具检测\n\n浏览器按 F12 后打开的工具，正式名称是 **开发者工具（Developer Tools，简称 DevTools）**，也常被称作「调试工具」「F12 工具」。\n\n检测原理可以参考 \"开发者工具检测器\"：[https://github.com/AEPKILL/devtools-detector](https://github.com/AEPKILL/devtools-detector)\n\n针对检测器，一个通用的chrome反检测插件：[https://greasyfork.org/zh-CN/scripts/523792-%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8E%A7%E5%88%B6%E5%8F%B0%E9%98%B2%E6%A3%80%E6%B5%8B](https://greasyfork.org/zh-CN/scripts/523792-%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8E%A7%E5%88%B6%E5%8F%B0%E9%98%B2%E6%A3%80%E6%B5%8B)\n\n启用后可通过 [zaker](https://www.myzaker.com/) 、zhihu、xueqiu、xhs.huitun.com [、www.autoinfo.org.cn](https://www.autoinfo.org.cn/#/)、[blog.aepkill.com/demos/devtools-detector](https://blog.aepkill.com/demos/devtools-detector/) 的**DevTools**检测机制。\n\n![image.png](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/Lk3lbmbzGpdmMOm9/img/e75fa14a-17f8-4270-ac10-52a80c4e5d0b.png)"
  },
  {
    "path": "第三章：Web Js逆向/3.11 常见反调试/无限debugger.md",
    "content": "# 无限debugger\n\n`debugger` 是JavaScript中的一个关键字，用于在代码中设置断点。当浏览器的开发者工具开启时，遇到 `debugger` 语句会暂停代码执行，等待用户操作。\n\n**无限** `**debugger**` **的表现：**\n\n*   控制台频繁弹出断点提示\n    \n*   页面无法正常加载或执行\n    \n*   手动跳过断点后又立即再次触发\n    \n\n**示例代码：**\n\n```javascript\nsetInterval(function() {\n    debugger;\n}, 1000);\n```\n\n或者更隐蔽的方式：\n\n```javascript\nfunction loopDebug() {\n    while (true) {\n        debugger;\n    }\n}\nloopDebug();\n```\n\n---\n\n## 三、绕过无限 `debugger` 的方法\n\n### 方法一：禁用所有断点\n\n**Chrome / Edge / Firefox 浏览器：**\n\n1.  打开开发者工具（F12）\n    \n2.  在“Sources”或“Debugger”面板中找到“Deactivate breakpoints”按钮（通常是一个断点图标或“暂停”图标）\n    \n3.  点击按钮（或使用快捷键 `Ctrl + F8` / `Cmd + F8`），禁用所有断点\n    \n\n> 此方法可以临时跳过所有断点，包括 `debugger` 语句。\n\n---\n\n### 方法二：覆盖 `debugger` 语句（控制台注入代码）\n\n由于 `debugger` 是语言关键字，不能直接覆盖。但可以尝试使用调试器忽略断点执行：\n\n1.  打开开发者工具\n    \n2.  在“Sources”面板找到触发 `debugger` 的脚本\n    \n3.  在 `debugger` 行号左侧点击，取消该行的断点\n    \n4.  或者右键选择“Never pause here”（Chrome）\n    \n\n---\n\n### 方法三：使用“黑盒脚本”功能（Blackboxing）\n\n**Chrome / Edge 支持此功能：**\n\n1.  打开开发者工具\n    \n2.  点击右上角“三个点”菜单 > “Settings”\n    \n3.  进入 “Debugger” 或 “Blackboxing” 选项卡\n    \n4.  添加你想忽略调试的脚本文件或使用正则匹配\n    \n5.  浏览器将不再在这些文件中暂停（包括 `debugger`）\n    \n\n> 适用于已知触发无限 `debugger` 的脚本文件路径。\n\n---\n\n### 方法四：使用浏览器扩展绕过\n\n可以使用浏览器插件来自动屏蔽某些脚本或修改网页行为：\n\n*   **Tampermonkey:** 自定义hook脚本\n    \n\n*   **uBlock Origin：**屏蔽特定脚本加载\n    \n*   **Debugger Auto Continue**：自动跳过断点\n    \n*   **AntiBebug Breaker**: 绕过无限Debugger\n    \n\n**示例：使用 Tampermonkey 脚本跳过** `**debugger**`\n\n```javascript\n// ==UserScript==\n// @name         Skip Debugger\n// @namespace    http://tampermonkey.net/\n// @version      1.0\n// @description  跳过无限 debugger\n// @author       You\n// @match        *://*/*\n// @grant        none\n// ==/UserScript==\n\n(function() {\n    'use strict';\n\n    // 覆盖 setInterval（可选）\n    const origSetInterval = window.setInterval;\n    window.setInterval = function(func, delay) {\n        if (func.toString().includes(\"debugger\")) {\n            console.log(\"Blocked setInterval with debugger\");\n            return null;\n        }\n        return origSetInterval.apply(this, arguments);\n    };\n\n    // 其他绕过方式可继续添加\n})();\n```\n---\n\n**示例：hook Function 原型构造函数， 修改debugger** \n\n```javascript\n\nFunction.prototype.temp_constructor= Function.prototype.constructor;\nFunction.prototype.constructor=function(){\n    if (arguments && typeof arguments[0]===\"string\"){\n        if (arguments[0]===\"debugger\")\n        return \"\"\n    }\n    return Function.prototype.temp_constructor.apply(this, arguments);\n};\n\n// hook setInterval 定时器函数 替换debugger\n_setInterval = setInterval\nsetInterval = function setInterval(code, time){\n    console.log(code, time)\n    code = code.toString().replace(/debugger/, \"\").replace(/function ()/, \"function xxx\")\n    return _setInterval(new Function(code) , time)\n}\n_setTimeout = setTimeout\nsetTimeout = function setTimeout(code, time){\n    console.log(code, time)\n    code = code.toString().replace(/debugger/, \"\").replace(/function ()/, \"function xxx\")\n    return _setTimeout(new Function(code), time)\n}\n\n```\n---\n\n### 方法五：使用火狐浏览器（推荐）\n\n使用新版firefox浏览器，选中debugger代码行，取消勾选【在调试语句上暂停】\n\n---\n\n## 五、总结\n\n| 方法 | 说明 | 适用场景 |\n| --- | --- | --- |\n| 禁用所有断点 | 快速跳过所有断点 | 临时调试 |\n| 黑盒脚本 | 忽略特定文件的调试行为 | 精确控制 |\n| 使用插件 | 自动屏蔽或跳过 | 高级用户 |\n| 注入脚本 | 定制化绕过逻辑 | Tampermonkey 用户 |\n| 火狐浏览器 | 在调试语句上暂停 | all in |\n\n---"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast.js",
    "content": "const parser = require(\"@babel/parser\");\nconst template = require(\"@babel/template\").default;\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\nconst fs = require(\"fs\");\nconst path = require('path');\n// lx.js 是被混淆的js文件\nvar jscode = fs.readFileSync(\"lx.js\", { encoding: \"utf-8\"});\n\nconst visitor_string = {\n    'StringLiteral|NumericLiteral'(path) {\n        delete path.node.extra\n    }\n};\n\nconst visitor_number = {\n    'UnaryExpression'(path) {\n        const {value} = path.evaluate();\n        switch (typeof value) {\n            case 'boolean':\n                path.replaceWith(t.BooleanLiteral(value))\n                break;\n            case 'string':\n                path.replaceWith(t.StringLiteral(value))\n                break;\n            case 'number':\n                path.replaceWith(t.NumericLiteral(value))\n                break;\n            default:\n                break;\n        }\n    }\n}\nconst visitor_function = {\n    MemberExpression(path) {\n        let property = path.get('property')\n        if (property.isStringLiteral()) {\n            let value = property.node.value;\n            path.node.computed = false\n            property.replaceWith(t.Identifier(value))\n        }\n    }\n};\nconst visitor_del_cons =\n    {\n        VariableDeclarator(path) {\n            const {id} = path.node;\n            const binding = path.scope.getBinding(id.name);\n            if (!binding || binding.constantViolations.length > 0) {\n                return;\n            }\n            if (binding.referencePaths.length === 0) {\n                path.remove();\n            }\n        },\n    }\n\nconst visitor_eval =\n    {\n        CallExpression(path)\n        {\n            let {callee,arguments} = path.node;\n            if (!t.isIdentifier(callee,{name:'eval'})) return;\n            if (arguments.length !== 1 || !t.isStringLiteral(arguments[0])) return;\n            let value = arguments[0].value;\n            path.replaceWith(t.Identifier(value));\n        },\n    }\n\n// 将JS源码转换成语法树\nlet ast = parser.parse(jscode);\ntraverse(ast, visitor_string);     //识别字符串\ntraverse(ast, visitor_number);     //计算表达式 !![] -> true\ntraverse(ast, visitor_function);   //将a[\"length\"]转为a.length\ntraverse(ast, visitor_del_cons);   //删除未被调用的变量\ntraverse(ast, visitor_eval);       //处理eval函数\nlet {code} = generator(ast, {jsescOption: {\"minimal\": true}});\nfs.writeFile('lx_decoded.js', code, (err) => {});"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/readme.md",
    "content": "补充部分的内容收集于网络，内容并未出现在书籍中，如有侵权请联系作者进行删除。\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/while-if转变为while-switch.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode =\n    `\nfunction test() {\n  var index = 0,\n      arr = [3, 0, 2, 1],\n      pindex;\n\n  while (1) {\n    pindex = arr[index++];\n\n    if (pindex < 1) {\n      console.log(\"this is index 0\");\n    } else if (pindex < 2) {\n      console.log(\"this is index 1\");\n      return;\n    } else if (pindex < 3) {\n      console.log(\"this is index 2\");\n    } else {\n      console.log(\"Hello world!\");\n    }\n  }\n}\n`;\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        \"WhileStatement\"(path) {\n            let {test, body} = path.node;\n\n            //******************************************************特征判断开始\n            if (!t.isNumericLiteral(test, {value: 1})) return;\n\n            let block_body = body.body;\n\n            if (block_body.length !== 2 || !t.isExpressionStatement(block_body[0]) || !t.isIfStatement(block_body[1])) {\n                return;\n            }\n            //******************************************************特征判断结束\n\n            let {left, right} = block_body[0].expression;\n            let name = left.name;\n\n            let if_arrs = [];\n            path.traverse({\n                \"IfStatement\"(_path) {\n\n                    let {test, consequent, alternate} = _path.node;\n\n                    let {left, operator, right} = test;\n\n                    if (!t.isIdentifier(left, {name: name}) || operator !== '<' || !t.isNumericLiteral(right)) return;\n\n                    if (consequent.body.length === 1) {\n                        if_arrs[right.value - 1] = consequent.body[0];\n                    } else {\n                        if_arrs[right.value - 1] = consequent;\n                    }\n\n                    if (!t.isIfStatement(alternate)) {\n                        if (consequent.body.length === 1) {\n                            if_arrs[right.value] = alternate.body[0];\n                        } else {\n                            if_arrs[right.value] = alternate;\n                        }\n                    }\n                },\n            })\n\n            if (if_arrs.length === 0) return;\n\n            for (var i = 0; i < if_arrs.length - 1; i++) {\n                consequent = [if_arrs[i], t.BreakStatement()];\n                if_arrs[i] = t.SwitchCase(test = t.NumericLiteral(i), consequent = consequent);\n            }\n\n            consequent = [if_arrs[if_arrs.length - 1], t.BreakStatement()];\n            if_arrs[i] = t.SwitchCase(test = null, consequent = consequent);\n\n            let new_node = t.SwitchStatement(right, if_arrs);\n\n            path.get('body.body.1').replaceInline(new_node);\n            path.get('body.body.0').remove();\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast, visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/三目运算符.js",
    "content": "/*\ndesc    : 把 a = m?11:22; 转成 m ? a = 11 : a = 22;\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"a = m ? 11 : 22;\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        ConditionalExpression(path){\n            let {test, consequent, alternate} = path.node;\n            const ParentPath = path.parentPath;\n            if(t.isAssignmentExpression(ParentPath)){\n                let {operator, left} = ParentPath.node;\n                if (operator === '='){\n                    consequent = t.AssignmentExpression('=', left, consequent);\n                    alternate = t.AssignmentExpression('=', left, alternate);\n                    ParentPath.replaceWith(t.ConditionalExpression(test, consequent, alternate))\n                }\n            }\n        }\n    }\n\n//some function code\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n/*\n\n1.节点类型变了，由 AssignmentExpression 类型变成了ConditionalExpression 类型。\n2.ConditionalExpression 子节点的 consequent 和 alternate 都变成了 AssignmentExpression 类型。\n\n*/\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/函数调用处自动替换计算值.js",
    "content": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"function add(a, b) {\\n\" +\n    \"  return a + b;\\n\" +\n    \"}\\n\" +\n    \"\\n\" +\n    \"let c = add(1, 2);\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        FunctionDeclaration(path) {\n            let {id} = path.node;\n            let code = path.toString();\n            if (code.indexOf(\"try\") !== -1 || code.indexOf(\"random\") !== -1 || code.indexOf(\"Date\") !== -1) {\n                // 不是纯函数，不处理\n                return\n            }\n\n            eval(code);\n\n            let scope = path.scope;\n            const binding = path.scope.parent.getBinding(id.name);\n\n            if (!binding || binding.constantViolations.length > 0) {\n                return\n            }\n\n            for (const refer_path of binding.referencePaths) {\n                // 查找父节点\n                let call_express = refer_path.findParent(p => p.isCallExpression());\n\n                let arguments = call_express.get(\"arguments\");\n                let args = [];\n\n                // 判断参数是否为 Literal 类型\n                arguments.forEach(arg => {\n                    args.push(arg.isLiteral())\n                })\n\n                // 自行编写判断条件，example\n                if (args.length === 0 || args.indexOf(false) !== -1) {\n                    continue\n                }\n\n                try {\n                    // 计算值\n                    let value = eval(call_express.toString());\n                    value && call_express.replaceWith(t.valueToNode(value));\n                } catch (e) {\n\n                }\n            }\n\n        }\n    }\n\n\n//some function code\n\n\ntraverse(ast, visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n\n/*\n1.函数需要满足在任意位置都能执行。就是一个函数声明的代码，随便拷贝到任意的地方都能直接运行，不会报错。说白了其实也就是函数体内的所有变量或者对象，其作用域只在函数体里面。\n2.定义的函数，对于实参是固定的，其结果也是固定的。请大家自行百度 纯函数 的概念\n3.实参必须是字面量，因为对于遍历的节点来说。只有是字面量，才能给你计算出具体的字，如果不是字面量，实参对它来说就是 undefined 的，是无法计算的。\n4.将函数定义eval到本地环境，然后根据作用域找到函数调用的位置。再eval该表达式即可。注意需要使用try...catch语句，避免错误。\n*/\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除多余的空行和空语句.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var a = 123;\\n\" +\n    \"\\n\" +\n    \";\\n\" +\n    \"\\n\" +\n    \"var b = 456;\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        EmptyStatement(path)\n        {\n            path.remove();\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除所有的代码注释.js",
    "content": "\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var a = 123; //this is single line comment\\n\" +\n    \"\\n\" +\n    \"/*\\n\" +\n    \"\\n\" +\n    \"This is a  multiline comments;\\n\" +\n    \"\\n\" +\n    \"test\\n\" +\n    \"\\n\" +\n    \"test\\n\" +\n    \"\\n\" +\n    \"test\\n\" +\n    \"\\n\" +\n    \"*/\\n\" +\n    \"\\n\" +\n    \"var b = 456;\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        //TODO  write your code here！\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast, {comments:false});\nconsole.log(code);\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被使用的变量.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var a = 123,b;\\n\" +\n    \"\\n\" +\n    \"let c = 4 + 5;\\n\" +\n    \"\\n\" +\n    \"d = a + 12;\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        VariableDeclarator(path) {\n\n            const {id} = path.node;\n            const binding = path.scope.getBinding(id.name);\n\n            //如果变量被修改过，则不能进行删除动作。\n            if (!binding || binding.constantViolations.length > 0) {\n                return;\n            }\n\n            //长度为0，说明变量没有被使用过。\n            if (binding.referencePaths.length === 0) {\n                path.remove();\n            }\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被调用的函数.js",
    "content": "const fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"function i()\\n\" +\n    \"\\n\" +\n    \"{\\n\" +\n    \"\\n\" +\n    \"    var i = 123;\\n\" +\n    \"\\n\" +\n    \"    i += 2;\\n\" +\n    \"\\n\" +\n    \"    \\n\" +\n    \"\\n\" +\n    \"  return 123;\\n\" +\n    \"\\n\" +\n    \"}\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        FunctionDeclaration(path) {\n            // path.scope.dump();\n\n            const {id} = path.node;\n            const binding = path.scope.parent.getBinding(id.name);\n\n            if (!binding || binding.constantViolations.length > 0) {\n                return;\n            }\n\n            if (binding.referencePaths.length === 0) {\n                path.remove();\n            }\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(for-switch).js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode =\n`\nfunction test() {\n  for (var index = 0; index != 5;) {\n    switch (index) {\n      case 0:\n        console.log(\"This is case-block 0\");\n        index = 3;\n        continue;\n\n      case 1:\n        console.log(\"This is case-block 1\");\n        return;\n        index = 5;\n        continue;\n\n      case 2:\n        console.log(\"This is case-block 2\");\n        index = 1;\n        continue;\n\n      case 3:\n        console.log(\"This is case-block 3\");\n        index = 4;\n        continue;\n\n      case 4:\n        console.log(\"This is case-block 4\");\n        index = 2;\n        continue;\n    }\n\n    break;\n  }\n}\n`;\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        ForStatement(path) {\n            //遍历for语句\n            const { init, update, test, body } = path.node;\n\n            //特征判断\n            if (\n                !t.isVariableDeclaration(init) ||\n                !t.isBinaryExpression(test) ||\n                update !== null\n            )\n                return;\n\n            let declaration = init.declarations[0];\n\n            //获取控制循环的变量及其初始值\n            const init_name = declaration.id.name;\n            let init_value = declaration.init.value;\n            let { left, right, operator } = test;\n\n            //特征判断\n            if (\n                !t.isIdentifier(left, { name: init_name }) ||\n                operator !== \"!=\" ||\n                !t.isNumericLiteral(right)\n            )\n                return;\n\n            let test_value = right.value;\n            let switch_body = body.body[0];\n\n            //特征判断\n            if (!t.isSwitchStatement(switch_body)) return;\n            let { discriminant, cases } = switch_body;\n\n            if (!t.isIdentifier(discriminant, { name: init_name })) return;\n            let ret_body = [];\n            let end_flag = false;\n\n            //不断的拿到控制循环的变量值\n            while (init_value !== test_value) {\n                //如果没有与之匹配的值，直接跳出循环\n                if (end_flag === true) {\n                    //如果遇到return语句，直接跳出循环\n                    break;\n                }\n\n                for (const each_case of cases) {\n                    let { test, consequent } = each_case;\n\n                    if (init_value !== test.value) {\n                        continue;\n                    }\n\n                    if (t.isContinueStatement(consequent[consequent.length - 1])) {\n                        //如果是continue语句，直接删除\n                        consequent.pop();\n                    }\n\n                    if (t.isExpressionStatement(consequent[consequent.length - 1])) {\n                        //如果是表达式语句，则判断是否包含控制循环的变量的赋值语句\n                        let { expression } = consequent[consequent.length - 1];\n                        if (t.isAssignmentExpression(expression)) {\n                            let { left, right, operator } = expression;\n                            if (t.isIdentifier(left, { name: init_name })) {\n                                //更新控制循环的变量值，并进行删除\n                                init_value = right.value;\n                                consequent.pop();\n                            }\n                        }\n                    }\n\n                    if (t.isReturnStatement(consequent[consequent.length - 1])) {\n                        end_flag = true;\n                    }\n                    ret_body = ret_body.concat(consequent);\n                    break;\n                }\n            }\n            path.replaceInline(ret_body);\n        }\n\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(while-switch).js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode =\n`\nvar arr = \"3|0|1|2|4\".split(\"|\");\nvar cnt = 0;\n\nwhile (true) {\n  switch (arr[cnt++]) {\n     case \"1\":\n      console.log(\"This is case-block 1\");\n      continue;\n      \n    case \"0\":\n      console.log(\"This is case-block 0\");\n      continue;\n\n    case \"2\":\n      console.log(\"This is case-block 2\");\n      continue;\n\n    case \"4\":\n      console.log(\"This is case-block 4\");\n      continue;\n      \n    case \"3\":\n      console.log(\"This is case-block 3\");\n      continue;\n  }\n\n  break;\n}\n`;\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        WhileStatement(path) {\n            const { test, body } = path.node;\n\n            //特征语句判断，视情况而定，也可以不判断\n            if (!t.isBooleanLiteral(test) || test.value !== true) return;\n\n            //特征语句判断，body.body[0] 必须是 SwitchStatement 节点，\n            //注意一定要先判断长度，避免index出错\n            if (body.body.length === 0 || !t.isSwitchStatement(body.body[0])) return;\n\n            let switch_state = body.body[0];\n\n            //获取discriminant及cases节点\n            let { discriminant, cases } = switch_state;\n\n            //特征语句判断，经过此判断后，基本可以确定是需要还原的while节点了。\n            //如果出错了，可以继续增加判断，直到不出错即可\n            if (!t.isMemberExpression(discriminant) || !t.isUpdateExpression(discriminant.property)) return;\n\n            //获取数组名，用于查找该数组。\n            let arr_name = discriminant.object.name;\n            let arr = [];\n\n            //在这里再加一个特征语句的判断：WhileStatement 节点前面有两个节点\n            let all_pre_siblings = path.getAllPrevSiblings();\n            if (all_pre_siblings.length !== 2) return;\n\n            all_pre_siblings.forEach((pre_path) => {\n                //虽然知道是第0个节点，但这里还是做下判断取arr\n                const { declarations } = pre_path.node;\n                let { id, init } = declarations[0];\n\n                if (arr_name === id.name) {\n                    //如果是定义arr的节点，拿到该arr的值\n                    arr = init.callee.object.value.split(\"|\");\n                }\n\n                //没啥用的语句可以直接删除\n                pre_path.remove();\n            });\n\n            //新建一个数组变量，用于存放 case 节点\n            let ret_body = [];\n\n            arr.forEach((index) => {\n                //遍历数组，去case节点\n                let case_body = [];\n                for (const tmp of cases){\n                    if(index === tmp.test.value){\n                        case_body = tmp.consequent;\n                        break;\n                    }\n                }\n\n                if (t.isContinueStatement(case_body[case_body.length - 1])) {\n                    //删除 continue语句\n                    case_body.pop();\n                }\n\n                //存放于数组变量中\n                ret_body = ret_body.concat(case_body);\n            });\n\n            //替换\n            path.replaceInline(ret_body);\n        }\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n\n/*\n去控制流(while-switch), 代码不通用，存在优化空间，\n比如将 case 做个键值对映射，这样直接取结果就比循环判断好一些\n */\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/合并定义在object对象外面的key、value.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode =\n`\nvar h = {};\nh[\"aaa\"] = \"hello wolrd\";\nh[\"bbb\"] = function (a,b)\n{\n   return a | b;\n}\n`;\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        VariableDeclarator(path)\n        {\n            const {id,init} = path.node;\n            if (!t.isObjectExpression(init)) return;\n            let name = id.name;\n            let properties = init.properties;\n            let all_next_siblings = path.parentPath.getAllNextSiblings();\n\n            for (let next_sibling of all_next_siblings)\n            {\n                if (!next_sibling.isExpressionStatement())  break;\n\n                let expression = next_sibling.get('expression');\n                if (!expression.isAssignmentExpression()) break;\n                let {operator,left,right} = expression.node;\n\n                if (operator !== '=' || !t.isMemberExpression(left) || !t.isIdentifier(left.object,{name:name}))\n                {\n                    break;\n                }\n                properties.push(t.ObjectProperty(left.property,right));\n                next_sibling.remove();\n            }\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n\n/*\n\n1.object对象使用var定义的，因此遍历 VariableDeclarator 节点即可\n2.依次判断后续节点，是否为定义在外面的key和value\n3.收集key和value，用于构造ObjectProperty 节点\n4. properties  属性是Array对象，只用push方法来增加节点\n5.处理完成后删除后续节点。\n\n */"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理eval函数.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"eval('var a = 123;');\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        CallExpression(path)\n        {\n            let {callee,arguments} = path.node;\n            if (!t.isIdentifier(callee,{name:'eval'})) return;\n            if (arguments.length !== 1 || !t.isStringLiteral(arguments[0])) return;\n            let value = arguments[0].value;\n            path.replaceWith(t.Identifier(value));\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的if语句.js",
    "content": "const fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\n// let jscode = \"if (true)\\n\" +\n//     \"{\\n\" +\n//     \"   //do something;\\n\" +\n//     \"  funcA();\\n\" +\n//     \"}\\n\" +\n//     \"else\\n\" +\n//     \"{\\n\" +\n//     \"   //do something;\\n\" +\n//     \"  funcB();\\n\" +\n//     \"}\";\n\nlet jscode = \"if ('123'==='123')\\n\" +\n    \"   a = 123;\\n\" +\n    \"else\\n\" +\n    \"  a = 456;\";\n\nlet ast = parse(jscode);\n\nconst visitor1 =\n    {\n        BinaryExpression(path) {\n            let {confident, value} = path.evaluate();\n            // console.log(path.type, confident, value)\n            if (confident) {\n                // console.log(path.node);\n                path.replaceInline(t.valueToNode(value))\n\n            }\n        }\n    }\n\nconst visitor2 =\n    {\n        IfStatement(path) {\n            let {test, consequent, alternate} = path.node;\n\n            if (!t.isBlockStatement(consequent)) {//添加中括号\n                path.node.consequent = t.BlockStatement([consequent]);\n            }\n\n            if (alternate !== null && !t.isBlockStatement(alternate)) {//添加中括号\n                path.node.alternate = t.BlockStatement([alternate]);\n            }\n\n            //特征判断，if语句里面的test是否为字面量\n            if (!t.isLiteral(test)) return;\n\n            let value = test.value;\n            consequent = path.node.consequent;\n            alternate = path.node.alternate;\n\n            if (value) {//替换\n                path.replaceInline(consequent.body);\n            } else {//替换\n                alternate === null ? path.remove() : path.replaceInline(alternate.body);\n            }\n        },\n    }\n\n//some function code\n\n\ntraverse(ast, visitor1);\ntraverse(ast, visitor2);\nlet {code} = generator(ast);\nconsole.log(code);\n\n/*\nif (true)\n//do something;\nelse\n//do something;\n\n与\nif (true)\n{\n    //do something;\n}\nelse\n{\n    //do something;\n}\n\n解析出来的结构会有小小的差异，不利于处理，因此先将上面的代码转变为下面的代码，再进行处理即可\n\n1.先将if语句块中没有 中括号的处理成 包含中括号的\n2.判断if条件里面的值，获取应该执行的语句块\n3.用语句块替换整个if表达式即可。\n\n*/\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的三元表达式.js",
    "content": "const fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"a = 5 ? 11 : 22;\\n\" +\n    \"b = 0 ? 33 : 44;\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        ConditionalExpression(path) {\n            let { test, consequent, alternate } = path.node;\n\n            if (!t.isLiteral(test)) return;\n\n            if (test.value) {\n                path.replaceInline(consequent);\n            } else {\n                path.replaceInline(alternate);\n            }\n        }\n    }\n\n//some function code\n\ntraverse(ast, visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n// 和常见表达式的计算类似"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理没有实参的自执行函数.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"!function () {\\n\" +\n    \"  a = 123;\\n\" +\n    \"}();\";\n\nlet ast = parse(jscode);\n\nconst visitor = {\n\n    UnaryExpression(path) {\n        const {operator, argument} = path.node;\n\n        if (operator !== \"!\" || !t.isCallExpression(argument)) return;\n\n        let {callee, arguments} = argument;\n\n        if (!t.isFunctionExpression(callee) || arguments.length !== 0) return;\n\n        path.replaceInline(callee.body.body);\n\n    },\n\n}\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/对同一节点使用多个方法.js",
    "content": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        CallExpression:\n            {// 注意顺序\n                enter: [reduce_call_express, delete_empty_params]\n            },\n    }\n\n\n//some function code\n\nfunction reduce_call_express(path) {\n}\n\nfunction delete_empty_params(path) {\n}\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n/*\n\n假设想对一个函数表达式的 CallExpression 节点进行进行实参还原，\n如果还原后，没有了实参和形参，假如又可以将函数体里面的代码提取出来。\n这个时候就需要两个方法来分别进行处理了\n\nreduce_call_express     还原函数的实参\ndelete_empty_params     将参数为空的函数进行处理，将函数体里面的代码直接提取出来\n\n*/"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/条件表达式拆分为if语句.js",
    "content": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode =\n`\nr ? r > 1 ? e.apply(t, arguments) : e.call(t, n) : e.call(t);\n`;\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        ConditionalExpression(path) {\n            let { test, consequent, alternate } = path.node;\n            const ParentPath = path.parentPath;\n            if (t.isExpressionStatement(ParentPath)) {\n                if (!t.isExpressionStatement(consequent)) {\n                    consequent = t.BlockStatement([t.ExpressionStatement(consequent)]);\n                }\n                if (!t.isExpressionStatement(alternate)) {\n                    alternate = t.BlockStatement([t.ExpressionStatement(alternate)]);\n                }\n                ParentPath.replaceInline(t.IfStatement(test, consequent, alternate));\n            }\n        }\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n/*\n\nr ? r > 1 ? e.apply(t, arguments) : e.call(t, n) : e.call(t);\n\n\nif (r) {\n  if (r > 1) {\n    e.apply(t, arguments);\n  } else {\n    e.call(t, n);\n  }\n} else {\n  e.call(t);\n}\n */"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/构造节点.js",
    "content": "/*\n* 将 var a; 转换为 var a = 123 + 456;\n*\n* */\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var a\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        // 方法一\n        VariableDeclarator(path){\n            const {init} = path.node;\n            let node = {\n                type: \"BinaryExpression\",\n                operator: \"+\",\n                left: {\n                    type: \"NumericLiteral\",\n                    value: 123,\n                },\n                right: {\n                    type: \"NumericLiteral\",\n                    value: 456,\n                }\n            }\n\n            init || path.set(\"init\", node)\n        },\n\n        // 方法二\n/*        VariableDeclarator(path){\n            const {init} = path.node;\n            init || path.set(\"init\", t.binaryExpression('+',t.valueToNode(123),t.valueToNode(456)))\n\n        },*/\n    }\n\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/节点类型转换.js",
    "content": "/*\ndesc    : 将 BinaryExpression 类型转换为 CallExpression 类型\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var a = 123 | 456;\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        \"VariableDeclarator\"(path)\n        {\n            const init_path = path.get('init');\n            if (!init_path.isBinaryExpression()) return\n\n            init_path.node.type = \"CallExpression\";\n            let {operator,left,right} = init_path.node;\n            init_path.node.arguments = [left,right];\n\n            let id = null;\n            let frist_arg  = t.Identifier('s');\n            let second_arg = t.Identifier('h');\n            let params = [frist_arg,second_arg];\n\n            let args = t.BinaryExpression(operator,frist_arg,second_arg);\n            let return_state = t.ReturnStatement(args);\n\n            let body = t.BlockStatement([return_state]);\n            init_path.node.callee = t.FunctionExpression(id ,params,body);\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原Array对象.js",
    "content": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var _2$SS = function (_SSz, _1111) {\\n\" +\n    \"    var _l1L1 = [46222, '\\x74\\x61\\x43\\x61\\x70\\x74\\x63\\x68\\x61\\x42\\x6c\\x6f\\x62', '\\x74', '\\x61', '\\x73', '\\x6c', '\\x64', '\\x69', .3834417654519915, '\\x65\\x6e\\x63\\x72\\x79\\x70\\x74\\x4a', '\\x73\\x6f', '\\x6e', 49344];\\n\" +\n    \"\\n\" +\n    \"    var _2Szs = _l1L1[5] + _l1L1[7] + (_l1L1[4] + _l1L1[2]),\\n\" +\n    \"        _I1il1 = _l1L1[9] + (_l1L1[10] + _l1L1[11]);\\n\" +\n    \"\\n\" +\n    \"    var _0ooQoO = _l1L1[0];\\n\" +\n    \"    var _$Z22 = _l1L1[12],\\n\" +\n    \"        _2sS2 = _l1L1[8];\\n\" +\n    \"    return _l1L1[6] + _l1L1[3] + _l1L1[1];\\n\" +\n    \"};\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        VariableDeclarator(path){\n            // 还原数组对象\n            const {id, init} = path.node;\n\n            // 非Array或者没有元素， 返回\n            if (!t.isArrayExpression(init) || init.elements.length===0) return;\n\n            let elements = init.elements;\n\n            // 获取binding实例\n            const binding = path.scope.getBinding(id.name);\n\n            for ( const ref_path of binding.referencePaths){\n                // 获取 MemberExpression 父节点\n                let member_path = ref_path.findParent(p=>p.isMemberExpression());\n                let property = member_path.get('property');\n\n                // 索引值不是 NumericLiteral 类型的不处理\n                if(!property.isNumericLiteral()){\n                    continue;\n                }\n\n                // 获取索引值\n                let index = property.node.value;\n\n                // 获取索引值对应的节点， 并替换\n                let arr_ele = elements[index];\n                member_path.replaceWith(arr_ele)\n            }\n        }\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原object对象.js",
    "content": "/*\ndate    : 2020/8/11\ndesc    : \n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var a = {\\n\" +\n    \"  \\\"YJJox\\\": \\\"object\\\",\\n\" +\n    \"  \\\"sbTga\\\": function (b, c) {\\n\" +\n    \"    return b | c;\\n\" +\n    \"  },\\n\" +\n    \"  \\\"iwvEK\\\": function (b, c) {\\n\" +\n    \"    return b << c;\\n\" +\n    \"  },\\n\" +\n    \"  \\\"HqkiD\\\": function (b, c) {\\n\" +\n    \"    return b(c);\\n\" +\n    \"  }\\n\" +\n    \"};\\n\" +\n    \"b = a[\\\"iwvEK\\\"](1, 3), c = a[\\\"sbTga\\\"](111, 222), d = a[\\\"YJJox\\\"], e = a[\\\"HqkiD\\\"](String.fromCharCode, 49);\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        VariableDeclarator(path) {\n            const {id, init} = path.node;\n\n            //特征判断，对象为空则不处理\n            if (!t.isObjectExpression(init) || init.properties.length === 0) return;\n\n            let name = id.name;\n            let scope = path.scope;\n\n            for (const property of init.properties) {//遍历key、value\n                let key = property.key.value;\n                let value = property.value;\n\n                //一般ob混淆，key长度都是5，也有是3的，自行调整即可。\n                if (key.length !== 5) return;\n\n                //如果是字面量\n                if (t.isLiteral(value)) {\n                    scope.traverse(scope.block, {\n                        //遍历MemberExpression，找出与key相同的表达式\n                        MemberExpression(_path) {\n                            let _node = _path.node;\n                            if (!t.isIdentifier(_node.object, {name: name})) return;\n                            if (!t.isLiteral(_node.property, {value: key})) return;\n                            _path.replaceWith(value);\n                        },\n                    })\n                }\n                //如果是函数表达式\n                else if (t.isFunctionExpression(value)) {\n                    let ret_state = value.body.body[0];\n\n                    //特征判断，如果不是return表达式\n                    if (!t.isReturnStatement(ret_state)) continue;\n\n                    scope.traverse(scope.block, {\n                        CallExpression: function (_path) {\n\n                            //遍历CallExpression\n                            let {callee, arguments} = _path.node;\n                            if (!t.isMemberExpression(callee)) return;\n                            if (!t.isIdentifier(callee.object, {name: name})) return;\n                            if (!t.isLiteral(callee.property, {value: key})) return;\n                            if (t.isCallExpression(ret_state.argument) && arguments.length > 0) {\n\n                                //构造节点\n                                _path.replaceWith(t.CallExpression(arguments[0], arguments.slice(1)));\n                            } else if (t.isBinaryExpression(ret_state.argument) && arguments.length === 2) {\n\n                                //构造节点\n                                let replace_node = t.BinaryExpression(ret_state.argument.operator, arguments[0], arguments[1]);\n                                _path.replaceWith(replace_node);\n                            } else if (t.isLogicalExpression(ret_state.argument) && arguments.length === 2) {\n\n                                //构造节点\n                                let replace_node = t.LogicalExpression(ret_state.argument.operator, arguments[0], arguments[1]);\n                                _path.replaceWith(replace_node);\n                            }\n                        }\n                    })\n                }\n            }\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n/*\n1.这里是 VariableDeclarator 节点，子节点 init 是 ObjectExpression 类型的表达式，因此我们可以遍历VariableDeclarator节点，便于获取 对象名 及整个对象\n2.遍历 ObjectExpression 节点的 properties 属性，它是一个 数组，遍历这个数组，获取key和value\n3.判断 value 的节点类型，如果是字面量，则可以直接进行替换；如果是函数表达式，则需要通过返回的表达式类型构造相应的表达式。然后在作用域块内遍历 MemberExpression (PS：a[\"sbTga\"]) 节点，如果是对象名，并且当前的key值也相等，则进行节点替换。\n4.遍历 properties 完毕后，可以试着删除整个  VariableDeclarator 节点，如果不报错就没事。\n*/\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原定义的字面量.js",
    "content": "/*\ndate    : 2020/8/11\ndesc    : \n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var s = 92;\\n\" +\n    \"b = Z(1324801, 92);\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        \"Identifier\"(path)\n        {\n            const {confident,value} = path.evaluate();\n            confident && path.replaceInline(t.valueToNode(value));\n        },\n\n        // 替换完了就没用了，将其删除\n        VariableDeclarator(path)\n        {\n            const {id,init} = path.node;\n\n            if (!t.isLiteral(init)) return;//只处理字面量\n\n            const binding = path.scope.getBinding(id.name);\n\n            if (!binding || binding.constantViolations.length > 0)\n            {//如果该变量的值被修改则不能处理\n                return;\n            }\n\n            for (const refer_path of binding.referencePaths)\n            {\n                refer_path.replaceWith(init);\n            }\n            path.remove();\n        },\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原成中文字符.js",
    "content": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"var s = \\\"\\u4f60\\u597d\\uff0c\\u4e16\\u754c;\\\"\\n\" +\n    \"var a = \\\"\\u0068\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0077\\u006f\\u0072\\u0064\\\";\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        StringLiteral(path)\n        {\n            path.get('extra').remove();\n        },\n    }\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast, {jsescOption:{\"minimal\":true}});\nconsole.log(code);\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原自执行函数的实参.js",
    "content": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst t = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode = \"!function (a, b) {\\n\" +\n    \"  c = a | b;\\n\" +\n    \"}(111, 222);\";\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        CallExpression(path){\n            let callee = path.get('callee');\n            let arguments = path.get('arguments');\n\n            if(!t.isFunctionExpression(callee) || arguments.length ===0){\n                // 实参的长度判断可以写死\n                return;\n            }\n\n            // 获取形参\n            let params = callee.get('params');\n            let scope = callee.scope;\n\n            for ( let i =0; i< arguments.length; i++){\n                // 遍历实参， 因为形参可能比实参长\n                let arg = params[i];\n                let {name} = arg.node;\n\n                const binding = scope.getBinding(name);\n\n                if(!binding || binding.constantViolations.length > 0){\n                    // 形参发生改变，不能被还原\n                    continue;\n                }\n\n                for(refer_path of binding.referencePaths){\n                    // 字面量可以直接替换\n                    refer_path.replaceWith(arguments[i]);\n                }\n\n                arg.remove();\n                arguments[i].remove();\n            }\n        }\n    }\n\n//some function code\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n// 替换完之后可以通过无参的自执行插件再替换"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/逗号表达式.js",
    "content": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;\nconst types = require(\"@babel/types\");\nconst generator = require(\"@babel/generator\").default;\n\nlet jscode =\n`\nb = (0,g.o)(a);\n\nc = (a=1,b=2,c=3,d=4,e=5,f);\n\nfunction get()\n{\n\treturn a=1,b=2,a +=2,a;\n}\n`;\n\nlet ast = parse(jscode);\n\nconst visitor =\n    {\n        SequenceExpression: {\n\t\t    exit(path){\n                let expressions = path.get('expressions');\n                let last_expression = expressions.pop();\n                \n                let statement = path.getStatementParent();\n                \n                if(statement){\n                    for(let expression of expressions)\n                    {\n                        // 删除无用的干扰代码\n                        if(expression.isLiteral() ||expression.isIdentifier())\n                        {\n                            expression.remove();\n                            continue;\n                        }\n                        statement.insertBefore(types.ExpressionStatement(expression=expression.node));\n                    }\n\t\t\t\t    path.replaceInline(last_expression);\n                }\n            }\n        }\n    }\n\n\n//some function code\n\n\ntraverse(ast,visitor);\nlet {code} = generator(ast);\nconsole.log(code);\n\n\n/*******************************************\nb = (0,g.o)(a);\n\nc = (a=1,b=2,c=3,d=4,e=5,f);\n\nfunction get()\n{\n\treturn a=1,b=2,a +=2,a;\n}\n\n===>\n\nb = g.o(a);\na = 1;\nb = 2;\nc = 3;\nd = 4;\ne = 5;\nc = f;\n\nfunction get() {\n  a = 1;\n  b = 2;\n  a += 2;\n  return a;\n}\n\n******************************************/\n"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/for_swith.js",
    "content": "const visitor =\n    {\n        ForStatement(path) {\n            const { init, update, test, body } = path.node;\n            if (\n                !t.isVariableDeclaration(init) ||\n                !t.isBinaryExpression(test) ||\n                update !== null\n            )\n                return;\n\n            let declaration = init.declarations[0];\n\n            const init_name = declaration.id.name;\n            let init_value = declaration.init.value;\n            let { left, right, operator } = test;\n            //判断特征\n            if (\n                !t.isIdentifier(left, { name: init_name }) ||\n                operator !== \"!=\" ||\n                !t.isNumericLiteral(right)\n            )\n                return;\n\n            let test_value = right.value;\n            let switch_body = body.body[0];\n\n            //判断特征\n            if (!t.isSwitchStatement(switch_body)) return;\n            let { discriminant, cases } = switch_body;\n\n            if (!t.isIdentifier(discriminant, { name: init_name })) return;\n            let ret_body = [];\n            let end_flag = false;\n\n            while (init_value !== test_value) {\n                if (end_flag === true) {\n                    break;\n                }\n\n                for (const each_case of cases) {\n                    let { test, consequent } = each_case;\n                    if (init_value !== test.value) {\n                        continue;\n                    }\n                    if (t.isContinueStatement(consequent[consequent.length - 1])) {\n                        consequent.pop();\n                    }\n                    if (t.isExpressionStatement(consequent[consequent.length - 1])) {\n                        let { expression } = consequent[consequent.length - 1];\n                        if (t.isAssignmentExpression(expression)) {\n                            let { left, right, operator } = expression;\n                            if (t.isIdentifier(left, { name: init_name })) {\n                                init_value = right.value;\n                                consequent.pop();\n                            }\n                        }\n                    }\n                    if (t.isReturnStatement(consequent[consequent.length - 1])) {\n                        end_flag = true;\n                    }\n                    ret_body = ret_body.concat(consequent);\n                    break;\n                }\n            }\n            path.replaceInline(ret_body);\n        }\n    }"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/lx.js",
    "content": "function test() {\n  for (var index = 0; index != 5;) {\n    switch (index) {\n      case 0:\n        console.log(\"This is case-block 0\");\n        index = 3;\n        continue;\n\n      case 1:\n        console.log(\"This is case-block 1\");\n        return;\n        index = 5;\n        continue;\n\n      case 2:\n        console.log(\"This is case-block 2\");\n        index = 1;\n        continue;\n\n      case 3:\n        console.log(\"This is case-block 3\");\n        index = 4;\n        continue;\n\n      case 4:\n        console.log(\"This is case-block 4\");\n        index = 2;\n        continue;\n    }\n    break;\n  }\n}"
  },
  {
    "path": "第三章：Web Js逆向/3.13 反混淆AST/readme.md",
    "content": "可能大家对ast不太理解，其实是通过生成语法树(AST)，可快速修改代码中的一些混淆处理，从而简化代码，便于后续分析。\n\n比如通过Python来把JS转为AST并进行简单的操作，内容很简单。\n\n\n\n比如我们下图中的JS代码，有sum和minus两个函数，一个变量a，两个换行\\n，以及一次sum函数的调用，参数为1和2。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ab7b48fbb46d4a6581082aeb4a6a60c8.png)\n\n\n通过pyjsparser库将script代码转换成为json-ast格式。\n\n\npyjsparser是目前用于 python 的最快和最易理解的 JavaScript 解析器。可将JavaScript翻译成Python，即在Python中运行JavaScript代码。\n\n\n\nimport pyjsparser\njs_ast = pyjsparser.parse(script)\n\n\n\n转换后用Json格式化工具打开。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/f909c4d84d7e4df79ffb228408ab72fa.png)\n\n  在body下的元素有这几种类型：\n          函数声明：FunctionDeclaration\n          空语句(\\n)：EmptyStatement\n          变量声明：VariableDeclaration\n          表达式语句：ExpressionStatement\n\n根据Json可看到FunctionDeclaration中有基本的函数名、参数名、参数类型、块语句和返回语句等。\n\n\n\n此外，表达式语句中还有调用表达式(CallExpression)、二元表达式(BinaryExpression)、赋值表达式(AssignmentExpression)等等。\n\n\n\n\n那么我们就可以通过这些Type，以修改Json对象的方式去操作这棵语法树。比如根据是否被调用去删除一些无用的对象，删除未调用的函数，或根据规则去替换一些结构，修改一些节点。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/3a2842229fc44be8aa512aae6b0830de.png)\n\n假如这是一段时间长并且难以阅读的代码，我们需要先将其转为AST，然后遍历所有函数，来查找未被调用的方法，然后进行删除，再根据AST转回正常的JS代码。\n\n\n\n```python\n# 完整代码如下，大家自己试试删除无用变量a吧！\n# js2py依赖于pyjsparser，所以安装js2py即可安装pyjsparser\n# pip install js2py\nscript = '''\n    function sum(a,b){  \n        c = minus(2,3)\n        return a+c;\n    };\n    \n    function minus(a2,b2){  \n        return a2-b2;\n    };\n    \n    function dddd(a2,b2){  \n        return a2-b2;\n    };\n    \n    var a = 123;\n    sum(1,2)\n'''\n\nimport pyjsparser\njs_ast = pyjsparser.parse(script)\n# 获取所有方法\nfuncList = []\nfor i in js_ast['body']:\n    if i['type'] =='FunctionDeclaration':\n        name = i['id']['name']\n        funcList.append(name)\n\n# 查找未被调用的方法\nnoCallList = []\nfor func in funcList:\n    searchStatement = \"{'type': 'CallExpression', 'callee': {'type': 'Identifier', 'name': '%s'}\"%func\n    if searchStatement not in str(js_ast):\n        noCallList.append(func)\n\n# 删除未调用的方法\nfor i in js_ast['body']:\n    if i['type'] =='FunctionDeclaration':\n        if i['id']['name'] in noCallList:\n            js_ast['body'].remove(i)\n\n#js_ast['body'][0]['id']['name'] = 'pythonlx'  # 修改一个函数名\n\n# 用AST重新生成js代码\nimport js2py.py_node_modules.escodegen as escodegen\nescodegen = escodegen.var.get('escodegen')\nres = escodegen.get('generate')(js_ast)\nprint(res.to_python()\n```\n\n\n\n执行后，可以发现未被调用的dddd方法已经被删除。\n\n代码很简单，大家试试如何删除无关变量a吧！\n\n本文牛刀小试，更多内容我们后续再见！\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/d046fa03df384dbda997bbb0fd01944d.png)"
  },
  {
    "path": "第三章：Web Js逆向/3.3 加密参数定位方法/3.3.7 注入和Hook/readme.md",
    "content": "参数定位工具的下载地址在代码库中。\n\n下载地址：https://pan.baidu.com/s/1OmMiE4rJrTNwarw3EJbz0A?pwd=thyl\n\n---\n\n下面是一些常用的Js Hook代码。\n\n## Hook setInterval\n```js\nlet _setInterval=setInterval;\n        setInterval=function(a,b){\n            if(a.toString().indexOf(\"debugger\")!=-1){\n                return null;\n            }\n            _setInterval(a,b);\n}        \n```\n\n\n## Hook header\n```js\nvar header_old = window.XMLHttpRequest.prototype.setRequestHeader;\nwindow.XMLHttpRequest.prototype.setRequestHeader = function (key, value) {\n    if (key=='k'){\n        console.log(key, value)\n        debugger;\n    }\n    if (key=='token'){\n        console.log(key, value)\n        debugger;\n    }\n    \n    return header_old.apply(this, arguments);\n}\n```\n\n\n## Hook Cookie Info\n\n\n```javascript\nvar cookie_cache = document.cookie;\n        Object.defineProperty(document, 'cookie', {\n            get: function() {\n                console.log('Getting cookie');\n                return cookie_cache;\n            },\n            set: function(val) {\n                console.log('Setting cookie', val);\n                var cookie = val.split(\";\")[0];\n                var ncookie = cookie.split(\"=\");\n                var flag = false;\n                var cache = cookie_cache.split(\"; \");\n                cache = cache.map(function(a){\n                    if (a.split(\"=\")[0] === ncookie[0]){\n                        flag = true;\n                        return cookie;\n                    }\n                    return a;\n                })\n                cookie_cache = cache.join(\"; \");\n                if (!flag){\n                    cookie_cache += cookie + \"; \";\n                }\n                this._value = val;\n                return cookie_cache;\n            },\n        });\n        \n```\n\n\n## Hook Json Info\n\n```javascript\nvar my_stringify = JSON.stringify;\n        JSON.stringify = function (params){\n            console.log(\"json_stringify:\", params);\n            return json_stringify(params);\n        };\n\n        var my_parse = JSON.parse;\n        JSON.parse = function (params){\n            console.log(\"json_parse:\", params);\n            return json_parse(params);\n        };\n        \n```\n\n## Hook WebSocket Info\n```javascript\nWebSocket.prototype.senda = WebSocket.prototype.send;\n        WebSocket.prototype.send = function (data){\n         console.info(\"Hook WebSocket\", data);\n         return this.senda(data)\n        }\n        \n```\n\n## Hook Cookie\n```js\n(function() {\n    'use strict';\n    var cookie_cache = document.cookie;\n    Object.defineProperty(document, 'cookie', {\n        get: function() {\n            // console.log(cookie_cache);\n            return cookie_cache;\n        },\n        set: function(val) {\n            if (val.indexOf('gdxidpyhxdE') != -1){\n                console.log('cookie',val)   \n                debugger;\n            }\n            var cookie = val.split(\";\")[0];\n            var ncookie = cookie.split(\"=\");\n            var flag = false;\n            var cache = cookie_cache.split(\";\");\n            cache = cache.map(function(a){\n                if (a.split(\"=\")[0] === ncookie[0]){\n                    flag = true;\n                    return cookie;\n                }\n                return a;\n            })\n            cookie_cache = cache.join(\";\");\n            if (!flag){\n                cookie_cache += cookie + \";\";\n            }\n        },\n    });\n\n})();\n\n```\n\n## Hook XHR\n\n```javascript\n// 代码作者：掘金tager\n// xhr中的方法拦截，eg: open、send etc.\nfunction hookFunction(funcName, config) {\n  return function () {\n    var args = Array.prototype.slice.call(arguments)\n    // 将open参数存入xhr, 在其它事件回调中可以获取到。\n    if (funcName === 'open') {\n      this.xhr.open_args = args\n    }\n    if (config[funcName]) {\n      console.log(this, 'this')\n      // 配置的函数执行结果返回为true时终止调用\n      var result = config[funcName].call(this, args, this.xhr)\n      if (result) return result;\n    }\n    return this.xhr[funcName].apply(this.xhr, arguments);\n  }\n}\n\n// xhr中的属性和事件的拦截\nfunction getterFactory(attr, config) {\n  return function () {\n    var value = this.hasOwnProperty(attr + \"_\") ? this[attr + \"_\"] : this.xhr[attr];\n    var getterHook = (config[attr] || {})[\"getter\"]\n    return getterHook && getterHook(value, this) || value\n  }\n}\n// 在赋值时触发该工厂函数（如onload等事件）\nfunction setterFactory(attr, config) {\n  return function (value) {\n    var _this = this;\n    var xhr = this.xhr;\n    var hook = config[attr]; // 方法或对象\n    this[attr + \"_\"] = value;\n    if (/^on/.test(attr)) {\n      // note：间接的在真实的xhr上给事件绑定函数\n      xhr[attr] = function (e) {\n        // e = configEvent(e, _this)\n        var result = hook && config[attr].call(_this, xhr, e)\n        result || value.call(_this, e);\n      }\n    } else {\n      var attrSetterHook = (hook || {})[\"setter\"]\n      value = attrSetterHook && attrSetterHook(value, _this) || value\n      try {\n        // 并非xhr的所有属性都是可写的\n        xhr[attr] = value;\n      } catch (e) {\n        console.warn('xhr的' + attr + '属性不可写')\n      }\n    }\n  }\n}\n\n// 核心拦截的handler\nfunction xhrHook(config) {\n  // 存储真实的xhr构造器, 在取消hook时，可恢复\n  window.realXhr = window.realXhr || XMLHttpRequest\n  // 重写XMLHttpRequest构造函数\n  XMLHttpRequest = function () {\n    var xhr = new window.realXhr()\n    // 真实的xhr实例存储到自定义的xhr属性中\n    this.xhr = xhr\n    // note: 遍历实例及其原型上的属性（实例和原型链上有相同属性时，取实例属性）\n    for (var attr in xhr) {\n      if (Object.prototype.toString.call(xhr[attr]) === '[object Function]') {\n        this[attr] = hookFunction(attr, config); // 接管xhr function\n      } else {\n        // attention: 如果重写XMLHttpRequest，必须要全部重写，否则在ajax中不会触发success、error（原因是3.x版本是在load事件中执行success）\n        Object.defineProperty(this, attr, { // 接管xhr attr、event\n          get: getterFactory(attr, config),\n          set: setterFactory(attr, config),\n          enumerable: true\n        })\n      }\n    }\n  }\n  return window.realXhr\n}\n\n// 解除xhr拦截，归还xhr管理权\nfunction unXhrHook() {\n  if (window[realXhr]) XMLHttpRequest = window[realXhr];\n  window[realXhr] = undefined;\n}\n\n// 执行部分\nxhrHook({\n  open: function (args, xhr) {\n    console.log(\"open called!\", args, xhr)\n     // return true // 返回true将终止请求，这个就是常规拦截的精髓了\n  },\n  setRequestHeader: function (args, xhr) {\n    console.log(\"setRequestHeader called!\", args, xhr)\n         },\n  onload: function (xhr) {\n    // 对响应结果做处理\n    this.responseText += ' tager'\n  }\n})\n\n```\n"
  },
  {
    "path": "第三章：Web Js逆向/3.3 加密参数定位方法/readme.md",
    "content": "目前主流的定位方法如下\n\n## 全局搜索\n适用于：参数名是固定字符串（如`sign`、`token`、`timestamp`、`nonce`），且未被混淆的场景。\n\n**操作步骤**：\n\n1.  打开浏览器开发者工具（F12）→ 切换到`Sources`面板 → 点击左侧搜索图标（Ctrl+Shift+F）；\n    \n2.  输入目标参数名（如`sign`），选择 “Search in all files”；\n    \n3.  分析搜索结果：\n    \n    *   优先看`=` 、`:` 、`push`、`append`等赋值 / 拼接逻辑（如`data.sign = xxx`、`params['sign'] = xxx`）；\n        \n    *   排除纯注释、日志打印、无关引用的结果；\n        \n    \n4.  实战技巧：\n    \n    *   若参数名被混淆（如`s`、`_0x123`），可先搜索参数值的特征（比如参数值是 32 位 md5，可搜`md5`、`hash`、`hex`）；\n        \n    *   搜索时加通配符，如`sign*=`、`*sign:`，缩小范围。\n        \n    *   加解密可以搜 encrypt、decrypt等关键字。\n\n\n## XHR追踪\n仅适用于：参数出现在 AJAX 请求（XHR/Fetch）中，想知道请求发送前参数是怎么组装的。\n\n## 堆栈调试\n适用于：参数由函数调用生成（如sign = generateSign()），想找到generateSign的定义。\n\n## Hook拦截\n见hook脚本\n\n## DOM断点\n\n在特定场景下极其好用的方法 —— 尤其当参数生成和**DOM 操作（点击、输入、元素变化）**强相关时，Elements 断点能精准捕捉到触发参数生成的交互逻辑。\n\n### 适用场景\n\nElements 断点不是通用型方法，但在以下场景中能解决其他方法搞不定的问题：\n\n*   参数由 DOM 交互触发生成（比如点击 “登录” 按钮、输入验证码后生成`sign`参数）；\n    \n*   参数生成逻辑绑定在 DOM 事件上（如`onclick`、`onchange`、`onsubmit`）；\n    \n*   页面通过动态修改 DOM（如添加 / 删除节点、修改属性）触发参数组装；\n    \n*   想找到 “点击按钮后→参数生成→发送请求” 的完整链路。\n    \n\n### 断点类型\n\n**Break on subtree modifications:** 目标元素的子节点被添加 / 删除 / 修改时触发\n\n**Break on attribute modifications:** 目标元素的属性（如`value`、`data-sign`、`class`）被修改时触发\n\n**Break on node removal:** 目标元素被从 DOM 树中移除时触发\n\n### 避坑点\n\n1.  **避免过度使用**：仅在参数和 DOM 交互相关时使用，否则会触发大量无关断点（比如页面频繁渲染 DOM）；\n    \n2.  **区分事件类型**：点击按钮优先看`click`事件，输入内容优先看`input`/`change`事件；\n    \n3.  **处理异步逻辑**：若参数在事件回调的异步函数中生成（如`setTimeout`、`Promise`），断住后需在调用栈中找异步回调的入口；\n    \n4.  **注意影子 DOM**：部分页面使用 Shadow DOM（如 Vue/React 的组件），需在 Elements 面板开启 “Show user agent shadow DOM”（设置→Preferences→Elements），才能看到完整 DOM 结构。\n    \n\n## 进阶技巧\n\n技巧 1：结合 Event Listeners 面板\n\n断住后，在 Elements 面板右侧找到`Event Listeners`（事件监听器）：\n\n*   筛选目标元素绑定的事件（如`click`、`change`）；\n    \n*   点击事件后的 “↗” 箭头，直接跳转到事件处理函数的定义位置，快速定位参数生成逻辑。\n    \n\n技巧 2：处理动态绑定的事件\n\n若事件是通过`addEventListener`动态绑定（而非`onclick`属性）：\n\n1.  添加 Elements 断点断住后；\n    \n2.  在调用栈中找`dispatchEvent`、`addEventListener`相关的函数；\n    \n3.  向上回溯，找到事件回调函数，即为参数生成的入口。\n    \n\n技巧 3：配合条件过滤\n\n若 DOM 频繁变化导致断点触发过多：\n\n1.  右键断点→`Edit condition`；\n    \n2.  输入条件（如`attrName === 'data-sign'`），仅当修改`data-sign`属性时才断住，减少无效断点。\n\n\n## 内存定位\n\n\n### 内存漫游助手 ast-hook-for-js-RE\n\n聚焦「执行前 AST 语法树」: https://github.com/JSREI/ast-hook-for-js-RE\n\nast-hook-for-js-RE（AST 钩子工具）是基于抽象语法树（AST）拦截 的 JS 逆向工具，核心逻辑是：在 JS 代码被 V8 引擎编译执行前，先解析成 AST 语法树，通过修改 / 挂钩 AST 节点（如函数调用、变量赋值、加密 API 调用），实现对加密逻辑的拦截、篡改或还原。\n\n它的核心依赖是 `esprima`（AST 解析）、`estraverse`（AST 遍历）、`escodegen`（AST 还原代码），以及 `frida`（跨平台挂钩），是 JS 逆向中「静态 + 动态结合」的典型工具。\n\n**关键特点**：\n\n*   「前置拦截」：代码还没执行，就先修改语法树，比如把`CryptoJS.encrypt`替换成自定义函数，执行时直接拿到明文参数；\n    \n*   「后置读取」：代码已经执行，内存中已有完整的执行上下文，只能读取数据，无法修改已执行的逻辑；\n    \n\n*   「数据提取」：核心目标是拿到运行时的真实数据（比如混淆代码执行后内存中的密钥），而非修改逻辑；\n    \n\n### 推理算法助手 help\\_tool\n\n[https://gitcode.com/gh\\_mirrors/he/help\\_tool](https://gitcode.com/gh_mirrors/he/help_tool)\n\n一款专为加密分析设计的工具，能够帮助用户快速识别和推测出使用的加密算法类型，并尝试解密出明文。\n\n推理算法助手（help\\_tool）的核心实现原理围绕**加密算法特征识别、进程内存分析、模型辅助推理**三大核心逻辑展开，结合逆向工程实战场景需求，实现加密算法自动识别与明文还原。\n\n工具内置了主流加密算法（哈希、对称加密、非对称加密）的**特征规则库**，通过分析输入密文的格式、长度、编码特征，初步筛选候选算法。通过**预训练的特征模型**捕捉加密算法的深层特征（而非仅依赖规则），尤其适用于密文格式不标准、部分参数未知（如密钥、IV）的场景。\n\n![image.png](https://i-blog.csdnimg.cn/img_convert/5eb21b2203d04fb474f8fc84a8691eae.png)\n\n\n### 通俗化理解（友好版）\n\n1.  **推理算法助手**：像「密码破译专家」—— 你给它密文，它通过特征库匹配、扒进程内存，告诉你 “这是 AES 加密，明文是 XXX”，核心是「从密文倒推算法和明文」，不干涉代码执行，只看最终结果。\n    \n2.  **ast-hook-for-js-RE**：像「代码执行前的安检员」——JS 代码还没跑起来，先把代码拆成 AST 语法树，你可以挂钩加密函数、篡改参数，甚至让加密逻辑失效，核心是「主动控制代码怎么执行」。\n"
  },
  {
    "path": "第三章：Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/readme.md",
    "content": "新增webpack逆向的案例\n\n案例地址：https://space.bilibili.com/390499740\n\n\n可以用于webpack解包，代码格式化、反混淆的在线站点\nhttps://webcrack.netlify.app/"
  },
  {
    "path": "第三章：Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/webpack-export.js",
    "content": "var lx;\n!function (e){\n    var report = {};\n    function o(n){\n        if (report[n])\n            return report[n].exports;\n        var t = report[n] = {\n            i:n,\n            l:!1,\n            exports:{}\n        };\n        return e[n].call(t.exports,t,t.exports,o),\n        t.l = !0,\n        t.exports\n    }\n    lx = o;\n}({\n    // 添加webpack模块\n    // \"method\":function(e){}\n});\n// 调用模块函数\n// var t = lx(\"method\");"
  },
  {
    "path": "第三章：Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例一.js",
    "content": "// 贝壳网登录的webpack逆向案例\nwindow = {}\nwindow.location = {\n    href:'https://zz.ke.com/?utm_source=baidu&utm_medium=pinzhuan&utm_term=biaoti&utm_content=biaotimiaoshu&utm_campaign=wyzhengzhou'\n}\ndocument = {\n}\nvar aaa;\nvar ddd;\nnavigator = {\n  appName:\"Netscape\"\n}\n\n!function(n) {\n    var r = {};\n    function i(t) {\n        if (r[t])\n            return r[t].exports;\n        var e = r[t] = {\n            i: t,\n            l: !1,\n            exports: {}\n        };\n        return n[t].call(e.exports, e, e.exports, i),\n        e.l = !0,\n        e.exports\n    }\n    i.m = n,\n    i.c = r,\n    i.d = function(t, e, n) {\n        i.o(t, e) || Object.defineProperty(t, e, {\n            enumerable: !0,\n            get: n\n        })\n    }\n    ,\n    i.r = function(t) {\n        \"undefined\" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, {\n            value: \"Module\"\n        }),\n        Object.defineProperty(t, \"__esModule\", {\n            value: !0\n        })\n    }\n    ,\n    i.t = function(e, t) {\n        if (1 & t && (e = i(e)),\n        8 & t)\n            return e;\n        if (4 & t && \"object\" == typeof e && e && e.__esModule)\n            return e;\n        var n = Object.create(null);\n        if (i.r(n),\n        Object.defineProperty(n, \"default\", {\n            enumerable: !0,\n            value: e\n        }),\n        2 & t && \"string\" != typeof e)\n            for (var r in e)\n                i.d(n, r, function(t) {\n                    return e[t]\n                }\n                .bind(null, r));\n        return n\n    }\n    ,\n    i.n = function(t) {\n        var e = t && t.__esModule ? function() {\n            return t.default\n        }\n        : function() {\n            return t\n        }\n        ;\n        return i.d(e, \"a\", e),\n        e\n    }\n    ,\n    i.o = function(t, e) {\n        return Object.prototype.hasOwnProperty.call(t, e)\n    }\n    ,\n    i.p = \"/\";\n    //i(i.s = 50);\n    aaa = i;\n}(\n  {\n       50:function(t, e, n) {\n        \"use strict\";\n        n.r(e);\n        function r(t) {\n            var o = this;\n            this.refreshTicket = function () {\n                o.getTicket(),\n                o.interval && clearInterval(o.interval),\n                    o.interval = setInterval(function () {\n                        o.getTicket()\n                    }, 6e5)\n            }\n                ,\n                this.getTicket = function () {\n                    var t = {\n                        service: o.service,\n                        version: o.serviceVersion\n                    };\n                    return new Promise(function (n) {\n                            Object(l.fetch)({\n                                url: \"\" + o.domain + u.APIEndpoint.init,\n                                method: \"POST\",\n                                data: t\n                            }).then(function (t) {\n                                if (n(),\n                                    t.data.success) {\n                                    var e = t.data.publicKey.key;\n                                    o.ec.setPublicKey(e),\n                                        o.loginTicketId = t.data.loginTicketId,\n                                        o.publicKey = e,\n                                        o.encodeVersion = t.data.publicKey.version\n                                } else\n                                    Object(c.sendFee)({\n                                        detail: t,\n                                        errorName: \"passport-init-error\"\n                                    })\n                            })\n                        }\n                    )\n                }\n                ,\n                this.getRiskInfo = function (t) {\n                    var e = {\n                        name: \"\",\n                        version: \"\"\n                    }\n                        , n = \"\";\n                    try {\n                        var r = new a.a;\n                        e = r.getOS(),\n                            n = r.getUA()\n                    } catch (t) {\n                        Object(c.sendFee)({\n                            detail: {\n                                error: t\n                            },\n                            errorName: \"ua-parser-error\"\n                        })\n                    }\n                    var i = {\n                        ua: n,\n                        clientSource: \"pc\",\n                        os: e.name,\n                        osVersion: e.version\n                    };\n                    return Object.assign({}, i, t)\n                }\n                ,\n                this.passwordLogin = function (t, e) {\n                    t.encodeVersion = o.encodeVersion;\n                    var n = {};\n                    e.clickPos && (n = o.getRiskInfo(Object.assign({}, e.clickPos))),\n                    o.publicKey && (t.password = o.ec.encrypt(t.password));\n                    var r = {\n                        service: o.service,\n                        mainAuthMethodName: u.mainAuthMethodName.PASSWORD,\n                        accountSystem: o.accountSystem,\n                        credential: t,\n                        context: Object.assign({}, n),\n                        loginTicketId: o.loginTicketId,\n                        version: o.serviceVersion\n                    };\n                    return window.srcId && (r.srcId = window.srcId),\n                    t.code && (r.mfaAuthMethodName = u.allianceMethods.security),\n                    e.ticketMaxAge && (r.ticketMaxAge = e.ticketMaxAge),\n                        new Promise(function (e, n) {\n                                Object(l.fetch)({\n                                    url: \"\" + o.domain + u.APIEndpoint.auth,\n                                    method: \"POST\",\n                                    data: r\n                                }).then(function (t) {\n                                    e(t),\n                                        o.sign = t.data.sign,\n                                        o.tgt = t.data.serviceTicket.id\n                                }).catch(function (t) {\n                                    Object(c.sendFee)({\n                                        detail: {\n                                            error: t,\n                                            data: r\n                                        },\n                                        errorName: \"passport-auth-error\"\n                                    }),\n                                        n(t)\n                                })\n                            }\n                        )\n                }\n                ,\n                this.register = function (t, e) {\n                    t.encodeVersion = o.encodeVersion;\n                    var n = {};\n                    e.clickPos && (n = o.getRiskInfo(Object.assign({}, e.clickPos))),\n                    o.publicKey && (t.password = o.ec.encrypt(t.password));\n                    var r = {\n                        service: o.service,\n                        accountSystem: o.accountSystem,\n                        context: Object.assign({}, n),\n                        displayName: Object(l.maskPhoneNumber)(t.phoneNum),\n                        registerMethodName: \"security-code\",\n                        credential: t\n                    };\n                    return window.srcId && (r.srcId = window.srcId),\n                        new Promise(function (e, n) {\n                                Object(l.fetch)({\n                                    url: \"\" + o.domain + u.APIEndpoint.register,\n                                    method: \"POST\",\n                                    data: r\n                                }).then(function (t) {\n                                    e(t)\n                                }).catch(function (t) {\n                                    Object(c.sendFee)({\n                                        detail: {\n                                            error: t,\n                                            data: r\n                                        },\n                                        errorName: \"passport-register-error\"\n                                    }),\n                                        n(t)\n                                })\n                            }\n                        )\n                }\n                ,\n                this.logout = function (r) {\n                    return new Promise(function (e, n) {\n                            Object(l.fetch)({\n                                url: \"\" + o.domain + u.APIEndpoint.logout,\n                                method: \"POST\",\n                                data: {\n                                    context: {\n                                        sign: r && r.context && r.context.sign ? r.context.sign : o.sign\n                                    },\n                                    tgt: r && r.tgt ? r.tgt : o.tgt\n                                }\n                            }).then(function (t) {\n                                e(t)\n                            }).catch(function (t) {\n                                Object(c.sendFee)({\n                                    detail: {\n                                        error: t,\n                                        data: {\n                                            service: o.service,\n                                            tgt: r && r.tgt ? r.tgt : o.tgt\n                                        }\n                                    },\n                                    errorName: \"passport-logout-error\"\n                                }),\n                                    n(t)\n                            })\n                        }\n                    )\n                }\n                ,\n                this.ec = new s.a,\n                ddd = this;\n                this.loginTicketId = \"\";\n                this.publicKey = \"\";\n                this.encodeVersion = \"\";\n                this.sign = \"\";\n                this.tgt = \"\";\n        }\n        var i = n(5)\n          , s = n.n(i)\n          , o = n(19)\n          , a = n.n(o)\n          , c = n(2)\n          , u = n(0)\n          , l = n(1)\n          , h = function(t, s, a, c) {\n            return new (a = a || Promise)(function(e, n) {\n                function r(t) {\n                    try {\n                        o(c.next(t))\n                    } catch (t) {\n                        n(t)\n                    }\n                }\n                function i(t) {\n                    try {\n                        o(c.throw(t))\n                    } catch (t) {\n                        n(t)\n                    }\n                }\n                function o(t) {\n                    t.done ? e(t.value) : function(e) {\n                        return e instanceof a ? e : new a(function(t) {\n                            t(e)\n                        }\n                        )\n                    }(t.value).then(r, i)\n                }\n                o((c = c.apply(t, s || [])).next())\n            }\n            )\n        }\n          , f = function(n, r) {\n            var i, o, s, t, a = {\n                label: 0,\n                sent: function() {\n                    if (1 & s[0])\n                        throw s[1];\n                    return s[1]\n                },\n                trys: [],\n                ops: []\n            };\n            return t = {\n                next: e(0),\n                throw: e(1),\n                return: e(2)\n            },\n            \"function\" == typeof Symbol && (t[Symbol.iterator] = function() {\n                return this\n            }\n            ),\n            t;\n            function e(e) {\n                return function(t) {\n                    return function(e) {\n                        if (i)\n                            throw new TypeError(\"Generator is already executing.\");\n                        for (; a; )\n                            try {\n                                if (i = 1,\n                                o && (s = 2 & e[0] ? o.return : e[0] ? o.throw || ((s = o.return) && s.call(o),\n                                0) : o.next) && !(s = s.call(o, e[1])).done)\n                                    return s;\n                                switch (o = 0,\n                                s && (e = [2 & e[0], s.value]),\n                                e[0]) {\n                                case 0:\n                                case 1:\n                                    s = e;\n                                    break;\n                                case 4:\n                                    return a.label++,\n                                    {\n                                        value: e[1],\n                                        done: !1\n                                    };\n                                case 5:\n                                    a.label++,\n                                    o = e[1],\n                                    e = [0];\n                                    continue;\n                                case 7:\n                                    e = a.ops.pop(),\n                                    a.trys.pop();\n                                    continue;\n                                default:\n                                    if (!(s = 0 < (s = a.trys).length && s[s.length - 1]) && (6 === e[0] || 2 === e[0])) {\n                                        a = 0;\n                                        continue\n                                    }\n                                    if (3 === e[0] && (!s || e[1] > s[0] && e[1] < s[3])) {\n                                        a.label = e[1];\n                                        break\n                                    }\n                                    if (6 === e[0] && a.label < s[1]) {\n                                        a.label = s[1],\n                                        s = e;\n                                        break\n                                    }\n                                    if (s && a.label < s[2]) {\n                                        a.label = s[2],\n                                        a.ops.push(e);\n                                        break\n                                    }\n                                    s[2] && a.ops.pop(),\n                                    a.trys.pop();\n                                    continue\n                                }\n                                e = r.call(n, a)\n                            } catch (t) {\n                                e = [6, t],\n                                o = 0\n                            } finally {\n                                i = s = 0\n                            }\n                        if (5 & e[0])\n                            throw e[1];\n                        return {\n                            value: e[0] ? e[1] : void 0,\n                            done: !0\n                        }\n                    }([e, t])\n                }\n            }\n        };\n        e.default = r\n    },\n       5 :function(t, e, n) {\n        !function(t) {\n            \"use strict\";\n            var e = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n            function c(t) {\n                return e.charAt(t)\n            }\n            function n(t, e) {\n                return t & e\n            }\n            function u(t, e) {\n                return t | e\n            }\n            function r(t, e) {\n                return t ^ e\n            }\n            function i(t, e) {\n                return t & ~e\n            }\n            function o(t) {\n                if (0 == t)\n                    return -1;\n                var e = 0;\n                return 0 == (65535 & t) && (t >>= 16,\n                e += 16),\n                0 == (255 & t) && (t >>= 8,\n                e += 8),\n                0 == (15 & t) && (t >>= 4,\n                e += 4),\n                0 == (3 & t) && (t >>= 2,\n                e += 2),\n                0 == (1 & t) && ++e,\n                e\n            }\n            function s(t) {\n                for (var e = 0; 0 != t; )\n                    t &= t - 1,\n                    ++e;\n                return e\n            }\n            var a = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n            function l(t) {\n                var e, n, r = \"\";\n                for (e = 0; e + 3 <= t.length; e += 3)\n                    n = parseInt(t.substring(e, e + 3), 16),\n                    r += a.charAt(n >> 6) + a.charAt(63 & n);\n                for (e + 1 == t.length ? (n = parseInt(t.substring(e, e + 1), 16),\n                r += a.charAt(n << 2)) : e + 2 == t.length && (n = parseInt(t.substring(e, e + 2), 16),\n                r += a.charAt(n >> 2) + a.charAt((3 & n) << 4)); 0 < (3 & r.length); )\n                    r += \"=\";\n                return r\n            }\n            function h(t) {\n                var e, n = \"\", r = 0, i = 0;\n                for (e = 0; e < t.length && \"=\" != t.charAt(e); ++e) {\n                    var o = a.indexOf(t.charAt(e));\n                    o < 0 || (r = 0 == r ? (n += c(o >> 2),\n                    i = 3 & o,\n                    1) : 1 == r ? (n += c(i << 2 | o >> 4),\n                    i = 15 & o,\n                    2) : 2 == r ? (n += c(i),\n                    n += c(o >> 2),\n                    i = 3 & o,\n                    3) : (n += c(i << 2 | o >> 4),\n                    n += c(15 & o),\n                    0))\n                }\n                return 1 == r && (n += c(i << 2)),\n                n\n            }\n            var f, d = function(t, e) {\n                return (d = Object.setPrototypeOf || {\n                    __proto__: []\n                }instanceof Array && function(t, e) {\n                    t.__proto__ = e\n                }\n                || function(t, e) {\n                    for (var n in e)\n                        e.hasOwnProperty(n) && (t[n] = e[n])\n                }\n                )(t, e)\n            };\n            var p, g = {\n                decode: function(t) {\n                    var e;\n                    if (void 0 === f) {\n                        var n = \"0123456789ABCDEF\"\n                          , r = \" \\f\\n\\r\\t \\u2028\\u2029\";\n                        for (f = {},\n                        e = 0; e < 16; ++e)\n                            f[n.charAt(e)] = e;\n                        for (n = n.toLowerCase(),\n                        e = 10; e < 16; ++e)\n                            f[n.charAt(e)] = e;\n                        for (e = 0; e < r.length; ++e)\n                            f[r.charAt(e)] = -1\n                    }\n                    var i = []\n                      , o = 0\n                      , s = 0;\n                    for (e = 0; e < t.length; ++e) {\n                        var a = t.charAt(e);\n                        if (\"=\" == a)\n                            break;\n                        if (-1 != (a = f[a])) {\n                            if (void 0 === a)\n                                throw new Error(\"Illegal character at offset \" + e);\n                            o |= a,\n                            2 <= ++s ? (i[i.length] = o,\n                            s = o = 0) : o <<= 4\n                        }\n                    }\n                    if (s)\n                        throw new Error(\"Hex encoding incomplete: 4 bits missing\");\n                    return i\n                }\n            }, m = {\n                decode: function(t) {\n                    var e;\n                    if (void 0 === p) {\n                        var n = \"= \\f\\n\\r\\t \\u2028\\u2029\";\n                        for (p = Object.create(null),\n                        e = 0; e < 64; ++e)\n                            p[\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".charAt(e)] = e;\n                        for (e = 0; e < n.length; ++e)\n                            p[n.charAt(e)] = -1\n                    }\n                    var r = []\n                      , i = 0\n                      , o = 0;\n                    for (e = 0; e < t.length; ++e) {\n                        var s = t.charAt(e);\n                        if (\"=\" == s)\n                            break;\n                        if (-1 != (s = p[s])) {\n                            if (void 0 === s)\n                                throw new Error(\"Illegal character at offset \" + e);\n                            i |= s,\n                            4 <= ++o ? (r[r.length] = i >> 16,\n                            r[r.length] = i >> 8 & 255,\n                            r[r.length] = 255 & i,\n                            o = i = 0) : i <<= 6\n                        }\n                    }\n                    switch (o) {\n                    case 1:\n                        throw new Error(\"Base64 encoding incomplete: at least 2 bits missing\");\n                    case 2:\n                        r[r.length] = i >> 10;\n                        break;\n                    case 3:\n                        r[r.length] = i >> 16,\n                        r[r.length] = i >> 8 & 255\n                    }\n                    return r\n                },\n                re: /-----BEGIN [^-]+-----([A-Za-z0-9+\\/=\\s]+)-----END [^-]+-----|begin-base64[^\\n]+\\n([A-Za-z0-9+\\/=\\s]+)====/,\n                unarmor: function(t) {\n                    var e = m.re.exec(t);\n                    if (e)\n                        if (e[1])\n                            t = e[1];\n                        else {\n                            if (!e[2])\n                                throw new Error(\"RegExp out of sync\");\n                            t = e[2]\n                        }\n                    return m.decode(t)\n                }\n            }, v = 1e13, y = function() {\n                function t(t) {\n                    this.buf = [+t || 0]\n                }\n                return t.prototype.mulAdd = function(t, e) {\n                    var n, r, i = this.buf, o = i.length;\n                    for (n = 0; n < o; ++n)\n                        (r = i[n] * t + e) < v ? e = 0 : r -= (e = 0 | r / v) * v,\n                        i[n] = r;\n                    0 < e && (i[n] = e)\n                }\n                ,\n                t.prototype.sub = function(t) {\n                    var e, n, r = this.buf, i = r.length;\n                    for (e = 0; e < i; ++e)\n                        n = r[e] - t,\n                        t = n < 0 ? (n += v,\n                        1) : 0,\n                        r[e] = n;\n                    for (; 0 === r[r.length - 1]; )\n                        r.pop()\n                }\n                ,\n                t.prototype.toString = function(t) {\n                    if (10 != (t || 10))\n                        throw new Error(\"only base 10 is supported\");\n                    for (var e = this.buf, n = e[e.length - 1].toString(), r = e.length - 2; 0 <= r; --r)\n                        n += (v + e[r]).toString().substring(1);\n                    return n\n                }\n                ,\n                t.prototype.valueOf = function() {\n                    for (var t = this.buf, e = 0, n = t.length - 1; 0 <= n; --n)\n                        e = e * v + t[n];\n                    return e\n                }\n                ,\n                t.prototype.simplify = function() {\n                    var t = this.buf;\n                    return 1 == t.length ? t[0] : this\n                }\n                ,\n                t\n            }(), b = \"…\", w = /^(\\d\\d)(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])([01]\\d|2[0-3])(?:([0-5]\\d)(?:([0-5]\\d)(?:[.,](\\d{1,3}))?)?)?(Z|[-+](?:[0]\\d|1[0-2])([0-5]\\d)?)?$/, x = /^(\\d\\d\\d\\d)(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])([01]\\d|2[0-3])(?:([0-5]\\d)(?:([0-5]\\d)(?:[.,](\\d{1,3}))?)?)?(Z|[-+](?:[0]\\d|1[0-2])([0-5]\\d)?)?$/;\n            function T(t, e) {\n                return t.length > e && (t = t.substring(0, e) + b),\n                t\n            }\n            var E, S = function() {\n                function n(t, e) {\n                    this.hexDigits = \"0123456789ABCDEF\",\n                    t instanceof n ? (this.enc = t.enc,\n                    this.pos = t.pos) : (this.enc = t,\n                    this.pos = e)\n                }\n                return n.prototype.get = function(t) {\n                    if (void 0 === t && (t = this.pos++),\n                    t >= this.enc.length)\n                        throw new Error(\"Requesting byte offset \" + t + \" on a stream of length \" + this.enc.length);\n                    return \"string\" == typeof this.enc ? this.enc.charCodeAt(t) : this.enc[t]\n                }\n                ,\n                n.prototype.hexByte = function(t) {\n                    return this.hexDigits.charAt(t >> 4 & 15) + this.hexDigits.charAt(15 & t)\n                }\n                ,\n                n.prototype.hexDump = function(t, e, n) {\n                    for (var r = \"\", i = t; i < e; ++i)\n                        if (r += this.hexByte(this.get(i)),\n                        !0 !== n)\n                            switch (15 & i) {\n                            case 7:\n                                r += \"  \";\n                                break;\n                            case 15:\n                                r += \"\\n\";\n                                break;\n                            default:\n                                r += \" \"\n                            }\n                    return r\n                }\n                ,\n                n.prototype.isASCII = function(t, e) {\n                    for (var n = t; n < e; ++n) {\n                        var r = this.get(n);\n                        if (r < 32 || 176 < r)\n                            return !1\n                    }\n                    return !0\n                }\n                ,\n                n.prototype.parseStringISO = function(t, e) {\n                    for (var n = \"\", r = t; r < e; ++r)\n                        n += String.fromCharCode(this.get(r));\n                    return n\n                }\n                ,\n                n.prototype.parseStringUTF = function(t, e) {\n                    for (var n = \"\", r = t; r < e; ) {\n                        var i = this.get(r++);\n                        n += i < 128 ? String.fromCharCode(i) : 191 < i && i < 224 ? String.fromCharCode((31 & i) << 6 | 63 & this.get(r++)) : String.fromCharCode((15 & i) << 12 | (63 & this.get(r++)) << 6 | 63 & this.get(r++))\n                    }\n                    return n\n                }\n                ,\n                n.prototype.parseStringBMP = function(t, e) {\n                    for (var n, r, i = \"\", o = t; o < e; )\n                        n = this.get(o++),\n                        r = this.get(o++),\n                        i += String.fromCharCode(n << 8 | r);\n                    return i\n                }\n                ,\n                n.prototype.parseTime = function(t, e, n) {\n                    var r = this.parseStringISO(t, e)\n                      , i = (n ? w : x).exec(r);\n                    return i ? (n && (i[1] = +i[1],\n                    i[1] += +i[1] < 70 ? 2e3 : 1900),\n                    r = i[1] + \"-\" + i[2] + \"-\" + i[3] + \" \" + i[4],\n                    i[5] && (r += \":\" + i[5],\n                    i[6] && (r += \":\" + i[6],\n                    i[7] && (r += \".\" + i[7]))),\n                    i[8] && (r += \" UTC\",\n                    \"Z\" != i[8] && (r += i[8],\n                    i[9] && (r += \":\" + i[9]))),\n                    r) : \"Unrecognized time: \" + r\n                }\n                ,\n                n.prototype.parseInteger = function(t, e) {\n                    for (var n, r = this.get(t), i = 127 < r, o = i ? 255 : 0, s = \"\"; r == o && ++t < e; )\n                        r = this.get(t);\n                    if (0 === (n = e - t))\n                        return i ? -1 : 0;\n                    if (4 < n) {\n                        for (s = r,\n                        n <<= 3; 0 == (128 & (+s ^ o)); )\n                            s = +s << 1,\n                            --n;\n                        s = \"(\" + n + \" bit)\\n\"\n                    }\n                    i && (r -= 256);\n                    for (var a = new y(r), c = t + 1; c < e; ++c)\n                        a.mulAdd(256, this.get(c));\n                    return s + a.toString()\n                }\n                ,\n                n.prototype.parseBitString = function(t, e, n) {\n                    for (var r = this.get(t), i = (e - t - 1 << 3) - r, o = \"(\" + i + \" bit)\\n\", s = \"\", a = t + 1; a < e; ++a) {\n                        for (var c = this.get(a), u = a == e - 1 ? r : 0, l = 7; u <= l; --l)\n                            s += c >> l & 1 ? \"1\" : \"0\";\n                        if (s.length > n)\n                            return o + T(s, n)\n                    }\n                    return o + s\n                }\n                ,\n                n.prototype.parseOctetString = function(t, e, n) {\n                    if (this.isASCII(t, e))\n                        return T(this.parseStringISO(t, e), n);\n                    var r = e - t\n                      , i = \"(\" + r + \" byte)\\n\";\n                    (n /= 2) < r && (e = t + n);\n                    for (var o = t; o < e; ++o)\n                        i += this.hexByte(this.get(o));\n                    return n < r && (i += b),\n                    i\n                }\n                ,\n                n.prototype.parseOID = function(t, e, n) {\n                    for (var r = \"\", i = new y, o = 0, s = t; s < e; ++s) {\n                        var a = this.get(s);\n                        if (i.mulAdd(128, 127 & a),\n                        o += 7,\n                        !(128 & a)) {\n                            if (\"\" === r)\n                                if ((i = i.simplify())instanceof y)\n                                    i.sub(80),\n                                    r = \"2.\" + i.toString();\n                                else {\n                                    var c = i < 80 ? i < 40 ? 0 : 1 : 2;\n                                    r = c + \".\" + (i - 40 * c)\n                                }\n                            else\n                                r += \".\" + i.toString();\n                            if (r.length > n)\n                                return T(r, n);\n                            i = new y,\n                            o = 0\n                        }\n                    }\n                    return 0 < o && (r += \".incomplete\"),\n                    r\n                }\n                ,\n                n\n            }(), _ = function() {\n                function l(t, e, n, r, i) {\n                    if (!(r instanceof A))\n                        throw new Error(\"Invalid tag value.\");\n                    this.stream = t,\n                    this.header = e,\n                    this.length = n,\n                    this.tag = r,\n                    this.sub = i\n                }\n                return l.prototype.typeName = function() {\n                    switch (this.tag.tagClass) {\n                    case 0:\n                        switch (this.tag.tagNumber) {\n                        case 0:\n                            return \"EOC\";\n                        case 1:\n                            return \"BOOLEAN\";\n                        case 2:\n                            return \"INTEGER\";\n                        case 3:\n                            return \"BIT_STRING\";\n                        case 4:\n                            return \"OCTET_STRING\";\n                        case 5:\n                            return \"NULL\";\n                        case 6:\n                            return \"OBJECT_IDENTIFIER\";\n                        case 7:\n                            return \"ObjectDescriptor\";\n                        case 8:\n                            return \"EXTERNAL\";\n                        case 9:\n                            return \"REAL\";\n                        case 10:\n                            return \"ENUMERATED\";\n                        case 11:\n                            return \"EMBEDDED_PDV\";\n                        case 12:\n                            return \"UTF8String\";\n                        case 16:\n                            return \"SEQUENCE\";\n                        case 17:\n                            return \"SET\";\n                        case 18:\n                            return \"NumericString\";\n                        case 19:\n                            return \"PrintableString\";\n                        case 20:\n                            return \"TeletexString\";\n                        case 21:\n                            return \"VideotexString\";\n                        case 22:\n                            return \"IA5String\";\n                        case 23:\n                            return \"UTCTime\";\n                        case 24:\n                            return \"GeneralizedTime\";\n                        case 25:\n                            return \"GraphicString\";\n                        case 26:\n                            return \"VisibleString\";\n                        case 27:\n                            return \"GeneralString\";\n                        case 28:\n                            return \"UniversalString\";\n                        case 30:\n                            return \"BMPString\"\n                        }\n                        return \"Universal_\" + this.tag.tagNumber.toString();\n                    case 1:\n                        return \"Application_\" + this.tag.tagNumber.toString();\n                    case 2:\n                        return \"[\" + this.tag.tagNumber.toString() + \"]\";\n                    case 3:\n                        return \"Private_\" + this.tag.tagNumber.toString()\n                    }\n                }\n                ,\n                l.prototype.content = function(t) {\n                    if (void 0 === this.tag)\n                        return null;\n                    void 0 === t && (t = 1 / 0);\n                    var e = this.posContent()\n                      , n = Math.abs(this.length);\n                    if (!this.tag.isUniversal())\n                        return null !== this.sub ? \"(\" + this.sub.length + \" elem)\" : this.stream.parseOctetString(e, e + n, t);\n                    switch (this.tag.tagNumber) {\n                    case 1:\n                        return 0 === this.stream.get(e) ? \"false\" : \"true\";\n                    case 2:\n                        return this.stream.parseInteger(e, e + n);\n                    case 3:\n                        return this.sub ? \"(\" + this.sub.length + \" elem)\" : this.stream.parseBitString(e, e + n, t);\n                    case 4:\n                        return this.sub ? \"(\" + this.sub.length + \" elem)\" : this.stream.parseOctetString(e, e + n, t);\n                    case 6:\n                        return this.stream.parseOID(e, e + n, t);\n                    case 16:\n                    case 17:\n                        return null !== this.sub ? \"(\" + this.sub.length + \" elem)\" : \"(no elem)\";\n                    case 12:\n                        return T(this.stream.parseStringUTF(e, e + n), t);\n                    case 18:\n                    case 19:\n                    case 20:\n                    case 21:\n                    case 22:\n                    case 26:\n                        return T(this.stream.parseStringISO(e, e + n), t);\n                    case 30:\n                        return T(this.stream.parseStringBMP(e, e + n), t);\n                    case 23:\n                    case 24:\n                        return this.stream.parseTime(e, e + n, 23 == this.tag.tagNumber)\n                    }\n                    return null\n                }\n                ,\n                l.prototype.toString = function() {\n                    return this.typeName() + \"@\" + this.stream.pos + \"[header:\" + this.header + \",length:\" + this.length + \",sub:\" + (null === this.sub ? \"null\" : this.sub.length) + \"]\"\n                }\n                ,\n                l.prototype.toPrettyString = function(t) {\n                    void 0 === t && (t = \"\");\n                    var e = t + this.typeName() + \" @\" + this.stream.pos;\n                    if (0 <= this.length && (e += \"+\"),\n                    e += this.length,\n                    this.tag.tagConstructed ? e += \" (constructed)\" : !this.tag.isUniversal() || 3 != this.tag.tagNumber && 4 != this.tag.tagNumber || null === this.sub || (e += \" (encapsulates)\"),\n                    e += \"\\n\",\n                    null !== this.sub) {\n                        t += \"  \";\n                        for (var n = 0, r = this.sub.length; n < r; ++n)\n                            e += this.sub[n].toPrettyString(t)\n                    }\n                    return e\n                }\n                ,\n                l.prototype.posStart = function() {\n                    return this.stream.pos\n                }\n                ,\n                l.prototype.posContent = function() {\n                    return this.stream.pos + this.header\n                }\n                ,\n                l.prototype.posEnd = function() {\n                    return this.stream.pos + this.header + Math.abs(this.length)\n                }\n                ,\n                l.prototype.toHexString = function() {\n                    return this.stream.hexDump(this.posStart(), this.posEnd(), !0)\n                }\n                ,\n                l.decodeLength = function(t) {\n                    var e = t.get()\n                      , n = 127 & e;\n                    if (n == e)\n                        return n;\n                    if (6 < n)\n                        throw new Error(\"Length over 48 bits not supported at position \" + (t.pos - 1));\n                    if (0 == n)\n                        return null;\n                    for (var r = e = 0; r < n; ++r)\n                        e = 256 * e + t.get();\n                    return e\n                }\n                ,\n                l.prototype.getHexStringValue = function() {\n                    var t = this.toHexString()\n                      , e = 2 * this.header\n                      , n = 2 * this.length;\n                    return t.substr(e, n)\n                }\n                ,\n                l.decode = function(t) {\n                    var r;\n                    r = t instanceof S ? t : new S(t,0);\n                    var e = new S(r)\n                      , n = new A(r)\n                      , i = l.decodeLength(r)\n                      , o = r.pos\n                      , s = o - e.pos\n                      , a = null\n                      , c = function() {\n                        var t = [];\n                        if (null !== i) {\n                            for (var e = o + i; r.pos < e; )\n                                t[t.length] = l.decode(r);\n                            if (r.pos != e)\n                                throw new Error(\"Content size is not correct for container starting at offset \" + o)\n                        } else\n                            try {\n                                for (; ; ) {\n                                    var n = l.decode(r);\n                                    if (n.tag.isEOC())\n                                        break;\n                                    t[t.length] = n\n                                }\n                                i = o - r.pos\n                            } catch (t) {\n                                throw new Error(\"Exception while decoding undefined length content: \" + t)\n                            }\n                        return t\n                    };\n                    if (n.tagConstructed)\n                        a = c();\n                    else if (n.isUniversal() && (3 == n.tagNumber || 4 == n.tagNumber))\n                        try {\n                            if (3 == n.tagNumber && 0 != r.get())\n                                throw new Error(\"BIT STRINGs with unused bits cannot encapsulate.\");\n                            a = c();\n                            for (var u = 0; u < a.length; ++u)\n                                if (a[u].tag.isEOC())\n                                    throw new Error(\"EOC is not supposed to be actual content.\")\n                        } catch (t) {\n                            a = null\n                        }\n                    if (null === a) {\n                        if (null === i)\n                            throw new Error(\"We can't skip over an invalid tag with undefined length at offset \" + o);\n                        r.pos = o + Math.abs(i)\n                    }\n                    return new l(e,s,i,n,a)\n                }\n                ,\n                l\n            }(), A = function() {\n                function t(t) {\n                    var e = t.get();\n                    if (this.tagClass = e >> 6,\n                    this.tagConstructed = 0 != (32 & e),\n                    this.tagNumber = 31 & e,\n                    31 == this.tagNumber) {\n                        for (var n = new y; e = t.get(),\n                        n.mulAdd(128, 127 & e),\n                        128 & e; )\n                            ;\n                        this.tagNumber = n.simplify()\n                    }\n                }\n                return t.prototype.isUniversal = function() {\n                    return 0 === this.tagClass\n                }\n                ,\n                t.prototype.isEOC = function() {\n                    return 0 === this.tagClass && 0 === this.tagNumber\n                }\n                ,\n                t\n            }(), k = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997], C = (1 << 26) / k[k.length - 1], D = function() {\n                function b(t, e, n) {\n                    null != t && (\"number\" == typeof t ? this.fromNumber(t, e, n) : null == e && \"string\" != typeof t ? this.fromString(t, 256) : this.fromString(t, e))\n                }\n                return b.prototype.toString = function(t) {\n                    if (this.s < 0)\n                        return \"-\" + this.negate().toString(t);\n                    var e;\n                    if (16 == t)\n                        e = 4;\n                    else if (8 == t)\n                        e = 3;\n                    else if (2 == t)\n                        e = 1;\n                    else if (32 == t)\n                        e = 5;\n                    else {\n                        if (4 != t)\n                            return this.toRadix(t);\n                        e = 2\n                    }\n                    var n, r = (1 << e) - 1, i = !1, o = \"\", s = this.t, a = this.DB - s * this.DB % e;\n                    if (0 < s--)\n                        for (a < this.DB && 0 < (n = this[s] >> a) && (i = !0,\n                        o = c(n)); 0 <= s; )\n                            a < e ? (n = (this[s] & (1 << a) - 1) << e - a,\n                            n |= this[--s] >> (a += this.DB - e)) : (n = this[s] >> (a -= e) & r,\n                            a <= 0 && (a += this.DB,\n                            --s)),\n                            0 < n && (i = !0),\n                            i && (o += c(n));\n                    return i ? o : \"0\"\n                }\n                ,\n                b.prototype.negate = function() {\n                    var t = P();\n                    return b.ZERO.subTo(this, t),\n                    t\n                }\n                ,\n                b.prototype.abs = function() {\n                    return this.s < 0 ? this.negate() : this\n                }\n                ,\n                b.prototype.compareTo = function(t) {\n                    var e = this.s - t.s;\n                    if (0 != e)\n                        return e;\n                    var n = this.t;\n                    if (0 != (e = n - t.t))\n                        return this.s < 0 ? -e : e;\n                    for (; 0 <= --n; )\n                        if (0 != (e = this[n] - t[n]))\n                            return e;\n                    return 0\n                }\n                ,\n                b.prototype.bitLength = function() {\n                    return this.t <= 0 ? 0 : this.DB * (this.t - 1) + U(this[this.t - 1] ^ this.s & this.DM)\n                }\n                ,\n                b.prototype.mod = function(t) {\n                    var e = P();\n                    return this.abs().divRemTo(t, null, e),\n                    this.s < 0 && 0 < e.compareTo(b.ZERO) && t.subTo(e, e),\n                    e\n                }\n                ,\n                b.prototype.modPowInt = function(t, e) {\n                    var n;\n                    return n = t < 256 || e.isEven() ? new O(e) : new R(e),\n                    this.exp(t, n)\n                }\n                ,\n                b.prototype.clone = function() {\n                    var t = P();\n                    return this.copyTo(t),\n                    t\n                }\n                ,\n                b.prototype.intValue = function() {\n                    if (this.s < 0) {\n                        if (1 == this.t)\n                            return this[0] - this.DV;\n                        if (0 == this.t)\n                            return -1\n                    } else {\n                        if (1 == this.t)\n                            return this[0];\n                        if (0 == this.t)\n                            return 0\n                    }\n                    return (this[1] & (1 << 32 - this.DB) - 1) << this.DB | this[0]\n                }\n                ,\n                b.prototype.byteValue = function() {\n                    return 0 == this.t ? this.s : this[0] << 24 >> 24\n                }\n                ,\n                b.prototype.shortValue = function() {\n                    return 0 == this.t ? this.s : this[0] << 16 >> 16\n                }\n                ,\n                b.prototype.signum = function() {\n                    return this.s < 0 ? -1 : this.t <= 0 || 1 == this.t && this[0] <= 0 ? 0 : 1\n                }\n                ,\n                b.prototype.toByteArray = function() {\n                    var t = this.t\n                      , e = [];\n                    e[0] = this.s;\n                    var n, r = this.DB - t * this.DB % 8, i = 0;\n                    if (0 < t--)\n                        for (r < this.DB && (n = this[t] >> r) != (this.s & this.DM) >> r && (e[i++] = n | this.s << this.DB - r); 0 <= t; )\n                            r < 8 ? (n = (this[t] & (1 << r) - 1) << 8 - r,\n                            n |= this[--t] >> (r += this.DB - 8)) : (n = this[t] >> (r -= 8) & 255,\n                            r <= 0 && (r += this.DB,\n                            --t)),\n                            0 != (128 & n) && (n |= -256),\n                            0 == i && (128 & this.s) != (128 & n) && ++i,\n                            (0 < i || n != this.s) && (e[i++] = n);\n                    return e\n                }\n                ,\n                b.prototype.equals = function(t) {\n                    return 0 == this.compareTo(t)\n                }\n                ,\n                b.prototype.min = function(t) {\n                    return this.compareTo(t) < 0 ? this : t\n                }\n                ,\n                b.prototype.max = function(t) {\n                    return 0 < this.compareTo(t) ? this : t\n                }\n                ,\n                b.prototype.and = function(t) {\n                    var e = P();\n                    return this.bitwiseTo(t, n, e),\n                    e\n                }\n                ,\n                b.prototype.or = function(t) {\n                    var e = P();\n                    return this.bitwiseTo(t, u, e),\n                    e\n                }\n                ,\n                b.prototype.xor = function(t) {\n                    var e = P();\n                    return this.bitwiseTo(t, r, e),\n                    e\n                }\n                ,\n                b.prototype.andNot = function(t) {\n                    var e = P();\n                    return this.bitwiseTo(t, i, e),\n                    e\n                }\n                ,\n                b.prototype.not = function() {\n                    for (var t = P(), e = 0; e < this.t; ++e)\n                        t[e] = this.DM & ~this[e];\n                    return t.t = this.t,\n                    t.s = ~this.s,\n                    t\n                }\n                ,\n                b.prototype.shiftLeft = function(t) {\n                    var e = P();\n                    return t < 0 ? this.rShiftTo(-t, e) : this.lShiftTo(t, e),\n                    e\n                }\n                ,\n                b.prototype.shiftRight = function(t) {\n                    var e = P();\n                    return t < 0 ? this.lShiftTo(-t, e) : this.rShiftTo(t, e),\n                    e\n                }\n                ,\n                b.prototype.getLowestSetBit = function() {\n                    for (var t = 0; t < this.t; ++t)\n                        if (0 != this[t])\n                            return t * this.DB + o(this[t]);\n                    return this.s < 0 ? this.t * this.DB : -1\n                }\n                ,\n                b.prototype.bitCount = function() {\n                    for (var t = 0, e = this.s & this.DM, n = 0; n < this.t; ++n)\n                        t += s(this[n] ^ e);\n                    return t\n                }\n                ,\n                b.prototype.testBit = function(t) {\n                    var e = Math.floor(t / this.DB);\n                    return e >= this.t ? 0 != this.s : 0 != (this[e] & 1 << t % this.DB)\n                }\n                ,\n                b.prototype.setBit = function(t) {\n                    return this.changeBit(t, u)\n                }\n                ,\n                b.prototype.clearBit = function(t) {\n                    return this.changeBit(t, i)\n                }\n                ,\n                b.prototype.flipBit = function(t) {\n                    return this.changeBit(t, r)\n                }\n                ,\n                b.prototype.add = function(t) {\n                    var e = P();\n                    return this.addTo(t, e),\n                    e\n                }\n                ,\n                b.prototype.subtract = function(t) {\n                    var e = P();\n                    return this.subTo(t, e),\n                    e\n                }\n                ,\n                b.prototype.multiply = function(t) {\n                    var e = P();\n                    return this.multiplyTo(t, e),\n                    e\n                }\n                ,\n                b.prototype.divide = function(t) {\n                    var e = P();\n                    return this.divRemTo(t, e, null),\n                    e\n                }\n                ,\n                b.prototype.remainder = function(t) {\n                    var e = P();\n                    return this.divRemTo(t, null, e),\n                    e\n                }\n                ,\n                b.prototype.divideAndRemainder = function(t) {\n                    var e = P()\n                      , n = P();\n                    return this.divRemTo(t, e, n),\n                    [e, n]\n                }\n                ,\n                b.prototype.modPow = function(t, e) {\n                    var n, r, i = t.bitLength(), o = q(1);\n                    if (i <= 0)\n                        return o;\n                    n = i < 18 ? 1 : i < 48 ? 3 : i < 144 ? 4 : i < 768 ? 5 : 6,\n                    r = i < 8 ? new O(e) : e.isEven() ? new I(e) : new R(e);\n                    var s = []\n                      , a = 3\n                      , c = n - 1\n                      , u = (1 << n) - 1;\n                    if (s[1] = r.convert(this),\n                    1 < n) {\n                        var l = P();\n                        for (r.sqrTo(s[1], l); a <= u; )\n                            s[a] = P(),\n                            r.mulTo(l, s[a - 2], s[a]),\n                            a += 2\n                    }\n                    var h, f, d = t.t - 1, p = !0, g = P();\n                    for (i = U(t[d]) - 1; 0 <= d; ) {\n                        for (c <= i ? h = t[d] >> i - c & u : (h = (t[d] & (1 << i + 1) - 1) << c - i,\n                        0 < d && (h |= t[d - 1] >> this.DB + i - c)),\n                        a = n; 0 == (1 & h); )\n                            h >>= 1,\n                            --a;\n                        if ((i -= a) < 0 && (i += this.DB,\n                        --d),\n                        p)\n                            s[h].copyTo(o),\n                            p = !1;\n                        else {\n                            for (; 1 < a; )\n                                r.sqrTo(o, g),\n                                r.sqrTo(g, o),\n                                a -= 2;\n                            0 < a ? r.sqrTo(o, g) : (f = o,\n                            o = g,\n                            g = f),\n                            r.mulTo(g, s[h], o)\n                        }\n                        for (; 0 <= d && 0 == (t[d] & 1 << i); )\n                            r.sqrTo(o, g),\n                            f = o,\n                            o = g,\n                            g = f,\n                            --i < 0 && (i = this.DB - 1,\n                            --d)\n                    }\n                    return r.revert(o)\n                }\n                ,\n                b.prototype.modInverse = function(t) {\n                    var e = t.isEven();\n                    if (this.isEven() && e || 0 == t.signum())\n                        return b.ZERO;\n                    for (var n = t.clone(), r = this.clone(), i = q(1), o = q(0), s = q(0), a = q(1); 0 != n.signum(); ) {\n                        for (; n.isEven(); )\n                            n.rShiftTo(1, n),\n                            e ? (i.isEven() && o.isEven() || (i.addTo(this, i),\n                            o.subTo(t, o)),\n                            i.rShiftTo(1, i)) : o.isEven() || o.subTo(t, o),\n                            o.rShiftTo(1, o);\n                        for (; r.isEven(); )\n                            r.rShiftTo(1, r),\n                            e ? (s.isEven() && a.isEven() || (s.addTo(this, s),\n                            a.subTo(t, a)),\n                            s.rShiftTo(1, s)) : a.isEven() || a.subTo(t, a),\n                            a.rShiftTo(1, a);\n                        0 <= n.compareTo(r) ? (n.subTo(r, n),\n                        e && i.subTo(s, i),\n                        o.subTo(a, o)) : (r.subTo(n, r),\n                        e && s.subTo(i, s),\n                        a.subTo(o, a))\n                    }\n                    return 0 != r.compareTo(b.ONE) ? b.ZERO : 0 <= a.compareTo(t) ? a.subtract(t) : a.signum() < 0 ? (a.addTo(t, a),\n                    a.signum() < 0 ? a.add(t) : a) : a\n                }\n                ,\n                b.prototype.pow = function(t) {\n                    return this.exp(t, new N)\n                }\n                ,\n                b.prototype.gcd = function(t) {\n                    var e = this.s < 0 ? this.negate() : this.clone()\n                      , n = t.s < 0 ? t.negate() : t.clone();\n                    if (e.compareTo(n) < 0) {\n                        var r = e;\n                        e = n,\n                        n = r\n                    }\n                    var i = e.getLowestSetBit()\n                      , o = n.getLowestSetBit();\n                    if (o < 0)\n                        return e;\n                    for (i < o && (o = i),\n                    0 < o && (e.rShiftTo(o, e),\n                    n.rShiftTo(o, n)); 0 < e.signum(); )\n                        0 < (i = e.getLowestSetBit()) && e.rShiftTo(i, e),\n                        0 < (i = n.getLowestSetBit()) && n.rShiftTo(i, n),\n                        0 <= e.compareTo(n) ? (e.subTo(n, e),\n                        e.rShiftTo(1, e)) : (n.subTo(e, n),\n                        n.rShiftTo(1, n));\n                    return 0 < o && n.lShiftTo(o, n),\n                    n\n                }\n                ,\n                b.prototype.isProbablePrime = function(t) {\n                    var e, n = this.abs();\n                    if (1 == n.t && n[0] <= k[k.length - 1]) {\n                        for (e = 0; e < k.length; ++e)\n                            if (n[0] == k[e])\n                                return !0;\n                        return !1\n                    }\n                    if (n.isEven())\n                        return !1;\n                    for (e = 1; e < k.length; ) {\n                        for (var r = k[e], i = e + 1; i < k.length && r < C; )\n                            r *= k[i++];\n                        for (r = n.modInt(r); e < i; )\n                            if (r % k[e++] == 0)\n                                return !1\n                    }\n                    return n.millerRabin(t)\n                }\n                ,\n                b.prototype.copyTo = function(t) {\n                    for (var e = this.t - 1; 0 <= e; --e)\n                        t[e] = this[e];\n                    t.t = this.t,\n                    t.s = this.s\n                }\n                ,\n                b.prototype.fromInt = function(t) {\n                    this.t = 1,\n                    this.s = t < 0 ? -1 : 0,\n                    0 < t ? this[0] = t : t < -1 ? this[0] = t + this.DV : this.t = 0\n                }\n                ,\n                b.prototype.fromString = function(t, e) {\n                    var n;\n                    if (16 == e)\n                        n = 4;\n                    else if (8 == e)\n                        n = 3;\n                    else if (256 == e)\n                        n = 8;\n                    else if (2 == e)\n                        n = 1;\n                    else if (32 == e)\n                        n = 5;\n                    else {\n                        if (4 != e)\n                            return void this.fromRadix(t, e);\n                        n = 2\n                    }\n                    this.t = 0,\n                    this.s = 0;\n                    for (var r = t.length, i = !1, o = 0; 0 <= --r; ) {\n                        var s = 8 == n ? 255 & +t[r] : V(t, r);\n                        s < 0 ? \"-\" == t.charAt(r) && (i = !0) : (i = !1,\n                        0 == o ? this[this.t++] = s : o + n > this.DB ? (this[this.t - 1] |= (s & (1 << this.DB - o) - 1) << o,\n                        this[this.t++] = s >> this.DB - o) : this[this.t - 1] |= s << o,\n                        (o += n) >= this.DB && (o -= this.DB))\n                    }\n                    8 == n && 0 != (128 & +t[0]) && (this.s = -1,\n                    0 < o && (this[this.t - 1] |= (1 << this.DB - o) - 1 << o)),\n                    this.clamp(),\n                    i && b.ZERO.subTo(this, this)\n                }\n                ,\n                b.prototype.clamp = function() {\n                    for (var t = this.s & this.DM; 0 < this.t && this[this.t - 1] == t; )\n                        --this.t\n                }\n                ,\n                b.prototype.dlShiftTo = function(t, e) {\n                    var n;\n                    for (n = this.t - 1; 0 <= n; --n)\n                        e[n + t] = this[n];\n                    for (n = t - 1; 0 <= n; --n)\n                        e[n] = 0;\n                    e.t = this.t + t,\n                    e.s = this.s\n                }\n                ,\n                b.prototype.drShiftTo = function(t, e) {\n                    for (var n = t; n < this.t; ++n)\n                        e[n - t] = this[n];\n                    e.t = Math.max(this.t - t, 0),\n                    e.s = this.s\n                }\n                ,\n                b.prototype.lShiftTo = function(t, e) {\n                    for (var n = t % this.DB, r = this.DB - n, i = (1 << r) - 1, o = Math.floor(t / this.DB), s = this.s << n & this.DM, a = this.t - 1; 0 <= a; --a)\n                        e[a + o + 1] = this[a] >> r | s,\n                        s = (this[a] & i) << n;\n                    for (var a = o - 1; 0 <= a; --a)\n                        e[a] = 0;\n                    e[o] = s,\n                    e.t = this.t + o + 1,\n                    e.s = this.s,\n                    e.clamp()\n                }\n                ,\n                b.prototype.rShiftTo = function(t, e) {\n                    e.s = this.s;\n                    var n = Math.floor(t / this.DB);\n                    if (n >= this.t)\n                        e.t = 0;\n                    else {\n                        var r = t % this.DB\n                          , i = this.DB - r\n                          , o = (1 << r) - 1;\n                        e[0] = this[n] >> r;\n                        for (var s = n + 1; s < this.t; ++s)\n                            e[s - n - 1] |= (this[s] & o) << i,\n                            e[s - n] = this[s] >> r;\n                        0 < r && (e[this.t - n - 1] |= (this.s & o) << i),\n                        e.t = this.t - n,\n                        e.clamp()\n                    }\n                }\n                ,\n                b.prototype.subTo = function(t, e) {\n                    for (var n = 0, r = 0, i = Math.min(t.t, this.t); n < i; )\n                        r += this[n] - t[n],\n                        e[n++] = r & this.DM,\n                        r >>= this.DB;\n                    if (t.t < this.t) {\n                        for (r -= t.s; n < this.t; )\n                            r += this[n],\n                            e[n++] = r & this.DM,\n                            r >>= this.DB;\n                        r += this.s\n                    } else {\n                        for (r += this.s; n < t.t; )\n                            r -= t[n],\n                            e[n++] = r & this.DM,\n                            r >>= this.DB;\n                        r -= t.s\n                    }\n                    e.s = r < 0 ? -1 : 0,\n                    r < -1 ? e[n++] = this.DV + r : 0 < r && (e[n++] = r),\n                    e.t = n,\n                    e.clamp()\n                }\n                ,\n                b.prototype.multiplyTo = function(t, e) {\n                    var n = this.abs()\n                      , r = t.abs()\n                      , i = n.t;\n                    for (e.t = i + r.t; 0 <= --i; )\n                        e[i] = 0;\n                    for (i = 0; i < r.t; ++i)\n                        e[i + n.t] = n.am(0, r[i], e, i, 0, n.t);\n                    e.s = 0,\n                    e.clamp(),\n                    this.s != t.s && b.ZERO.subTo(e, e)\n                }\n                ,\n                b.prototype.squareTo = function(t) {\n                    for (var e = this.abs(), n = t.t = 2 * e.t; 0 <= --n; )\n                        t[n] = 0;\n                    for (n = 0; n < e.t - 1; ++n) {\n                        var r = e.am(n, e[n], t, 2 * n, 0, 1);\n                        (t[n + e.t] += e.am(n + 1, 2 * e[n], t, 2 * n + 1, r, e.t - n - 1)) >= e.DV && (t[n + e.t] -= e.DV,\n                        t[n + e.t + 1] = 1)\n                    }\n                    0 < t.t && (t[t.t - 1] += e.am(n, e[n], t, 2 * n, 0, 1)),\n                    t.s = 0,\n                    t.clamp()\n                }\n                ,\n                b.prototype.divRemTo = function(t, e, n) {\n                    var r = t.abs();\n                    if (!(r.t <= 0)) {\n                        var i = this.abs();\n                        if (i.t < r.t)\n                            return null != e && e.fromInt(0),\n                            void (null != n && this.copyTo(n));\n                        null == n && (n = P());\n                        var o = P()\n                          , s = this.s\n                          , a = t.s\n                          , c = this.DB - U(r[r.t - 1]);\n                        0 < c ? (r.lShiftTo(c, o),\n                        i.lShiftTo(c, n)) : (r.copyTo(o),\n                        i.copyTo(n));\n                        var u = o.t\n                          , l = o[u - 1];\n                        if (0 != l) {\n                            var h = l * (1 << this.F1) + (1 < u ? o[u - 2] >> this.F2 : 0)\n                              , f = this.FV / h\n                              , d = (1 << this.F1) / h\n                              , p = 1 << this.F2\n                              , g = n.t\n                              , m = g - u\n                              , v = null == e ? P() : e;\n                            for (o.dlShiftTo(m, v),\n                            0 <= n.compareTo(v) && (n[n.t++] = 1,\n                            n.subTo(v, n)),\n                            b.ONE.dlShiftTo(u, v),\n                            v.subTo(o, o); o.t < u; )\n                                o[o.t++] = 0;\n                            for (; 0 <= --m; ) {\n                                var y = n[--g] == l ? this.DM : Math.floor(n[g] * f + (n[g - 1] + p) * d);\n                                if ((n[g] += o.am(0, y, n, m, 0, u)) < y)\n                                    for (o.dlShiftTo(m, v),\n                                    n.subTo(v, n); n[g] < --y; )\n                                        n.subTo(v, n)\n                            }\n                            null != e && (n.drShiftTo(u, e),\n                            s != a && b.ZERO.subTo(e, e)),\n                            n.t = u,\n                            n.clamp(),\n                            0 < c && n.rShiftTo(c, n),\n                            s < 0 && b.ZERO.subTo(n, n)\n                        }\n                    }\n                }\n                ,\n                b.prototype.invDigit = function() {\n                    if (this.t < 1)\n                        return 0;\n                    var t = this[0];\n                    if (0 == (1 & t))\n                        return 0;\n                    var e = 3 & t;\n                    return 0 < (e = (e = (e = (e = e * (2 - (15 & t) * e) & 15) * (2 - (255 & t) * e) & 255) * (2 - ((65535 & t) * e & 65535)) & 65535) * (2 - t * e % this.DV) % this.DV) ? this.DV - e : -e\n                }\n                ,\n                b.prototype.isEven = function() {\n                    return 0 == (0 < this.t ? 1 & this[0] : this.s)\n                }\n                ,\n                b.prototype.exp = function(t, e) {\n                    if (4294967295 < t || t < 1)\n                        return b.ONE;\n                    var n = P()\n                      , r = P()\n                      , i = e.convert(this)\n                      , o = U(t) - 1;\n                    for (i.copyTo(n); 0 <= --o; )\n                        if (e.sqrTo(n, r),\n                        0 < (t & 1 << o))\n                            e.mulTo(r, i, n);\n                        else {\n                            var s = n;\n                            n = r,\n                            r = s\n                        }\n                    return e.revert(n)\n                }\n                ,\n                b.prototype.chunkSize = function(t) {\n                    return Math.floor(Math.LN2 * this.DB / Math.log(t))\n                }\n                ,\n                b.prototype.toRadix = function(t) {\n                    if (null == t && (t = 10),\n                    0 == this.signum() || t < 2 || 36 < t)\n                        return \"0\";\n                    var e = this.chunkSize(t)\n                      , n = Math.pow(t, e)\n                      , r = q(n)\n                      , i = P()\n                      , o = P()\n                      , s = \"\";\n                    for (this.divRemTo(r, i, o); 0 < i.signum(); )\n                        s = (n + o.intValue()).toString(t).substr(1) + s,\n                        i.divRemTo(r, i, o);\n                    return o.intValue().toString(t) + s\n                }\n                ,\n                b.prototype.fromRadix = function(t, e) {\n                    this.fromInt(0),\n                    null == e && (e = 10);\n                    for (var n = this.chunkSize(e), r = Math.pow(e, n), i = !1, o = 0, s = 0, a = 0; a < t.length; ++a) {\n                        var c = V(t, a);\n                        c < 0 ? \"-\" == t.charAt(a) && 0 == this.signum() && (i = !0) : (s = e * s + c,\n                        ++o >= n && (this.dMultiply(r),\n                        this.dAddOffset(s, 0),\n                        s = o = 0))\n                    }\n                    0 < o && (this.dMultiply(Math.pow(e, o)),\n                    this.dAddOffset(s, 0)),\n                    i && b.ZERO.subTo(this, this)\n                }\n                ,\n                b.prototype.fromNumber = function(t, e, n) {\n                    if (\"number\" == typeof e)\n                        if (t < 2)\n                            this.fromInt(1);\n                        else\n                            for (this.fromNumber(t, n),\n                            this.testBit(t - 1) || this.bitwiseTo(b.ONE.shiftLeft(t - 1), u, this),\n                            this.isEven() && this.dAddOffset(1, 0); !this.isProbablePrime(e); )\n                                this.dAddOffset(2, 0),\n                                this.bitLength() > t && this.subTo(b.ONE.shiftLeft(t - 1), this);\n                    else {\n                        var r = []\n                          , i = 7 & t;\n                        r.length = 1 + (t >> 3),\n                        e.nextBytes(r),\n                        0 < i ? r[0] &= (1 << i) - 1 : r[0] = 0,\n                        this.fromString(r, 256)\n                    }\n                }\n                ,\n                b.prototype.bitwiseTo = function(t, e, n) {\n                    var r, i, o = Math.min(t.t, this.t);\n                    for (r = 0; r < o; ++r)\n                        n[r] = e(this[r], t[r]);\n                    if (t.t < this.t) {\n                        for (i = t.s & this.DM,\n                        r = o; r < this.t; ++r)\n                            n[r] = e(this[r], i);\n                        n.t = this.t\n                    } else {\n                        for (i = this.s & this.DM,\n                        r = o; r < t.t; ++r)\n                            n[r] = e(i, t[r]);\n                        n.t = t.t\n                    }\n                    n.s = e(this.s, t.s),\n                    n.clamp()\n                }\n                ,\n                b.prototype.changeBit = function(t, e) {\n                    var n = b.ONE.shiftLeft(t);\n                    return this.bitwiseTo(n, e, n),\n                    n\n                }\n                ,\n                b.prototype.addTo = function(t, e) {\n                    for (var n = 0, r = 0, i = Math.min(t.t, this.t); n < i; )\n                        r += this[n] + t[n],\n                        e[n++] = r & this.DM,\n                        r >>= this.DB;\n                    if (t.t < this.t) {\n                        for (r += t.s; n < this.t; )\n                            r += this[n],\n                            e[n++] = r & this.DM,\n                            r >>= this.DB;\n                        r += this.s\n                    } else {\n                        for (r += this.s; n < t.t; )\n                            r += t[n],\n                            e[n++] = r & this.DM,\n                            r >>= this.DB;\n                        r += t.s\n                    }\n                    e.s = r < 0 ? -1 : 0,\n                    0 < r ? e[n++] = r : r < -1 && (e[n++] = this.DV + r),\n                    e.t = n,\n                    e.clamp()\n                }\n                ,\n                b.prototype.dMultiply = function(t) {\n                    this[this.t] = this.am(0, t - 1, this, 0, 0, this.t),\n                    ++this.t,\n                    this.clamp()\n                }\n                ,\n                b.prototype.dAddOffset = function(t, e) {\n                    if (0 != t) {\n                        for (; this.t <= e; )\n                            this[this.t++] = 0;\n                        for (this[e] += t; this[e] >= this.DV; )\n                            this[e] -= this.DV,\n                            ++e >= this.t && (this[this.t++] = 0),\n                            ++this[e]\n                    }\n                }\n                ,\n                b.prototype.multiplyLowerTo = function(t, e, n) {\n                    var r = Math.min(this.t + t.t, e);\n                    for (n.s = 0,\n                    n.t = r; 0 < r; )\n                        n[--r] = 0;\n                    for (var i = n.t - this.t; r < i; ++r)\n                        n[r + this.t] = this.am(0, t[r], n, r, 0, this.t);\n                    for (var i = Math.min(t.t, e); r < i; ++r)\n                        this.am(0, t[r], n, r, 0, e - r);\n                    n.clamp()\n                }\n                ,\n                b.prototype.multiplyUpperTo = function(t, e, n) {\n                    --e;\n                    var r = n.t = this.t + t.t - e;\n                    for (n.s = 0; 0 <= --r; )\n                        n[r] = 0;\n                    for (r = Math.max(e - this.t, 0); r < t.t; ++r)\n                        n[this.t + r - e] = this.am(e - r, t[r], n, 0, 0, this.t + r - e);\n                    n.clamp(),\n                    n.drShiftTo(1, n)\n                }\n                ,\n                b.prototype.modInt = function(t) {\n                    if (t <= 0)\n                        return 0;\n                    var e = this.DV % t\n                      , n = this.s < 0 ? t - 1 : 0;\n                    if (0 < this.t)\n                        if (0 == e)\n                            n = this[0] % t;\n                        else\n                            for (var r = this.t - 1; 0 <= r; --r)\n                                n = (e * n + this[r]) % t;\n                    return n\n                }\n                ,\n                b.prototype.millerRabin = function(t) {\n                    var e = this.subtract(b.ONE)\n                      , n = e.getLowestSetBit();\n                    if (n <= 0)\n                        return !1;\n                    var r = e.shiftRight(n);\n                    k.length < (t = t + 1 >> 1) && (t = k.length);\n                    for (var i = P(), o = 0; o < t; ++o) {\n                        i.fromInt(k[Math.floor(Math.random() * k.length)]);\n                        var s = i.modPow(r, this);\n                        if (0 != s.compareTo(b.ONE) && 0 != s.compareTo(e)) {\n                            for (var a = 1; a++ < n && 0 != s.compareTo(e); )\n                                if (0 == (s = s.modPowInt(2, this)).compareTo(b.ONE))\n                                    return !1;\n                            if (0 != s.compareTo(e))\n                                return !1\n                        }\n                    }\n                    return !0\n                }\n                ,\n                b.prototype.square = function() {\n                    var t = P();\n                    return this.squareTo(t),\n                    t\n                }\n                ,\n                b.prototype.gcda = function(t, e) {\n                    var n = this.s < 0 ? this.negate() : this.clone()\n                      , r = t.s < 0 ? t.negate() : t.clone();\n                    if (n.compareTo(r) < 0) {\n                        var i = n;\n                        n = r,\n                        r = i\n                    }\n                    var o = n.getLowestSetBit()\n                      , s = r.getLowestSetBit();\n                    if (s < 0)\n                        e(n);\n                    else {\n                        o < s && (s = o),\n                        0 < s && (n.rShiftTo(s, n),\n                        r.rShiftTo(s, r));\n                        var a = function() {\n                            0 < (o = n.getLowestSetBit()) && n.rShiftTo(o, n),\n                            0 < (o = r.getLowestSetBit()) && r.rShiftTo(o, r),\n                            0 <= n.compareTo(r) ? (n.subTo(r, n),\n                            n.rShiftTo(1, n)) : (r.subTo(n, r),\n                            r.rShiftTo(1, r)),\n                            0 < n.signum() ? setTimeout(a, 0) : (0 < s && r.lShiftTo(s, r),\n                            setTimeout(function() {\n                                e(r)\n                            }, 0))\n                        };\n                        setTimeout(a, 10)\n                    }\n                }\n                ,\n                b.prototype.fromNumberAsync = function(t, e, n, r) {\n                    if (\"number\" == typeof e)\n                        if (t < 2)\n                            this.fromInt(1);\n                        else {\n                            this.fromNumber(t, n),\n                            this.testBit(t - 1) || this.bitwiseTo(b.ONE.shiftLeft(t - 1), u, this),\n                            this.isEven() && this.dAddOffset(1, 0);\n                            var i = this\n                              , o = function() {\n                                i.dAddOffset(2, 0),\n                                i.bitLength() > t && i.subTo(b.ONE.shiftLeft(t - 1), i),\n                                i.isProbablePrime(e) ? setTimeout(function() {\n                                    r()\n                                }, 0) : setTimeout(o, 0)\n                            };\n                            setTimeout(o, 0)\n                        }\n                    else {\n                        var s = []\n                          , a = 7 & t;\n                        s.length = 1 + (t >> 3),\n                        e.nextBytes(s),\n                        0 < a ? s[0] &= (1 << a) - 1 : s[0] = 0,\n                        this.fromString(s, 256)\n                    }\n                }\n                ,\n                b\n            }(), N = function() {\n                function t() {}\n                return t.prototype.convert = function(t) {\n                    return t\n                }\n                ,\n                t.prototype.revert = function(t) {\n                    return t\n                }\n                ,\n                t.prototype.mulTo = function(t, e, n) {\n                    t.multiplyTo(e, n)\n                }\n                ,\n                t.prototype.sqrTo = function(t, e) {\n                    t.squareTo(e)\n                }\n                ,\n                t\n            }(), O = function() {\n                function t(t) {\n                    this.m = t\n                }\n                return t.prototype.convert = function(t) {\n                    return t.s < 0 || 0 <= t.compareTo(this.m) ? t.mod(this.m) : t\n                }\n                ,\n                t.prototype.revert = function(t) {\n                    return t\n                }\n                ,\n                t.prototype.reduce = function(t) {\n                    t.divRemTo(this.m, null, t)\n                }\n                ,\n                t.prototype.mulTo = function(t, e, n) {\n                    t.multiplyTo(e, n),\n                    this.reduce(n)\n                }\n                ,\n                t.prototype.sqrTo = function(t, e) {\n                    t.squareTo(e),\n                    this.reduce(e)\n                }\n                ,\n                t\n            }(), R = function() {\n                function t(t) {\n                    this.m = t,\n                    this.mp = t.invDigit(),\n                    this.mpl = 32767 & this.mp,\n                    this.mph = this.mp >> 15,\n                    this.um = (1 << t.DB - 15) - 1,\n                    this.mt2 = 2 * t.t\n                }\n                return t.prototype.convert = function(t) {\n                    var e = P();\n                    return t.abs().dlShiftTo(this.m.t, e),\n                    e.divRemTo(this.m, null, e),\n                    t.s < 0 && 0 < e.compareTo(D.ZERO) && this.m.subTo(e, e),\n                    e\n                }\n                ,\n                t.prototype.revert = function(t) {\n                    var e = P();\n                    return t.copyTo(e),\n                    this.reduce(e),\n                    e\n                }\n                ,\n                t.prototype.reduce = function(t) {\n                    for (; t.t <= this.mt2; )\n                        t[t.t++] = 0;\n                    for (var e = 0; e < this.m.t; ++e) {\n                        var n = 32767 & t[e]\n                          , r = n * this.mpl + ((n * this.mph + (t[e] >> 15) * this.mpl & this.um) << 15) & t.DM;\n                        for (n = e + this.m.t,\n                        t[n] += this.m.am(0, r, t, e, 0, this.m.t); t[n] >= t.DV; )\n                            t[n] -= t.DV,\n                            t[++n]++\n                    }\n                    t.clamp(),\n                    t.drShiftTo(this.m.t, t),\n                    0 <= t.compareTo(this.m) && t.subTo(this.m, t)\n                }\n                ,\n                t.prototype.mulTo = function(t, e, n) {\n                    t.multiplyTo(e, n),\n                    this.reduce(n)\n                }\n                ,\n                t.prototype.sqrTo = function(t, e) {\n                    t.squareTo(e),\n                    this.reduce(e)\n                }\n                ,\n                t\n            }(), I = function() {\n                function t(t) {\n                    this.m = t,\n                    this.r2 = P(),\n                    this.q3 = P(),\n                    D.ONE.dlShiftTo(2 * t.t, this.r2),\n                    this.mu = this.r2.divide(t)\n                }\n                return t.prototype.convert = function(t) {\n                    if (t.s < 0 || t.t > 2 * this.m.t)\n                        return t.mod(this.m);\n                    if (t.compareTo(this.m) < 0)\n                        return t;\n                    var e = P();\n                    return t.copyTo(e),\n                    this.reduce(e),\n                    e\n                }\n                ,\n                t.prototype.revert = function(t) {\n                    return t\n                }\n                ,\n                t.prototype.reduce = function(t) {\n                    for (t.drShiftTo(this.m.t - 1, this.r2),\n                    t.t > this.m.t + 1 && (t.t = this.m.t + 1,\n                    t.clamp()),\n                    this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3),\n                    this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); t.compareTo(this.r2) < 0; )\n                        t.dAddOffset(1, this.m.t + 1);\n                    for (t.subTo(this.r2, t); 0 <= t.compareTo(this.m); )\n                        t.subTo(this.m, t)\n                }\n                ,\n                t.prototype.mulTo = function(t, e, n) {\n                    t.multiplyTo(e, n),\n                    this.reduce(n)\n                }\n                ,\n                t.prototype.sqrTo = function(t, e) {\n                    t.squareTo(e),\n                    this.reduce(e)\n                }\n                ,\n                t\n            }();\n            function P() {\n                return new D(null)\n            }\n            function j(t, e) {\n                return new D(t,e)\n            }\n            E = \"Microsoft Internet Explorer\" == navigator.appName ? (D.prototype.am = function(t, e, n, r, i, o) {\n                var s = 32767 & e\n                  , a = e >> 15;\n                for (; 0 <= --o; ) {\n                    var c = 32767 & this[t]\n                      , u = this[t++] >> 15\n                      , l = a * c + u * s;\n                    c = s * c + ((32767 & l) << 15) + n[r] + (1073741823 & i),\n                    i = (c >>> 30) + (l >>> 15) + a * u + (i >>> 30),\n                    n[r++] = 1073741823 & c\n                }\n                return i\n            }\n            ,\n            30) : \"Netscape\" != navigator.appName ? (D.prototype.am = function(t, e, n, r, i, o) {\n                for (; 0 <= --o; ) {\n                    var s = e * this[t++] + n[r] + i;\n                    i = Math.floor(s / 67108864),\n                    n[r++] = 67108863 & s\n                }\n                return i\n            }\n            ,\n            26) : (D.prototype.am = function(t, e, n, r, i, o) {\n                var s = 16383 & e\n                  , a = e >> 14;\n                for (; 0 <= --o; ) {\n                    var c = 16383 & this[t]\n                      , u = this[t++] >> 14\n                      , l = a * c + u * s;\n                    c = s * c + ((16383 & l) << 14) + n[r] + i,\n                    i = (c >> 28) + (l >> 14) + a * u,\n                    n[r++] = 268435455 & c\n                }\n                return i\n            }\n            ,\n            28),\n            D.prototype.DB = E,\n            D.prototype.DM = (1 << E) - 1,\n            D.prototype.DV = 1 << E;\n            D.prototype.FV = Math.pow(2, 52),\n            D.prototype.F1 = 52 - E,\n            D.prototype.F2 = 2 * E - 52;\n            var B, L, M = [];\n            for (B = \"0\".charCodeAt(0),\n            L = 0; L <= 9; ++L)\n                M[B++] = L;\n            for (B = \"a\".charCodeAt(0),\n            L = 10; L < 36; ++L)\n                M[B++] = L;\n            for (B = \"A\".charCodeAt(0),\n            L = 10; L < 36; ++L)\n                M[B++] = L;\n            function V(t, e) {\n                var n = M[t.charCodeAt(e)];\n                return null == n ? -1 : n\n            }\n            function q(t) {\n                var e = P();\n                return e.fromInt(t),\n                e\n            }\n            function U(t) {\n                var e, n = 1;\n                return 0 != (e = t >>> 16) && (t = e,\n                n += 16),\n                0 != (e = t >> 8) && (t = e,\n                n += 8),\n                0 != (e = t >> 4) && (t = e,\n                n += 4),\n                0 != (e = t >> 2) && (t = e,\n                n += 2),\n                0 != (e = t >> 1) && (t = e,\n                n += 1),\n                n\n            }\n            D.ZERO = q(0),\n            D.ONE = q(1);\n            var H = function() {\n                function t() {\n                    this.i = 0,\n                    this.j = 0,\n                    this.S = []\n                }\n                return t.prototype.init = function(t) {\n                    var e, n, r;\n                    for (e = 0; e < 256; ++e)\n                        this.S[e] = e;\n                    for (e = n = 0; e < 256; ++e)\n                        n = n + this.S[e] + t[e % t.length] & 255,\n                        r = this.S[e],\n                        this.S[e] = this.S[n],\n                        this.S[n] = r;\n                    this.i = 0,\n                    this.j = 0\n                }\n                ,\n                t.prototype.next = function() {\n                    var t;\n                    return this.i = this.i + 1 & 255,\n                    this.j = this.j + this.S[this.i] & 255,\n                    t = this.S[this.i],\n                    this.S[this.i] = this.S[this.j],\n                    this.S[this.j] = t,\n                    this.S[t + this.S[this.i] & 255]\n                }\n                ,\n                t\n            }();\n            var F, K, W = 256, z = null;\n            if (null == z) {\n                z = [];\n                var G = void (K = 0);\n                if (window.crypto && window.crypto.getRandomValues) {\n                    var $ = new Uint32Array(256);\n                    for (window.crypto.getRandomValues($),\n                    G = 0; G < $.length; ++G)\n                        z[K++] = 255 & $[G]\n                }\n                var X = function(t) {\n                    if (this.count = this.count || 0,\n                    256 <= this.count || W <= K)\n                        window.removeEventListener ? window.removeEventListener(\"mousemove\", X, !1) : window.detachEvent && window.detachEvent(\"onmousemove\", X);\n                    else\n                        try {\n                            var e = t.x + t.y;\n                            z[K++] = 255 & e,\n                            this.count += 1\n                        } catch (t) {}\n                };\n                window.addEventListener ? window.addEventListener(\"mousemove\", X, !1) : window.attachEvent && window.attachEvent(\"onmousemove\", X)\n            }\n            function Q() {\n                if (null == F) {\n                    for (F = new H; K < W; ) {\n                        var t = Math.floor(65536 * Math.random());\n                        z[K++] = 255 & t\n                    }\n                    for (F.init(z),\n                    K = 0; K < z.length; ++K)\n                        z[K] = 0;\n                    K = 0\n                }\n                return F.next()\n            }\n            var J = function() {\n                function t() {}\n                return t.prototype.nextBytes = function(t) {\n                    for (var e = 0; e < t.length; ++e)\n                        t[e] = Q()\n                }\n                ,\n                t\n            }();\n            var Z = function() {\n                function t() {\n                    this.n = null,\n                    this.e = 0,\n                    this.d = null,\n                    this.p = null,\n                    this.q = null,\n                    this.dmp1 = null,\n                    this.dmq1 = null,\n                    this.coeff = null\n                }\n                return t.prototype.doPublic = function(t) {\n                    return t.modPowInt(this.e, this.n)\n                }\n                ,\n                t.prototype.doPrivate = function(t) {\n                    if (null == this.p || null == this.q)\n                        return t.modPow(this.d, this.n);\n                    for (var e = t.mod(this.p).modPow(this.dmp1, this.p), n = t.mod(this.q).modPow(this.dmq1, this.q); e.compareTo(n) < 0; )\n                        e = e.add(this.p);\n                    return e.subtract(n).multiply(this.coeff).mod(this.p).multiply(this.q).add(n)\n                }\n                ,\n                t.prototype.setPublic = function(t, e) {\n                    null != t && null != e && 0 < t.length && 0 < e.length && (this.n = j(t, 16),\n                    this.e = parseInt(e, 16))\n                }\n                ,\n                t.prototype.encrypt = function(t) {\n                    var e = function(t, e) {\n                        if (e < t.length + 11)\n                            return null;\n                        var n = []\n                          , r = t.length - 1;\n                        for (; 0 <= r && 0 < e; ) {\n                            var i = t.charCodeAt(r--);\n                            i < 128 ? n[--e] = i : 127 < i && i < 2048 ? (n[--e] = 63 & i | 128,\n                            n[--e] = i >> 6 | 192) : (n[--e] = 63 & i | 128,\n                            n[--e] = i >> 6 & 63 | 128,\n                            n[--e] = i >> 12 | 224)\n                        }\n                        n[--e] = 0;\n                        var o = new J\n                          , s = [];\n                        for (; 2 < e; ) {\n                            for (s[0] = 0; 0 == s[0]; )\n                                o.nextBytes(s);\n                            n[--e] = s[0]\n                        }\n                        return n[--e] = 2,\n                        n[--e] = 0,\n                        new D(n)\n                    }(t, this.n.bitLength() + 7 >> 3);\n                    if (null == e)\n                        return null;\n                    var n = this.doPublic(e);\n                    if (null == n)\n                        return null;\n                    var r = n.toString(16);\n                    return 0 == (1 & r.length) ? r : \"0\" + r\n                }\n                ,\n                t.prototype.setPrivate = function(t, e, n) {\n                    null != t && null != e && 0 < t.length && 0 < e.length && (this.n = j(t, 16),\n                    this.e = parseInt(e, 16),\n                    this.d = j(n, 16))\n                }\n                ,\n                t.prototype.setPrivateEx = function(t, e, n, r, i, o, s, a) {\n                    null != t && null != e && 0 < t.length && 0 < e.length && (this.n = j(t, 16),\n                    this.e = parseInt(e, 16),\n                    this.d = j(n, 16),\n                    this.p = j(r, 16),\n                    this.q = j(i, 16),\n                    this.dmp1 = j(o, 16),\n                    this.dmq1 = j(s, 16),\n                    this.coeff = j(a, 16))\n                }\n                ,\n                t.prototype.generate = function(t, e) {\n                    var n = new J\n                      , r = t >> 1;\n                    this.e = parseInt(e, 16);\n                    for (var i = new D(e,16); ; ) {\n                        for (; this.p = new D(t - r,1,n),\n                        0 != this.p.subtract(D.ONE).gcd(i).compareTo(D.ONE) || !this.p.isProbablePrime(10); )\n                            ;\n                        for (; this.q = new D(r,1,n),\n                        0 != this.q.subtract(D.ONE).gcd(i).compareTo(D.ONE) || !this.q.isProbablePrime(10); )\n                            ;\n                        if (this.p.compareTo(this.q) <= 0) {\n                            var o = this.p;\n                            this.p = this.q,\n                            this.q = o\n                        }\n                        var s = this.p.subtract(D.ONE)\n                          , a = this.q.subtract(D.ONE)\n                          , c = s.multiply(a);\n                        if (0 == c.gcd(i).compareTo(D.ONE)) {\n                            this.n = this.p.multiply(this.q),\n                            this.d = i.modInverse(c),\n                            this.dmp1 = this.d.mod(s),\n                            this.dmq1 = this.d.mod(a),\n                            this.coeff = this.q.modInverse(this.p);\n                            break\n                        }\n                    }\n                }\n                ,\n                t.prototype.decrypt = function(t) {\n                    var e = j(t, 16)\n                      , n = this.doPrivate(e);\n                    return null == n ? null : function(t, e) {\n                        var n = t.toByteArray()\n                          , r = 0;\n                        for (; r < n.length && 0 == n[r]; )\n                            ++r;\n                        if (n.length - r != e - 1 || 2 != n[r])\n                            return null;\n                        ++r;\n                        for (; 0 != n[r]; )\n                            if (++r >= n.length)\n                                return null;\n                        var i = \"\";\n                        for (; ++r < n.length; ) {\n                            var o = 255 & n[r];\n                            o < 128 ? i += String.fromCharCode(o) : 191 < o && o < 224 ? (i += String.fromCharCode((31 & o) << 6 | 63 & n[r + 1]),\n                            ++r) : (i += String.fromCharCode((15 & o) << 12 | (63 & n[r + 1]) << 6 | 63 & n[r + 2]),\n                            r += 2)\n                        }\n                        return i\n                    }(n, this.n.bitLength() + 7 >> 3)\n                }\n                ,\n                t.prototype.generateAsync = function(t, e, i) {\n                    var o = new J\n                      , s = t >> 1;\n                    this.e = parseInt(e, 16);\n                    var a = new D(e,16)\n                      , c = this\n                      , u = function() {\n                        var e = function() {\n                            if (c.p.compareTo(c.q) <= 0) {\n                                var t = c.p;\n                                c.p = c.q,\n                                c.q = t\n                            }\n                            var e = c.p.subtract(D.ONE)\n                              , n = c.q.subtract(D.ONE)\n                              , r = e.multiply(n);\n                            0 == r.gcd(a).compareTo(D.ONE) ? (c.n = c.p.multiply(c.q),\n                            c.d = a.modInverse(r),\n                            c.dmp1 = c.d.mod(e),\n                            c.dmq1 = c.d.mod(n),\n                            c.coeff = c.q.modInverse(c.p),\n                            setTimeout(function() {\n                                i()\n                            }, 0)) : setTimeout(u, 0)\n                        }\n                          , n = function() {\n                            c.q = P(),\n                            c.q.fromNumberAsync(s, 1, o, function() {\n                                c.q.subtract(D.ONE).gcda(a, function(t) {\n                                    0 == t.compareTo(D.ONE) && c.q.isProbablePrime(10) ? setTimeout(e, 0) : setTimeout(n, 0)\n                                })\n                            })\n                        }\n                          , r = function() {\n                            c.p = P(),\n                            c.p.fromNumberAsync(t - s, 1, o, function() {\n                                c.p.subtract(D.ONE).gcda(a, function(t) {\n                                    0 == t.compareTo(D.ONE) && c.p.isProbablePrime(10) ? setTimeout(n, 0) : setTimeout(r, 0)\n                                })\n                            })\n                        };\n                        setTimeout(r, 0)\n                    };\n                    setTimeout(u, 0)\n                }\n                ,\n                t.prototype.sign = function(t, e, n) {\n                    var r = function(t) {\n                        return Y[t] || \"\"\n                    }(n)\n                      , i = r + e(t).toString()\n                      , o = function(t, e) {\n                        if (e < t.length + 22)\n                            return null;\n                        for (var n = e - t.length - 6, r = \"\", i = 0; i < n; i += 2)\n                            r += \"ff\";\n                        return j(\"0001\" + r + \"00\" + t, 16)\n                    }(i, this.n.bitLength() / 4);\n                    if (null == o)\n                        return null;\n                    var s = this.doPrivate(o);\n                    if (null == s)\n                        return null;\n                    var a = s.toString(16);\n                    return 0 == (1 & a.length) ? a : \"0\" + a\n                }\n                ,\n                t.prototype.verify = function(t, e, n) {\n                    var r = j(e, 16)\n                      , i = this.doPublic(r);\n                    if (null == i)\n                        return null;\n                    var o = i.toString(16).replace(/^1f+00/, \"\")\n                      , s = function(t) {\n                        for (var e in Y)\n                            if (Y.hasOwnProperty(e)) {\n                                var n = Y[e]\n                                  , r = n.length;\n                                if (t.substr(0, r) == n)\n                                    return t.substr(r)\n                            }\n                        return t\n                    }(o);\n                    return s == n(t).toString()\n                }\n                ,\n                t\n            }();\n            var Y = {\n                md2: \"3020300c06082a864886f70d020205000410\",\n                md5: \"3020300c06082a864886f70d020505000410\",\n                sha1: \"3021300906052b0e03021a05000414\",\n                sha224: \"302d300d06096086480165030402040500041c\",\n                sha256: \"3031300d060960864801650304020105000420\",\n                sha384: \"3041300d060960864801650304020205000430\",\n                sha512: \"3051300d060960864801650304020305000440\",\n                ripemd160: \"3021300906052b2403020105000414\"\n            };\n            var tt = {};\n            tt.lang = {\n                extend: function(t, e, n) {\n                    if (!e || !t)\n                        throw new Error(\"YAHOO.lang.extend failed, please check that all dependencies are included.\");\n                    var r = function() {};\n                    if (r.prototype = e.prototype,\n                    t.prototype = new r,\n                    (t.prototype.constructor = t).superclass = e.prototype,\n                    e.prototype.constructor == Object.prototype.constructor && (e.prototype.constructor = e),\n                    n) {\n                        var i;\n                        for (i in n)\n                            t.prototype[i] = n[i];\n                        var o = function() {}\n                          , s = [\"toString\", \"valueOf\"];\n                        try {\n                            /MSIE/.test(navigator.userAgent) && (o = function(t, e) {\n                                for (i = 0; i < s.length; i += 1) {\n                                    var n = s[i]\n                                      , r = e[n];\n                                    \"function\" == typeof r && r != Object.prototype[n] && (t[n] = r)\n                                }\n                            }\n                            )\n                        } catch (t) {}\n                        o(t.prototype, n)\n                    }\n                }\n            };\n            var et = {};\n            void 0 !== et.asn1 && et.asn1 || (et.asn1 = {}),\n            et.asn1.ASN1Util = new function() {\n                this.integerToByteHex = function(t) {\n                    var e = t.toString(16);\n                    return e.length % 2 == 1 && (e = \"0\" + e),\n                    e\n                }\n                ,\n                this.bigIntToMinTwosComplementsHex = function(t) {\n                    var e = t.toString(16);\n                    if (\"-\" != e.substr(0, 1))\n                        e.length % 2 == 1 ? e = \"0\" + e : e.match(/^[0-7]/) || (e = \"00\" + e);\n                    else {\n                        var n = e.substr(1)\n                          , r = n.length;\n                        r % 2 == 1 ? r += 1 : e.match(/^[0-7]/) || (r += 2);\n                        for (var i = \"\", o = 0; o < r; o++)\n                            i += \"f\";\n                        var s = new D(i,16)\n                          , a = s.xor(t).add(D.ONE);\n                        e = a.toString(16).replace(/^-/, \"\")\n                    }\n                    return e\n                }\n                ,\n                this.getPEMStringFromHex = function(t, e) {\n                    return hextopem(t, e)\n                }\n                ,\n                this.newObject = function(t) {\n                    var e = et\n                      , n = e.asn1\n                      , r = n.DERBoolean\n                      , i = n.DERInteger\n                      , o = n.DERBitString\n                      , s = n.DEROctetString\n                      , a = n.DERNull\n                      , c = n.DERObjectIdentifier\n                      , u = n.DEREnumerated\n                      , l = n.DERUTF8String\n                      , h = n.DERNumericString\n                      , f = n.DERPrintableString\n                      , d = n.DERTeletexString\n                      , p = n.DERIA5String\n                      , g = n.DERUTCTime\n                      , m = n.DERGeneralizedTime\n                      , v = n.DERSequence\n                      , y = n.DERSet\n                      , b = n.DERTaggedObject\n                      , w = n.ASN1Util.newObject\n                      , x = Object.keys(t);\n                    if (1 != x.length)\n                        throw \"key of param shall be only one.\";\n                    var T = x[0];\n                    if (-1 == \":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:\".indexOf(\":\" + T + \":\"))\n                        throw \"undefined key: \" + T;\n                    if (\"bool\" == T)\n                        return new r(t[T]);\n                    if (\"int\" == T)\n                        return new i(t[T]);\n                    if (\"bitstr\" == T)\n                        return new o(t[T]);\n                    if (\"octstr\" == T)\n                        return new s(t[T]);\n                    if (\"null\" == T)\n                        return new a(t[T]);\n                    if (\"oid\" == T)\n                        return new c(t[T]);\n                    if (\"enum\" == T)\n                        return new u(t[T]);\n                    if (\"utf8str\" == T)\n                        return new l(t[T]);\n                    if (\"numstr\" == T)\n                        return new h(t[T]);\n                    if (\"prnstr\" == T)\n                        return new f(t[T]);\n                    if (\"telstr\" == T)\n                        return new d(t[T]);\n                    if (\"ia5str\" == T)\n                        return new p(t[T]);\n                    if (\"utctime\" == T)\n                        return new g(t[T]);\n                    if (\"gentime\" == T)\n                        return new m(t[T]);\n                    if (\"seq\" == T) {\n                        for (var E = t[T], S = [], _ = 0; _ < E.length; _++) {\n                            var A = w(E[_]);\n                            S.push(A)\n                        }\n                        return new v({\n                            array: S\n                        })\n                    }\n                    if (\"set\" == T) {\n                        for (var E = t[T], S = [], _ = 0; _ < E.length; _++) {\n                            var A = w(E[_]);\n                            S.push(A)\n                        }\n                        return new y({\n                            array: S\n                        })\n                    }\n                    if (\"tag\" == T) {\n                        var k = t[T];\n                        if (\"[object Array]\" === Object.prototype.toString.call(k) && 3 == k.length) {\n                            var C = w(k[2]);\n                            return new b({\n                                tag: k[0],\n                                explicit: k[1],\n                                obj: C\n                            })\n                        }\n                        var D = {};\n                        if (void 0 !== k.explicit && (D.explicit = k.explicit),\n                        void 0 !== k.tag && (D.tag = k.tag),\n                        void 0 === k.obj)\n                            throw \"obj shall be specified for 'tag'.\";\n                        return D.obj = w(k.obj),\n                        new b(D)\n                    }\n                }\n                ,\n                this.jsonToASN1HEX = function(t) {\n                    var e = this.newObject(t);\n                    return e.getEncodedHex()\n                }\n            }\n            ,\n            et.asn1.ASN1Util.oidHexToInt = function(t) {\n                for (var e = \"\", n = parseInt(t.substr(0, 2), 16), r = Math.floor(n / 40), i = n % 40, e = r + \".\" + i, o = \"\", s = 2; s < t.length; s += 2) {\n                    var a = parseInt(t.substr(s, 2), 16)\n                      , c = (\"00000000\" + a.toString(2)).slice(-8);\n                    if (o += c.substr(1, 7),\n                    \"0\" == c.substr(0, 1)) {\n                        var u = new D(o,2);\n                        e = e + \".\" + u.toString(10),\n                        o = \"\"\n                    }\n                }\n                return e\n            }\n            ,\n            et.asn1.ASN1Util.oidIntToHex = function(t) {\n                var c = function(t) {\n                    var e = t.toString(16);\n                    return 1 == e.length && (e = \"0\" + e),\n                    e\n                }\n                  , e = function(t) {\n                    var e = \"\"\n                      , n = new D(t,10)\n                      , r = n.toString(2)\n                      , i = 7 - r.length % 7;\n                    7 == i && (i = 0);\n                    for (var o = \"\", s = 0; s < i; s++)\n                        o += \"0\";\n                    r = o + r;\n                    for (var s = 0; s < r.length - 1; s += 7) {\n                        var a = r.substr(s, 7);\n                        s != r.length - 7 && (a = \"1\" + a),\n                        e += c(parseInt(a, 2))\n                    }\n                    return e\n                };\n                if (!t.match(/^[0-9.]+$/))\n                    throw \"malformed oid string: \" + t;\n                var n = \"\"\n                  , r = t.split(\".\")\n                  , i = 40 * parseInt(r[0]) + parseInt(r[1]);\n                n += c(i),\n                r.splice(0, 2);\n                for (var o = 0; o < r.length; o++)\n                    n += e(r[o]);\n                return n\n            }\n            ,\n            et.asn1.ASN1Object = function() {\n                this.getLengthHexFromValue = function() {\n                    if (void 0 === this.hV || null == this.hV)\n                        throw \"this.hV is null or undefined.\";\n                    if (this.hV.length % 2 == 1)\n                        throw \"value hex must be even length: n=\" + \"\".length + \",v=\" + this.hV;\n                    var t = this.hV.length / 2\n                      , e = t.toString(16);\n                    if (e.length % 2 == 1 && (e = \"0\" + e),\n                    t < 128)\n                        return e;\n                    var n = e.length / 2;\n                    if (15 < n)\n                        throw \"ASN.1 length too long to represent by 8x: n = \" + t.toString(16);\n                    var r = 128 + n;\n                    return r.toString(16) + e\n                }\n                ,\n                this.getEncodedHex = function() {\n                    return null != this.hTLV && !this.isModified || (this.hV = this.getFreshValueHex(),\n                    this.hL = this.getLengthHexFromValue(),\n                    this.hTLV = this.hT + this.hL + this.hV,\n                    this.isModified = !1),\n                    this.hTLV\n                }\n                ,\n                this.getValueHex = function() {\n                    return this.getEncodedHex(),\n                    this.hV\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return \"\"\n                }\n            }\n            ,\n            et.asn1.DERAbstractString = function(t) {\n                et.asn1.DERAbstractString.superclass.constructor.call(this),\n                this.getString = function() {\n                    return this.s\n                }\n                ,\n                this.setString = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.s = t,\n                    this.hV = stohex(this.s)\n                }\n                ,\n                this.setStringHex = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.s = null,\n                    this.hV = t\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n                ,\n                void 0 !== t && (\"string\" == typeof t ? this.setString(t) : void 0 !== t.str ? this.setString(t.str) : void 0 !== t.hex && this.setStringHex(t.hex))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERAbstractString, et.asn1.ASN1Object),\n            et.asn1.DERAbstractTime = function(t) {\n                et.asn1.DERAbstractTime.superclass.constructor.call(this),\n                this.localDateToUTC = function(t) {\n                    utc = t.getTime() + 6e4 * t.getTimezoneOffset();\n                    var e = new Date(utc);\n                    return e\n                }\n                ,\n                this.formatDate = function(t, e, n) {\n                    var r = this.zeroPadding\n                      , i = this.localDateToUTC(t)\n                      , o = String(i.getFullYear());\n                    \"utc\" == e && (o = o.substr(2, 2));\n                    var s = r(String(i.getMonth() + 1), 2)\n                      , a = r(String(i.getDate()), 2)\n                      , c = r(String(i.getHours()), 2)\n                      , u = r(String(i.getMinutes()), 2)\n                      , l = r(String(i.getSeconds()), 2)\n                      , h = o + s + a + c + u + l;\n                    if (!0 === n) {\n                        var f = i.getMilliseconds();\n                        if (0 != f) {\n                            var d = r(String(f), 3);\n                            d = d.replace(/[0]+$/, \"\"),\n                            h = h + \".\" + d\n                        }\n                    }\n                    return h + \"Z\"\n                }\n                ,\n                this.zeroPadding = function(t, e) {\n                    return t.length >= e ? t : new Array(e - t.length + 1).join(\"0\") + t\n                }\n                ,\n                this.getString = function() {\n                    return this.s\n                }\n                ,\n                this.setString = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.s = t,\n                    this.hV = stohex(t)\n                }\n                ,\n                this.setByDateValue = function(t, e, n, r, i, o) {\n                    var s = new Date(Date.UTC(t, e - 1, n, r, i, o, 0));\n                    this.setByDate(s)\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n            }\n            ,\n            tt.lang.extend(et.asn1.DERAbstractTime, et.asn1.ASN1Object),\n            et.asn1.DERAbstractStructured = function(t) {\n                et.asn1.DERAbstractString.superclass.constructor.call(this),\n                this.setByASN1ObjectArray = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.asn1Array = t\n                }\n                ,\n                this.appendASN1Object = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.asn1Array.push(t)\n                }\n                ,\n                this.asn1Array = new Array,\n                void 0 !== t && void 0 !== t.array && (this.asn1Array = t.array)\n            }\n            ,\n            tt.lang.extend(et.asn1.DERAbstractStructured, et.asn1.ASN1Object),\n            et.asn1.DERBoolean = function() {\n                et.asn1.DERBoolean.superclass.constructor.call(this),\n                this.hT = \"01\",\n                this.hTLV = \"0101ff\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERBoolean, et.asn1.ASN1Object),\n            et.asn1.DERInteger = function(t) {\n                et.asn1.DERInteger.superclass.constructor.call(this),\n                this.hT = \"02\",\n                this.setByBigInteger = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.hV = et.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)\n                }\n                ,\n                this.setByInteger = function(t) {\n                    var e = new D(String(t),10);\n                    this.setByBigInteger(e)\n                }\n                ,\n                this.setValueHex = function(t) {\n                    this.hV = t\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n                ,\n                void 0 !== t && (void 0 !== t.bigint ? this.setByBigInteger(t.bigint) : void 0 !== t.int ? this.setByInteger(t.int) : \"number\" == typeof t ? this.setByInteger(t) : void 0 !== t.hex && this.setValueHex(t.hex))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERInteger, et.asn1.ASN1Object),\n            et.asn1.DERBitString = function(t) {\n                if (void 0 !== t && void 0 !== t.obj) {\n                    var e = et.asn1.ASN1Util.newObject(t.obj);\n                    t.hex = \"00\" + e.getEncodedHex()\n                }\n                et.asn1.DERBitString.superclass.constructor.call(this),\n                this.hT = \"03\",\n                this.setHexValueIncludingUnusedBits = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.hV = t\n                }\n                ,\n                this.setUnusedBitsAndHexValue = function(t, e) {\n                    if (t < 0 || 7 < t)\n                        throw \"unused bits shall be from 0 to 7: u = \" + t;\n                    var n = \"0\" + t;\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.hV = n + e\n                }\n                ,\n                this.setByBinaryString = function(t) {\n                    var e = 8 - (t = t.replace(/0+$/, \"\")).length % 8;\n                    8 == e && (e = 0);\n                    for (var n = 0; n <= e; n++)\n                        t += \"0\";\n                    for (var r = \"\", n = 0; n < t.length - 1; n += 8) {\n                        var i = t.substr(n, 8)\n                          , o = parseInt(i, 2).toString(16);\n                        1 == o.length && (o = \"0\" + o),\n                        r += o\n                    }\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.hV = \"0\" + e + r\n                }\n                ,\n                this.setByBooleanArray = function(t) {\n                    for (var e = \"\", n = 0; n < t.length; n++)\n                        1 == t[n] ? e += \"1\" : e += \"0\";\n                    this.setByBinaryString(e)\n                }\n                ,\n                this.newFalseArray = function(t) {\n                    for (var e = new Array(t), n = 0; n < t; n++)\n                        e[n] = !1;\n                    return e\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n                ,\n                void 0 !== t && (\"string\" == typeof t && t.toLowerCase().match(/^[0-9a-f]+$/) ? this.setHexValueIncludingUnusedBits(t) : void 0 !== t.hex ? this.setHexValueIncludingUnusedBits(t.hex) : void 0 !== t.bin ? this.setByBinaryString(t.bin) : void 0 !== t.array && this.setByBooleanArray(t.array))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERBitString, et.asn1.ASN1Object),\n            et.asn1.DEROctetString = function(t) {\n                if (void 0 !== t && void 0 !== t.obj) {\n                    var e = et.asn1.ASN1Util.newObject(t.obj);\n                    t.hex = e.getEncodedHex()\n                }\n                et.asn1.DEROctetString.superclass.constructor.call(this, t),\n                this.hT = \"04\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DEROctetString, et.asn1.DERAbstractString),\n            et.asn1.DERNull = function() {\n                et.asn1.DERNull.superclass.constructor.call(this),\n                this.hT = \"05\",\n                this.hTLV = \"0500\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERNull, et.asn1.ASN1Object),\n            et.asn1.DERObjectIdentifier = function(t) {\n                var c = function(t) {\n                    var e = t.toString(16);\n                    return 1 == e.length && (e = \"0\" + e),\n                    e\n                }\n                  , o = function(t) {\n                    var e = \"\"\n                      , n = new D(t,10)\n                      , r = n.toString(2)\n                      , i = 7 - r.length % 7;\n                    7 == i && (i = 0);\n                    for (var o = \"\", s = 0; s < i; s++)\n                        o += \"0\";\n                    r = o + r;\n                    for (var s = 0; s < r.length - 1; s += 7) {\n                        var a = r.substr(s, 7);\n                        s != r.length - 7 && (a = \"1\" + a),\n                        e += c(parseInt(a, 2))\n                    }\n                    return e\n                };\n                et.asn1.DERObjectIdentifier.superclass.constructor.call(this),\n                this.hT = \"06\",\n                this.setValueHex = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.s = null,\n                    this.hV = t\n                }\n                ,\n                this.setValueOidString = function(t) {\n                    if (!t.match(/^[0-9.]+$/))\n                        throw \"malformed oid string: \" + t;\n                    var e = \"\"\n                      , n = t.split(\".\")\n                      , r = 40 * parseInt(n[0]) + parseInt(n[1]);\n                    e += c(r),\n                    n.splice(0, 2);\n                    for (var i = 0; i < n.length; i++)\n                        e += o(n[i]);\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.s = null,\n                    this.hV = e\n                }\n                ,\n                this.setValueName = function(t) {\n                    var e = et.asn1.x509.OID.name2oid(t);\n                    if (\"\" === e)\n                        throw \"DERObjectIdentifier oidName undefined: \" + t;\n                    this.setValueOidString(e)\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n                ,\n                void 0 !== t && (\"string\" == typeof t ? t.match(/^[0-2].[0-9.]+$/) ? this.setValueOidString(t) : this.setValueName(t) : void 0 !== t.oid ? this.setValueOidString(t.oid) : void 0 !== t.hex ? this.setValueHex(t.hex) : void 0 !== t.name && this.setValueName(t.name))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERObjectIdentifier, et.asn1.ASN1Object),\n            et.asn1.DEREnumerated = function(t) {\n                et.asn1.DEREnumerated.superclass.constructor.call(this),\n                this.hT = \"0a\",\n                this.setByBigInteger = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.hV = et.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)\n                }\n                ,\n                this.setByInteger = function(t) {\n                    var e = new D(String(t),10);\n                    this.setByBigInteger(e)\n                }\n                ,\n                this.setValueHex = function(t) {\n                    this.hV = t\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n                ,\n                void 0 !== t && (void 0 !== t.int ? this.setByInteger(t.int) : \"number\" == typeof t ? this.setByInteger(t) : void 0 !== t.hex && this.setValueHex(t.hex))\n            }\n            ,\n            tt.lang.extend(et.asn1.DEREnumerated, et.asn1.ASN1Object),\n            et.asn1.DERUTF8String = function(t) {\n                et.asn1.DERUTF8String.superclass.constructor.call(this, t),\n                this.hT = \"0c\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERUTF8String, et.asn1.DERAbstractString),\n            et.asn1.DERNumericString = function(t) {\n                et.asn1.DERNumericString.superclass.constructor.call(this, t),\n                this.hT = \"12\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERNumericString, et.asn1.DERAbstractString),\n            et.asn1.DERPrintableString = function(t) {\n                et.asn1.DERPrintableString.superclass.constructor.call(this, t),\n                this.hT = \"13\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERPrintableString, et.asn1.DERAbstractString),\n            et.asn1.DERTeletexString = function(t) {\n                et.asn1.DERTeletexString.superclass.constructor.call(this, t),\n                this.hT = \"14\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERTeletexString, et.asn1.DERAbstractString),\n            et.asn1.DERIA5String = function(t) {\n                et.asn1.DERIA5String.superclass.constructor.call(this, t),\n                this.hT = \"16\"\n            }\n            ,\n            tt.lang.extend(et.asn1.DERIA5String, et.asn1.DERAbstractString),\n            et.asn1.DERUTCTime = function(t) {\n                et.asn1.DERUTCTime.superclass.constructor.call(this, t),\n                this.hT = \"17\",\n                this.setByDate = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.date = t,\n                    this.s = this.formatDate(this.date, \"utc\"),\n                    this.hV = stohex(this.s)\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return void 0 === this.date && void 0 === this.s && (this.date = new Date,\n                    this.s = this.formatDate(this.date, \"utc\"),\n                    this.hV = stohex(this.s)),\n                    this.hV\n                }\n                ,\n                void 0 !== t && (void 0 !== t.str ? this.setString(t.str) : \"string\" == typeof t && t.match(/^[0-9]{12}Z$/) ? this.setString(t) : void 0 !== t.hex ? this.setStringHex(t.hex) : void 0 !== t.date && this.setByDate(t.date))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERUTCTime, et.asn1.DERAbstractTime),\n            et.asn1.DERGeneralizedTime = function(t) {\n                et.asn1.DERGeneralizedTime.superclass.constructor.call(this, t),\n                this.hT = \"18\",\n                this.withMillis = !1,\n                this.setByDate = function(t) {\n                    this.hTLV = null,\n                    this.isModified = !0,\n                    this.date = t,\n                    this.s = this.formatDate(this.date, \"gen\", this.withMillis),\n                    this.hV = stohex(this.s)\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return void 0 === this.date && void 0 === this.s && (this.date = new Date,\n                    this.s = this.formatDate(this.date, \"gen\", this.withMillis),\n                    this.hV = stohex(this.s)),\n                    this.hV\n                }\n                ,\n                void 0 !== t && (void 0 !== t.str ? this.setString(t.str) : \"string\" == typeof t && t.match(/^[0-9]{14}Z$/) ? this.setString(t) : void 0 !== t.hex ? this.setStringHex(t.hex) : void 0 !== t.date && this.setByDate(t.date),\n                !0 === t.millis && (this.withMillis = !0))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERGeneralizedTime, et.asn1.DERAbstractTime),\n            et.asn1.DERSequence = function(t) {\n                et.asn1.DERSequence.superclass.constructor.call(this, t),\n                this.hT = \"30\",\n                this.getFreshValueHex = function() {\n                    for (var t = \"\", e = 0; e < this.asn1Array.length; e++) {\n                        var n = this.asn1Array[e];\n                        t += n.getEncodedHex()\n                    }\n                    return this.hV = t,\n                    this.hV\n                }\n            }\n            ,\n            tt.lang.extend(et.asn1.DERSequence, et.asn1.DERAbstractStructured),\n            et.asn1.DERSet = function(t) {\n                et.asn1.DERSet.superclass.constructor.call(this, t),\n                this.hT = \"31\",\n                this.sortFlag = !0,\n                this.getFreshValueHex = function() {\n                    for (var t = new Array, e = 0; e < this.asn1Array.length; e++) {\n                        var n = this.asn1Array[e];\n                        t.push(n.getEncodedHex())\n                    }\n                    return 1 == this.sortFlag && t.sort(),\n                    this.hV = t.join(\"\"),\n                    this.hV\n                }\n                ,\n                void 0 !== t && void 0 !== t.sortflag && 0 == t.sortflag && (this.sortFlag = !1)\n            }\n            ,\n            tt.lang.extend(et.asn1.DERSet, et.asn1.DERAbstractStructured),\n            et.asn1.DERTaggedObject = function(t) {\n                et.asn1.DERTaggedObject.superclass.constructor.call(this),\n                this.hT = \"a0\",\n                this.hV = \"\",\n                this.isExplicit = !0,\n                this.asn1Object = null,\n                this.setASN1Object = function(t, e, n) {\n                    this.hT = e,\n                    this.isExplicit = t,\n                    this.asn1Object = n,\n                    this.isExplicit ? (this.hV = this.asn1Object.getEncodedHex(),\n                    this.hTLV = null,\n                    this.isModified = !0) : (this.hV = null,\n                    this.hTLV = n.getEncodedHex(),\n                    this.hTLV = this.hTLV.replace(/^../, e),\n                    this.isModified = !1)\n                }\n                ,\n                this.getFreshValueHex = function() {\n                    return this.hV\n                }\n                ,\n                void 0 !== t && (void 0 !== t.tag && (this.hT = t.tag),\n                void 0 !== t.explicit && (this.isExplicit = t.explicit),\n                void 0 !== t.obj && (this.asn1Object = t.obj,\n                this.setASN1Object(this.isExplicit, this.hT, this.asn1Object)))\n            }\n            ,\n            tt.lang.extend(et.asn1.DERTaggedObject, et.asn1.ASN1Object);\n            var nt = function(n) {\n                function r(t) {\n                    var e = n.call(this) || this;\n                    return t && (\"string\" == typeof t ? e.parseKey(t) : (r.hasPrivateKeyProperty(t) || r.hasPublicKeyProperty(t)) && e.parsePropertiesFrom(t)),\n                    e\n                }\n                return function(t, e) {\n                    function n() {\n                        this.constructor = t\n                    }\n                    d(t, e),\n                    t.prototype = null === e ? Object.create(e) : (n.prototype = e.prototype,\n                    new n)\n                }(r, n),\n                r.prototype.parseKey = function(t) {\n                    try {\n                        var e = 0\n                          , n = 0\n                          , r = /^\\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\\s*)+$/.test(t) ? g.decode(t) : m.unarmor(t)\n                          , i = _.decode(r);\n                        if (3 === i.sub.length && (i = i.sub[2].sub[0]),\n                        9 === i.sub.length) {\n                            e = i.sub[1].getHexStringValue(),\n                            this.n = j(e, 16),\n                            n = i.sub[2].getHexStringValue(),\n                            this.e = parseInt(n, 16);\n                            var o = i.sub[3].getHexStringValue();\n                            this.d = j(o, 16);\n                            var s = i.sub[4].getHexStringValue();\n                            this.p = j(s, 16);\n                            var a = i.sub[5].getHexStringValue();\n                            this.q = j(a, 16);\n                            var c = i.sub[6].getHexStringValue();\n                            this.dmp1 = j(c, 16);\n                            var u = i.sub[7].getHexStringValue();\n                            this.dmq1 = j(u, 16);\n                            var l = i.sub[8].getHexStringValue();\n                            this.coeff = j(l, 16)\n                        } else {\n                            if (2 !== i.sub.length)\n                                return !1;\n                            var h = i.sub[1]\n                              , f = h.sub[0];\n                            e = f.sub[0].getHexStringValue(),\n                            this.n = j(e, 16),\n                            n = f.sub[1].getHexStringValue(),\n                            this.e = parseInt(n, 16)\n                        }\n                        return !0\n                    } catch (t) {\n                        return !1\n                    }\n                }\n                ,\n                r.prototype.getPrivateBaseKey = function() {\n                    var t = {\n                        array: [new et.asn1.DERInteger({\n                            int: 0\n                        }), new et.asn1.DERInteger({\n                            bigint: this.n\n                        }), new et.asn1.DERInteger({\n                            int: this.e\n                        }), new et.asn1.DERInteger({\n                            bigint: this.d\n                        }), new et.asn1.DERInteger({\n                            bigint: this.p\n                        }), new et.asn1.DERInteger({\n                            bigint: this.q\n                        }), new et.asn1.DERInteger({\n                            bigint: this.dmp1\n                        }), new et.asn1.DERInteger({\n                            bigint: this.dmq1\n                        }), new et.asn1.DERInteger({\n                            bigint: this.coeff\n                        })]\n                    }\n                      , e = new et.asn1.DERSequence(t);\n                    return e.getEncodedHex()\n                }\n                ,\n                r.prototype.getPrivateBaseKeyB64 = function() {\n                    return l(this.getPrivateBaseKey())\n                }\n                ,\n                r.prototype.getPublicBaseKey = function() {\n                    var t = new et.asn1.DERSequence({\n                        array: [new et.asn1.DERObjectIdentifier({\n                            oid: \"1.2.840.113549.1.1.1\"\n                        }), new et.asn1.DERNull]\n                    })\n                      , e = new et.asn1.DERSequence({\n                        array: [new et.asn1.DERInteger({\n                            bigint: this.n\n                        }), new et.asn1.DERInteger({\n                            int: this.e\n                        })]\n                    })\n                      , n = new et.asn1.DERBitString({\n                        hex: \"00\" + e.getEncodedHex()\n                    })\n                      , r = new et.asn1.DERSequence({\n                        array: [t, n]\n                    });\n                    return r.getEncodedHex()\n                }\n                ,\n                r.prototype.getPublicBaseKeyB64 = function() {\n                    return l(this.getPublicBaseKey())\n                }\n                ,\n                r.wordwrap = function(t, e) {\n                    if (e = e || 64,\n                    !t)\n                        return t;\n                    var n = \"(.{1,\" + e + \"})( +|$\\n?)|(.{1,\" + e + \"})\";\n                    return t.match(RegExp(n, \"g\")).join(\"\\n\")\n                }\n                ,\n                r.prototype.getPrivateKey = function() {\n                    var t = \"-----BEGIN RSA PRIVATE KEY-----\\n\";\n                    return t += r.wordwrap(this.getPrivateBaseKeyB64()) + \"\\n\",\n                    t += \"-----END RSA PRIVATE KEY-----\"\n                }\n                ,\n                r.prototype.getPublicKey = function() {\n                    var t = \"-----BEGIN PUBLIC KEY-----\\n\";\n                    return t += r.wordwrap(this.getPublicBaseKeyB64()) + \"\\n\",\n                    t += \"-----END PUBLIC KEY-----\"\n                }\n                ,\n                r.hasPublicKeyProperty = function(t) {\n                    return (t = t || {}).hasOwnProperty(\"n\") && t.hasOwnProperty(\"e\")\n                }\n                ,\n                r.hasPrivateKeyProperty = function(t) {\n                    return (t = t || {}).hasOwnProperty(\"n\") && t.hasOwnProperty(\"e\") && t.hasOwnProperty(\"d\") && t.hasOwnProperty(\"p\") && t.hasOwnProperty(\"q\") && t.hasOwnProperty(\"dmp1\") && t.hasOwnProperty(\"dmq1\") && t.hasOwnProperty(\"coeff\")\n                }\n                ,\n                r.prototype.parsePropertiesFrom = function(t) {\n                    this.n = t.n,\n                    this.e = t.e,\n                    t.hasOwnProperty(\"d\") && (this.d = t.d,\n                    this.p = t.p,\n                    this.q = t.q,\n                    this.dmp1 = t.dmp1,\n                    this.dmq1 = t.dmq1,\n                    this.coeff = t.coeff)\n                }\n                ,\n                r\n            }(Z)\n              , rt = function() {\n                function t(t) {\n                    t = t || {},\n                    this.default_key_size = parseInt(t.default_key_size, 10) || 1024,\n                    this.default_public_exponent = t.default_public_exponent || \"010001\",\n                    this.log = t.log || !1,\n                    this.key = null\n                }\n                return t.prototype.setKey = function(t) {\n                    this.log && this.key,\n                    this.key = new nt(t)\n                }\n                ,\n                t.prototype.setPrivateKey = function(t) {\n                    this.setKey(t)\n                }\n                ,\n                t.prototype.setPublicKey = function(t) {\n                    this.setKey(t)\n                }\n                ,\n                t.prototype.decrypt = function(t) {\n                    try {\n                        return this.getKey().decrypt(h(t))\n                    } catch (t) {\n                        return !1\n                    }\n                }\n                ,\n                t.prototype.encrypt = function(t) {\n                    try {\n                        return l(this.getKey().encrypt(t))\n                    } catch (t) {\n                        return !1\n                    }\n                }\n                ,\n                t.prototype.sign = function(t, e, n) {\n                    try {\n                        return l(this.getKey().sign(t, e, n))\n                    } catch (t) {\n                        return !1\n                    }\n                }\n                ,\n                t.prototype.verify = function(t, e, n) {\n                    try {\n                        return this.getKey().verify(t, h(e), n)\n                    } catch (t) {\n                        return !1\n                    }\n                }\n                ,\n                t.prototype.getKey = function(t) {\n                    if (!this.key) {\n                        if (this.key = new nt,\n                        t && \"[object Function]\" === {}.toString.call(t))\n                            return void this.key.generateAsync(this.default_key_size, this.default_public_exponent, t);\n                        this.key.generate(this.default_key_size, this.default_public_exponent)\n                    }\n                    return this.key\n                }\n                ,\n                t.prototype.getPrivateKey = function() {\n                    return this.getKey().getPrivateKey()\n                }\n                ,\n                t.prototype.getPrivateKeyB64 = function() {\n                    return this.getKey().getPrivateBaseKeyB64()\n                }\n                ,\n                t.prototype.getPublicKey = function() {\n                    return this.getKey().getPublicKey()\n                }\n                ,\n                t.prototype.getPublicKeyB64 = function() {\n                    return this.getKey().getPublicBaseKeyB64()\n                }\n                ,\n                t.version = \"3.0.0-rc.1\",\n                t\n            }();\n            window.JSEncrypt = rt,\n            t.JSEncrypt = rt,\n            t.default = rt,\n            Object.defineProperty(t, \"__esModule\", {\n                value: !0\n            })\n        }(e)\n    },\n       19:function(F, K, W) {\n        var z;\n        !function(i, h) {\n            \"use strict\";\n            function t(t) {\n                for (var e = {}, n = 0; n < t.length; n++)\n                    e[t[n].toUpperCase()] = t[n];\n                return e\n            }\n            function o(t, e) {\n                return typeof t == u && -1 !== L(e).indexOf(L(t))\n            }\n            function s(t, e) {\n                if (typeof t == u)\n                    return t = t.replace(/^\\s\\s*/, \"\").replace(/\\s\\s*$/, \"\"),\n                    typeof e == c ? t : t.substring(0, 255)\n            }\n            function a(t, e) {\n                for (var n, r, i, o, s, a, c = 0; c < e.length && !s; ) {\n                    var u = e[c]\n                      , l = e[c + 1];\n                    for (n = r = 0; n < u.length && !s; )\n                        if (s = u[n++].exec(t))\n                            for (i = 0; i < l.length; i++)\n                                a = s[++r],\n                                typeof (o = l[i]) == d && 0 < o.length ? 2 === o.length ? typeof o[1] == f ? this[o[0]] = o[1].call(this, a) : this[o[0]] = o[1] : 3 === o.length ? typeof o[1] != f || o[1].exec && o[1].test ? this[o[0]] = a ? a.replace(o[1], o[2]) : h : this[o[0]] = a ? o[1].call(this, a, o[2]) : h : 4 === o.length && (this[o[0]] = a ? o[3].call(this, a.replace(o[1], o[2])) : h) : this[o] = a || h;\n                    c += 2\n                }\n            }\n            function e(t, e) {\n                for (var n in e)\n                    if (typeof e[n] == d && 0 < e[n].length) {\n                        for (var r = 0; r < e[n].length; r++)\n                            if (o(e[n][r], t))\n                                return \"?\" === n ? h : n\n                    } else if (o(e[n], t))\n                        return \"?\" === n ? h : n;\n                return t\n            }\n            var f = \"function\"\n              , c = \"undefined\"\n              , d = \"object\"\n              , u = \"string\"\n              , l = \"model\"\n              , p = \"name\"\n              , g = \"type\"\n              , m = \"vendor\"\n              , v = \"version\"\n              , y = \"architecture\"\n              , n = \"console\"\n              , r = \"mobile\"\n              , b = \"tablet\"\n              , w = \"smarttv\"\n              , x = \"wearable\"\n              , T = \"embedded\"\n              , E = \"Amazon\"\n              , S = \"Apple\"\n              , _ = \"BlackBerry\"\n              , A = \"Browser\"\n              , k = \"Chrome\"\n              , C = \"Firefox\"\n              , D = \"Google\"\n              , N = \"Microsoft\"\n              , O = \"Motorola\"\n              , R = \"Opera\"\n              , I = \"Samsung\"\n              , P = \"Sony\"\n              , j = \"Zebra\"\n              , B = \"Facebook\"\n              , L = function(t) {\n                return t.toLowerCase()\n            }\n              , M = {\n                ME: \"4.90\",\n                \"NT 3.11\": \"NT3.51\",\n                \"NT 4.0\": \"NT4.0\",\n                2e3: \"NT 5.0\",\n                XP: [\"NT 5.1\", \"NT 5.2\"],\n                Vista: \"NT 6.0\",\n                7: \"NT 6.1\",\n                8: \"NT 6.2\",\n                8.1: \"NT 6.3\",\n                10: [\"NT 6.4\", \"NT 10.0\"],\n                RT: \"ARM\"\n            }\n              , V = {\n                browser: [[/\\b(?:crmo|crios)\\/([\\w\\.]+)/i], [v, [p, \"Chrome\"]], [/edg(?:e|ios|a)?\\/([\\w\\.]+)/i], [v, [p, \"Edge\"]], [/(opera mini)\\/([-\\w\\.]+)/i, /(opera [mobiletab]{3,6})\\b.+version\\/([-\\w\\.]+)/i, /(opera)(?:.+version\\/|[\\/ ]+)([\\w\\.]+)/i], [p, v], [/opios[\\/ ]+([\\w\\.]+)/i], [v, [p, R + \" Mini\"]], [/\\bopr\\/([\\w\\.]+)/i], [v, [p, R]], [/(kindle)\\/([\\w\\.]+)/i, /(lunascape|maxthon|netfront|jasmine|blazer)[\\/ ]?([\\w\\.]*)/i, /(avant |iemobile|slim)(?:browser)?[\\/ ]?([\\w\\.]*)/i, /(ba?idubrowser)[\\/ ]?([\\w\\.]+)/i, /(?:ms|\\()(ie) ([\\w\\.]+)/i, /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq)\\/([-\\w\\.]+)/i, /(weibo)__([\\d\\.]+)/i], [p, v], [/(?:\\buc? ?browser|(?:juc.+)ucweb)[\\/ ]?([\\w\\.]+)/i], [v, [p, \"UC\" + A]], [/\\bqbcore\\/([\\w\\.]+)/i], [v, [p, \"WeChat(Win) Desktop\"]], [/micromessenger\\/([\\w\\.]+)/i], [v, [p, \"WeChat\"]], [/konqueror\\/([\\w\\.]+)/i], [v, [p, \"Konqueror\"]], [/trident.+rv[: ]([\\w\\.]{1,9})\\b.+like gecko/i], [v, [p, \"IE\"]], [/yabrowser\\/([\\w\\.]+)/i], [v, [p, \"Yandex\"]], [/(avast|avg)\\/([\\w\\.]+)/i], [[p, /(.+)/, \"$1 Secure \" + A], v], [/\\bfocus\\/([\\w\\.]+)/i], [v, [p, C + \" Focus\"]], [/\\bopt\\/([\\w\\.]+)/i], [v, [p, R + \" Touch\"]], [/coc_coc\\w+\\/([\\w\\.]+)/i], [v, [p, \"Coc Coc\"]], [/dolfin\\/([\\w\\.]+)/i], [v, [p, \"Dolphin\"]], [/coast\\/([\\w\\.]+)/i], [v, [p, R + \" Coast\"]], [/miuibrowser\\/([\\w\\.]+)/i], [v, [p, \"MIUI \" + A]], [/fxios\\/([-\\w\\.]+)/i], [v, [p, C]], [/\\bqihu|(qi?ho?o?|360)browser/i], [[p, \"360 \" + A]], [/(oculus|samsung|sailfish)browser\\/([\\w\\.]+)/i], [[p, /(.+)/, \"$1 \" + A], v], [/(comodo_dragon)\\/([\\w\\.]+)/i], [[p, /_/g, \" \"], v], [/(electron)\\/([\\w\\.]+) safari/i, /(tesla)(?: qtcarbrowser|\\/(20\\d\\d\\.[-\\w\\.]+))/i, /m?(qqbrowser|baiduboxapp|2345Explorer)[\\/ ]?([\\w\\.]+)/i], [p, v], [/(metasr)[\\/ ]?([\\w\\.]+)/i, /(lbbrowser)/i], [p], [/((?:fban\\/fbios|fb_iab\\/fb4a)(?!.+fbav)|;fbav\\/([\\w\\.]+);)/i], [[p, B], v], [/safari (line)\\/([\\w\\.]+)/i, /\\b(line)\\/([\\w\\.]+)\\/iab/i, /(chromium|instagram)[\\/ ]([-\\w\\.]+)/i], [p, v], [/\\bgsa\\/([\\w\\.]+) .*safari\\//i], [v, [p, \"GSA\"]], [/headlesschrome(?:\\/([\\w\\.]+)| )/i], [v, [p, k + \" Headless\"]], [/ wv\\).+(chrome)\\/([\\w\\.]+)/i], [[p, k + \" WebView\"], v], [/droid.+ version\\/([\\w\\.]+)\\b.+(?:mobile safari|safari)/i], [v, [p, \"Android \" + A]], [/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\\/v?([\\w\\.]+)/i], [p, v], [/version\\/([\\w\\.]+) .*mobile\\/\\w+ (safari)/i], [v, [p, \"Mobile Safari\"]], [/version\\/([\\w\\.]+) .*(mobile ?safari|safari)/i], [v, p], [/webkit.+?(mobile ?safari|safari)(\\/[\\w\\.]+)/i], [p, [v, e, {\n                    \"1.0\": \"/8\",\n                    1.2: \"/1\",\n                    1.3: \"/3\",\n                    \"2.0\": \"/412\",\n                    \"2.0.2\": \"/416\",\n                    \"2.0.3\": \"/417\",\n                    \"2.0.4\": \"/419\",\n                    \"?\": \"/\"\n                }]], [/(webkit|khtml)\\/([\\w\\.]+)/i], [p, v], [/(navigator|netscape\\d?)\\/([-\\w\\.]+)/i], [[p, \"Netscape\"], v], [/mobile vr; rv:([\\w\\.]+)\\).+firefox/i], [v, [p, C + \" Reality\"]], [/ekiohf.+(flow)\\/([\\w\\.]+)/i, /(swiftfox)/i, /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\\/ ]?([\\w\\.\\+]+)/i, /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\\/([-\\w\\.]+)$/i, /(firefox)\\/([\\w\\.]+)/i, /(mozilla)\\/([\\w\\.]+) .+rv\\:.+gecko\\/\\d+/i, /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\\. ]?browser)[-\\/ ]?v?([\\w\\.]+)/i, /(links) \\(([\\w\\.]+)/i], [p, v]],\n                cpu: [[/(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\\)]/i], [[y, \"amd64\"]], [/(ia32(?=;))/i], [[y, L]], [/((?:i[346]|x)86)[;\\)]/i], [[y, \"ia32\"]], [/\\b(aarch64|arm(v?8e?l?|_?64))\\b/i], [[y, \"arm64\"]], [/\\b(arm(?:v[67])?ht?n?[fl]p?)\\b/i], [[y, \"armhf\"]], [/windows (ce|mobile); ppc;/i], [[y, \"arm\"]], [/((?:ppc|powerpc)(?:64)?)(?: mac|;|\\))/i], [[y, /ower/, \"\", L]], [/(sun4\\w)[;\\)]/i], [[y, \"sparc\"]], [/((?:avr32|ia64(?=;))|68k(?=\\))|\\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\\b|pa-risc)/i], [[y, L]]],\n                device: [[/\\b(sch-i[89]0\\d|shw-m380s|sm-[pt]\\w{2,4}|gt-[pn]\\d{2,4}|sgh-t8[56]9|nexus 10)/i], [l, [m, I], [g, b]], [/\\b((?:s[cgp]h|gt|sm)-\\w+|galaxy nexus)/i, /samsung[- ]([-\\w]+)/i, /sec-(sgh\\w+)/i], [l, [m, I], [g, r]], [/\\((ip(?:hone|od)[\\w ]*);/i], [l, [m, S], [g, r]], [/\\((ipad);[-\\w\\),; ]+apple/i, /applecoremedia\\/[\\w\\.]+ \\((ipad)/i, /\\b(ipad)\\d\\d?,\\d\\d?[;\\]].+ios/i], [l, [m, S], [g, b]], [/\\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\\d{2})\\b(?!.+d\\/s)/i], [l, [m, \"Huawei\"], [g, b]], [/(?:huawei|honor)([-\\w ]+)[;\\)]/i, /\\b(nexus 6p|\\w{2,4}-[atu]?[ln][01259x][012359][an]?)\\b(?!.+d\\/s)/i], [l, [m, \"Huawei\"], [g, r]], [/\\b(poco[\\w ]+)(?: bui|\\))/i, /\\b; (\\w+) build\\/hm\\1/i, /\\b(hm[-_ ]?note?[_ ]?(?:\\d\\w)?) bui/i, /\\b(redmi[\\-_ ]?(?:note|k)?[\\w_ ]+)(?: bui|\\))/i, /\\b(mi[-_ ]?(?:a\\d|one|one[_ ]plus|note lte|max)?[_ ]?(?:\\d?\\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\\))/i], [[l, /_/g, \" \"], [m, \"Xiaomi\"], [g, r]], [/\\b(mi[-_ ]?(?:pad)(?:[\\w_ ]+))(?: bui|\\))/i], [[l, /_/g, \" \"], [m, \"Xiaomi\"], [g, b]], [/; (\\w+) bui.+ oppo/i, /\\b(cph[12]\\d{3}|p(?:af|c[al]|d\\w|e[ar])[mt]\\d0|x9007|a101op)\\b/i], [l, [m, \"OPPO\"], [g, r]], [/vivo (\\w+)(?: bui|\\))/i, /\\b(v[12]\\d{3}\\w?[at])(?: bui|;)/i], [l, [m, \"Vivo\"], [g, r]], [/\\b(rmx[12]\\d{3})(?: bui|;|\\))/i], [l, [m, \"Realme\"], [g, r]], [/\\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\\b[\\w ]+build\\//i, /\\bmot(?:orola)?[- ](\\w*)/i, /((?:moto[\\w\\(\\) ]+|xt\\d{3,4}|nexus 6)(?= bui|\\)))/i], [l, [m, O], [g, r]], [/\\b(mz60\\d|xoom[2 ]{0,2}) build\\//i], [l, [m, O], [g, b]], [/((?=lg)?[vl]k\\-?\\d{3}) bui| 3\\.[-\\w; ]{10}lg?-([06cv9]{3,4})/i], [l, [m, \"LG\"], [g, b]], [/(lm(?:-?f100[nv]?|-[\\w\\.]+)(?= bui|\\))|nexus [45])/i, /\\blg[-e;\\/ ]+((?!browser|netcast|android tv)\\w+)/i, /\\blg-?([\\d\\w]+) bui/i], [l, [m, \"LG\"], [g, r]], [/(ideatab[-\\w ]+)/i, /lenovo ?(s[56]000[-\\w]+|tab(?:[\\w ]+)|yt[-\\d\\w]{6}|tb[-\\d\\w]{6})/i], [l, [m, \"Lenovo\"], [g, b]], [/(?:maemo|nokia).*(n900|lumia \\d+)/i, /nokia[-_ ]?([-\\w\\.]*)/i], [[l, /_/g, \" \"], [m, \"Nokia\"], [g, r]], [/(pixel c)\\b/i], [l, [m, D], [g, b]], [/droid.+; (pixel[\\daxl ]{0,6})(?: bui|\\))/i], [l, [m, D], [g, r]], [/droid.+ ([c-g]\\d{4}|so[-gl]\\w+|xq-a\\w[4-7][12])(?= bui|\\).+chrome\\/(?![1-6]{0,1}\\d\\.))/i], [l, [m, P], [g, r]], [/sony tablet [ps]/i, /\\b(?:sony)?sgp\\w+(?: bui|\\))/i], [[l, \"Xperia Tablet\"], [m, P], [g, b]], [/ (kb2005|in20[12]5|be20[12][59])\\b/i, /(?:one)?(?:plus)? (a\\d0\\d\\d)(?: b|\\))/i], [l, [m, \"OnePlus\"], [g, r]], [/(alexa)webm/i, /(kf[a-z]{2}wi)( bui|\\))/i, /(kf[a-z]+)( bui|\\)).+silk\\//i], [l, [m, E], [g, b]], [/((?:sd|kf)[0349hijorstuw]+)( bui|\\)).+silk\\//i], [[l, /(.+)/g, \"Fire Phone $1\"], [m, E], [g, r]], [/(playbook);[-\\w\\),; ]+(rim)/i], [l, m, [g, b]], [/\\b((?:bb[a-f]|st[hv])100-\\d)/i, /\\(bb10; (\\w+)/i], [l, [m, _], [g, r]], [/(?:\\b|asus_)(transfo[prime ]{4,10} \\w+|eeepc|slider \\w+|nexus 7|padfone|p00[cj])/i], [l, [m, \"ASUS\"], [g, b]], [/ (z[bes]6[027][012][km][ls]|zenfone \\d\\w?)\\b/i], [l, [m, \"ASUS\"], [g, r]], [/(nexus 9)/i], [l, [m, \"HTC\"], [g, b]], [/(htc)[-;_ ]{1,2}([\\w ]+(?=\\)| bui)|\\w+)/i, /(zte)[- ]([\\w ]+?)(?: bui|\\/|\\))/i, /(alcatel|geeksphone|nexian|panasonic|sony)[-_ ]?([-\\w]*)/i], [m, [l, /_/g, \" \"], [g, r]], [/droid.+; ([ab][1-7]-?[0178a]\\d\\d?)/i], [l, [m, \"Acer\"], [g, b]], [/droid.+; (m[1-5] note) bui/i, /\\bmz-([-\\w]{2,})/i], [l, [m, \"Meizu\"], [g, r]], [/\\b(sh-?[altvz]?\\d\\d[a-ekm]?)/i], [l, [m, \"Sharp\"], [g, r]], [/(blackberry|benq|palm(?=\\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\\w]*)/i, /(hp) ([\\w ]+\\w)/i, /(asus)-?(\\w+)/i, /(microsoft); (lumia[\\w ]+)/i, /(lenovo)[-_ ]?([-\\w]+)/i, /(jolla)/i, /(oppo) ?([\\w ]+) bui/i], [m, l, [g, r]], [/(archos) (gamepad2?)/i, /(hp).+(touchpad(?!.+tablet)|tablet)/i, /(kindle)\\/([\\w\\.]+)/i, /(nook)[\\w ]+build\\/(\\w+)/i, /(dell) (strea[kpr\\d ]*[\\dko])/i, /(le[- ]+pan)[- ]+(\\w{1,9}) bui/i, /(trinity)[- ]*(t\\d{3}) bui/i, /(gigaset)[- ]+(q\\w{1,9}) bui/i, /(vodafone) ([\\w ]+)(?:\\)| bui)/i], [m, l, [g, b]], [/(surface duo)/i], [l, [m, N], [g, b]], [/droid [\\d\\.]+; (fp\\du?)(?: b|\\))/i], [l, [m, \"Fairphone\"], [g, r]], [/(u304aa)/i], [l, [m, \"AT&T\"], [g, r]], [/\\bsie-(\\w*)/i], [l, [m, \"Siemens\"], [g, r]], [/\\b(rct\\w+) b/i], [l, [m, \"RCA\"], [g, b]], [/\\b(venue[\\d ]{2,7}) b/i], [l, [m, \"Dell\"], [g, b]], [/\\b(q(?:mv|ta)\\w+) b/i], [l, [m, \"Verizon\"], [g, b]], [/\\b(?:barnes[& ]+noble |bn[rt])([\\w\\+ ]*) b/i], [l, [m, \"Barnes & Noble\"], [g, b]], [/\\b(tm\\d{3}\\w+) b/i], [l, [m, \"NuVision\"], [g, b]], [/\\b(k88) b/i], [l, [m, \"ZTE\"], [g, b]], [/\\b(nx\\d{3}j) b/i], [l, [m, \"ZTE\"], [g, r]], [/\\b(gen\\d{3}) b.+49h/i], [l, [m, \"Swiss\"], [g, r]], [/\\b(zur\\d{3}) b/i], [l, [m, \"Swiss\"], [g, b]], [/\\b((zeki)?tb.*\\b) b/i], [l, [m, \"Zeki\"], [g, b]], [/\\b([yr]\\d{2}) b/i, /\\b(dragon[- ]+touch |dt)(\\w{5}) b/i], [[m, \"Dragon Touch\"], l, [g, b]], [/\\b(ns-?\\w{0,9}) b/i], [l, [m, \"Insignia\"], [g, b]], [/\\b((nxa|next)-?\\w{0,9}) b/i], [l, [m, \"NextBook\"], [g, b]], [/\\b(xtreme\\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i], [[m, \"Voice\"], l, [g, r]], [/\\b(lvtel\\-)?(v1[12]) b/i], [[m, \"LvTel\"], l, [g, r]], [/\\b(ph-1) /i], [l, [m, \"Essential\"], [g, r]], [/\\b(v(100md|700na|7011|917g).*\\b) b/i], [l, [m, \"Envizen\"], [g, b]], [/\\b(trio[-\\w\\. ]+) b/i], [l, [m, \"MachSpeed\"], [g, b]], [/\\btu_(1491) b/i], [l, [m, \"Rotor\"], [g, b]], [/(shield[\\w ]+) b/i], [l, [m, \"Nvidia\"], [g, b]], [/(sprint) (\\w+)/i], [m, l, [g, r]], [/(kin\\.[onetw]{3})/i], [[l, /\\./g, \" \"], [m, N], [g, r]], [/droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\\)/i], [l, [m, j], [g, b]], [/droid.+; (ec30|ps20|tc[2-8]\\d[kx])\\)/i], [l, [m, j], [g, r]], [/(ouya)/i, /(nintendo) ([wids3utch]+)/i], [m, l, [g, n]], [/droid.+; (shield) bui/i], [l, [m, \"Nvidia\"], [g, n]], [/(playstation [345portablevi]+)/i], [l, [m, P], [g, n]], [/\\b(xbox(?: one)?(?!; xbox))[\\); ]/i], [l, [m, N], [g, n]], [/smart-tv.+(samsung)/i], [m, [g, w]], [/hbbtv.+maple;(\\d+)/i], [[l, /^/, \"SmartTV\"], [m, I], [g, w]], [/(nux; netcast.+smarttv|lg (netcast\\.tv-201\\d|android tv))/i], [[m, \"LG\"], [g, w]], [/(apple) ?tv/i], [m, [l, S + \" TV\"], [g, w]], [/crkey/i], [[l, k + \"cast\"], [m, D], [g, w]], [/droid.+aft(\\w)( bui|\\))/i], [l, [m, E], [g, w]], [/\\(dtv[\\);].+(aquos)/i], [l, [m, \"Sharp\"], [g, w]], [/\\b(roku)[\\dx]*[\\)\\/]((?:dvp-)?[\\d\\.]*)/i, /hbbtv\\/\\d+\\.\\d+\\.\\d+ +\\([\\w ]*; *(\\w[^;]*);([^;]*)/i], [[m, s], [l, s], [g, w]], [/\\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\\b/i], [[g, w]], [/((pebble))app/i], [m, l, [g, x]], [/droid.+; (glass) \\d/i], [l, [m, D], [g, x]], [/droid.+; (wt63?0{2,3})\\)/i], [l, [m, j], [g, x]], [/(quest( 2)?)/i], [l, [m, B], [g, x]], [/(tesla)(?: qtcarbrowser|\\/[-\\w\\.]+)/i], [m, [g, T]], [/droid .+?; ([^;]+?)(?: bui|\\) applew).+? mobile safari/i], [l, [g, r]], [/droid .+?; ([^;]+?)(?: bui|\\) applew).+?(?! mobile) safari/i], [l, [g, b]], [/\\b((tablet|tab)[;\\/]|focus\\/\\d(?!.+mobile))/i], [[g, b]], [/(phone|mobile(?:[;\\/]| safari)|pda(?=.+windows ce))/i], [[g, r]], [/(android[-\\w\\. ]{0,9});.+buil/i], [l, [m, \"Generic\"]]],\n                engine: [[/windows.+ edge\\/([\\w\\.]+)/i], [v, [p, \"EdgeHTML\"]], [/webkit\\/537\\.36.+chrome\\/(?!27)([\\w\\.]+)/i], [v, [p, \"Blink\"]], [/(presto)\\/([\\w\\.]+)/i, /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\\/([\\w\\.]+)/i, /ekioh(flow)\\/([\\w\\.]+)/i, /(khtml|tasman|links)[\\/ ]\\(?([\\w\\.]+)/i, /(icab)[\\/ ]([23]\\.[\\d\\.]+)/i], [p, v], [/rv\\:([\\w\\.]{1,9})\\b.+(gecko)/i], [v, p]],\n                os: [[/microsoft (windows) (vista|xp)/i], [p, v], [/(windows) nt 6\\.2; (arm)/i, /(windows (?:phone(?: os)?|mobile))[\\/ ]?([\\d\\.\\w ]*)/i, /(windows)[\\/ ]?([ntce\\d\\. ]+\\w)(?!.+xbox)/i], [p, [v, e, M]], [/(win(?=3|9|n)|win 9x )([nt\\d\\.]+)/i], [[p, \"Windows\"], [v, e, M]], [/ip[honead]{2,4}\\b(?:.*os ([\\w]+) like mac|; opera)/i, /cfnetwork\\/.+darwin/i], [[v, /_/g, \".\"], [p, \"iOS\"]], [/(mac os x) ?([\\w\\. ]*)/i, /(macintosh|mac_powerpc\\b)(?!.+haiku)/i], [[p, \"Mac OS\"], [v, /_/g, \".\"]], [/droid ([\\w\\.]+)\\b.+(android[- ]x86)/i], [v, p], [/(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\\/ ]?([\\w\\.]*)/i, /(blackberry)\\w*\\/([\\w\\.]*)/i, /(tizen|kaios)[\\/ ]([\\w\\.]+)/i, /\\((series40);/i], [p, v], [/\\(bb(10);/i], [v, [p, _]], [/(?:symbian ?os|symbos|s60(?=;)|series60)[-\\/ ]?([\\w\\.]*)/i], [v, [p, \"Symbian\"]], [/mozilla\\/[\\d\\.]+ \\((?:mobile|tablet|tv|mobile; [\\w ]+); rv:.+ gecko\\/([\\w\\.]+)/i], [v, [p, C + \" OS\"]], [/web0s;.+rt(tv)/i, /\\b(?:hp)?wos(?:browser)?\\/([\\w\\.]+)/i], [v, [p, \"webOS\"]], [/crkey\\/([\\d\\.]+)/i], [v, [p, k + \"cast\"]], [/(cros) [\\w]+ ([\\w\\.]+\\w)/i], [[p, \"Chromium OS\"], v], [/(nintendo|playstation) ([wids345portablevuch]+)/i, /(xbox); +xbox ([^\\);]+)/i, /\\b(joli|palm)\\b ?(?:os)?\\/?([\\w\\.]*)/i, /(mint)[\\/\\(\\) ]?(\\w*)/i, /(mageia|vectorlinux)[; ]/i, /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\\/ ]?(?!chrom|package)([-\\w\\.]*)/i, /(hurd|linux) ?([\\w\\.]*)/i, /(gnu) ?([\\w\\.]*)/i, /\\b([-frentopcghs]{0,5}bsd|dragonfly)[\\/ ]?(?!amd|[ix346]{1,2}86)([\\w\\.]*)/i, /(haiku) (\\w+)/i], [p, v], [/(sunos) ?([\\w\\.\\d]*)/i], [[p, \"Solaris\"], v], [/((?:open)?solaris)[-\\/ ]?([\\w\\.]*)/i, /(aix) ((\\d)(?=\\.|\\)| )[\\w\\.])*/i, /\\b(beos|os\\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, /(unix) ?([\\w\\.]*)/i], [p, v]]\n            }\n              , q = function(t, e) {\n                if (typeof t == d && (e = t,\n                t = h),\n                !(this instanceof q))\n                    return new q(t,e).getResult();\n                var n = t || (typeof i != c && i.navigator && i.navigator.userAgent ? i.navigator.userAgent : \"\")\n                  , r = e ? function(t, e) {\n                    var n = {};\n                    for (var r in t)\n                        e[r] && e[r].length % 2 == 0 ? n[r] = e[r].concat(t[r]) : n[r] = t[r];\n                    return n\n                }(V, e) : V;\n                return this.getBrowser = function() {\n                    var t = {};\n                    return t[p] = h,\n                    t[v] = h,\n                    a.call(t, n, r.browser),\n                    t.major = function(t) {\n                        return typeof t == u ? t.replace(/[^\\d\\.]/g, \"\").split(\".\")[0] : h\n                    }(t.version),\n                    t\n                }\n                ,\n                this.getCPU = function() {\n                    var t = {};\n                    return t[y] = h,\n                    a.call(t, n, r.cpu),\n                    t\n                }\n                ,\n                this.getDevice = function() {\n                    var t = {};\n                    return t[m] = h,\n                    t[l] = h,\n                    t[g] = h,\n                    a.call(t, n, r.device),\n                    t\n                }\n                ,\n                this.getEngine = function() {\n                    var t = {};\n                    return t[p] = h,\n                    t[v] = h,\n                    a.call(t, n, r.engine),\n                    t\n                }\n                ,\n                this.getOS = function() {\n                    var t = {};\n                    return t[p] = h,\n                    t[v] = h,\n                    a.call(t, n, r.os),\n                    t\n                }\n                ,\n                this.getResult = function() {\n                    return {\n                        ua: this.getUA(),\n                        browser: this.getBrowser(),\n                        engine: this.getEngine(),\n                        os: this.getOS(),\n                        device: this.getDevice(),\n                        cpu: this.getCPU()\n                    }\n                }\n                ,\n                this.getUA = function() {\n                    return n\n                }\n                ,\n                this.setUA = function(t) {\n                    return n = typeof t == u && 255 < t.length ? s(t, 255) : t,\n                    this\n                }\n                ,\n                this.setUA(n),\n                this\n            };\n            q.VERSION = \"1.0.2\",\n            q.BROWSER = t([p, v, \"major\"]),\n            q.CPU = t([y]),\n            q.DEVICE = t([l, m, g, n, r, w, b, x, T]),\n            q.ENGINE = q.OS = t([p, v]),\n            typeof K != c ? (typeof F != c && F.exports && (K = F.exports = q),\n            K.UAParser = q) : W(51) ? (z = function() {\n                return q\n            }\n            .call(K, W, K, F)) === h || (F.exports = z) : typeof i != c && (i.UAParser = q);\n            var U = typeof i != c && (i.jQuery || i.Zepto);\n            if (U && !U.ua) {\n                var H = new q;\n                U.ua = H.getResult(),\n                U.ua.get = function() {\n                    return H.getUA()\n                }\n                ,\n                U.ua.set = function(t) {\n                    H.setUA(t);\n                    var e = H.getResult();\n                    for (var n in e)\n                        U.ua[n] = e[n]\n                }\n            }\n        }(\"object\" == typeof window ? window : this)\n    },\n       2: function(t, e, n) {\n    \"use strict\";\n    n.r(e),\n    n.d(e, \"makeParam\", function() {\n        return o\n    }),\n    n.d(e, \"sendFee\", function() {\n        return r\n    });\n    var o = function(e) {\n        var n = \"\";\n        try {\n            n = JSON.stringify(e.detail)\n        } catch (t) {\n            n = Object.prototype.toString.call(e.detail)\n        }\n        return {\n            type: \"error\",\n            common: {\n                pid: e.pid,\n                uuid: e.uuid,\n                ucid: e.ucid,\n                is_test: \"test\" === e.env,\n                record: {\n                    time_on_page: !0,\n                    performance: !0,\n                    js_error: !0,\n                    js_error_report_config: {\n                        ERROR_RUNTIME: !0,\n                        ERROR_SCRIPT: !0,\n                        ERROR_STYLE: !0,\n                        ERROR_IMAGE: !0,\n                        ERROR_AUDIO: !0,\n                        ERROR_VIDEO: !0,\n                        ERROR_CONSOLE: !0,\n                        ERROR_TRY_CATCH: !0\n                    }\n                },\n                version: \"1.0.0\",\n                timestamp: Date.now(),\n                runtime_version: e.version,\n                sdk_version: \"1.3.0\",\n                page_type: e.pageUrl || \"/\"\n            },\n            code: 8,\n            extra: {\n                desc: n\n            },\n            detail: {\n                error_no: e.errorName || \"unknown_error\",\n                url: e.pageUrl || \"\",\n                http_code: 0,\n                during_ms: 0,\n                request_size_b: 0,\n                response_size_b: 0\n            }\n        }\n    }\n      , r = function(t) {\n        var e = t.errorName\n          , n = t.detail\n          , r = o({\n            detail: n,\n            env: /test/.test(window.location.href) ? \"test\" : \"prod\",\n            errorName: e,\n            pid: \"pc_login_sdk\",\n            ucid: 1,\n            uuid: \"\",\n            version: \"1.2.0\"\n        })\n          , i = \"https://dig.lianjia.com/fee.gif?d=\" + encodeURIComponent(JSON.stringify(r));\n        try {\n            new Image(0,0).src = i\n        } catch (t) {}\n    }\n},\n       0: function(t, e, n) {\n    \"use strict\";\n    n.r(e),\n    n.d(e, \"scene\", function() {\n        return L\n    }),\n    n.d(e, \"withCredentialDomain\", function() {\n        return M\n    }),\n    n.d(e, \"APIEndpoint\", function() {\n        return r\n    }),\n    n.d(e, \"PasswordAPIEndpoint\", function() {\n        return o\n    }),\n    n.d(e, \"captchaDomain\", function() {\n        return a\n    }),\n    n.d(e, \"captchaJSAddr\", function() {\n        return u\n    }),\n    n.d(e, \"APIDomainKe\", function() {\n        return h\n    }),\n    n.d(e, \"APIDomainDeyoulife\", function() {\n        return d\n    }),\n    n.d(e, \"APIDomainLianjia\", function() {\n        return g\n    }),\n    n.d(e, \"mainAuthMethodName\", function() {\n        return v\n    }),\n    n.d(e, \"TitleEnum\", function() {\n        return b\n    }),\n    n.d(e, \"allianceMethods\", function() {\n        return x\n    }),\n    n.d(e, \"SupportedIdentityCheckMethodsEnum\", function() {\n        return E\n    }),\n    n.d(e, \"accountSystem\", function() {\n        return _\n    }),\n    n.d(e, \"smsTypeEnum\", function() {\n        return k\n    }),\n    n.d(e, \"SceneKey\", function() {\n        return D\n    }),\n    n.d(e, \"AuthStatus\", function() {\n        return O\n    }),\n    n.d(e, \"Gender\", function() {\n        return I\n    }),\n    n.d(e, \"Views\", function() {\n        return j\n    });\n    var r, i, o, s, a, c, u, l, h, f, d, p, g, m, v, y, b, w, x, T, E, S, _, A, k, C, D, N, O, R, I, P, j, B, L = [\"0x6c\", \"0x6f\", \"0x67\", \"0x69\", \"0x6e\", \"0x5f\", \"0x73\", \"0x6c\", \"0x69\", \"0x64\", \"0x65\", \"0x72\"].map(function(t) {\n        return String.fromCharCode(Number(t))\n    }).reduce(function(t, e) {\n        return t + e\n    }), M = [\"ke.com\", \"lianjia.com\", \"deyoulife.com\"];\n    (i = r = r || {}).init = \"/authentication/initialize\",\n    i.auth = \"/authentication/authenticate\",\n    i.sms = \"/authentication/mfa/sms\",\n    i.getinfo = \"/serviceValidate\",\n    i.register = \"/registration/register\",\n    i.logout = \"/authentication/destroy\",\n    i.userLogout = \"/logout\",\n    i.qr = \"/qrcode\",\n    i.polling = \"/qrcode/status\",\n    (s = o = o || {}).init = \"/authentication/password/initialize\",\n    s.change = \"/authentication/password\",\n    s.reset = \"/authentication/reset-password\",\n    s.validate = \"/authentication/password/action/validate\",\n    (c = a = a || {}).dev = \"//test3-captcha.lianjia.com\",\n    c.test = \"//test3-captcha.lianjia.com\",\n    c.prod = \"https://captcha.lianjia.com\",\n    c.preview = \"https://captcha.lianjia.com\",\n    (l = u = u || {}).dev = \"//test-s1.ljcdn.com/test-captcha-js-sdk-v2/captcha.js\",\n    l.test = \"//test-s1.ljcdn.com/test-captcha-js-sdk-v2/captcha.js\",\n    l.prod = \"https://s1.ljcdn.com/captcha-js-sdk-v2/captcha.js\",\n    l.preview = \"https://s1.ljcdn.com/captcha-js-sdk-v2/captcha.js\",\n    (f = h = h || {}).dev = \"http://alps-passport.login-dev.tta.test.ke.com\",\n    f.test = \"https://test-clogin.ke.com\",\n    f.prod = \"https://clogin.ke.com\",\n    f.preview = \"https://clogin.ke.com\",\n    (p = d = d || {}).dev = \"http://alps-passport.login-dev.tta.test.ke.com\",\n    p.test = \"https://test-clogin.ke.com\",\n    p.prod = \"https://clogin.ke.com\",\n    p.preview = \"https://clogin.ke.com\",\n    (m = g = g || {}).dev = \"http://alps-passport.login-dev.tta.test.ke.com\",\n    m.test = \"https://test-clogin.lianjia.com\",\n    m.prod = \"https://clogin.lianjia.com\",\n    m.preview = \"https://clogin.lianjia.com\",\n    (y = v = v || {}).PASSWORD = \"username-password\",\n    y.QR = \"qrcode\",\n    y.PHONE = \"phone-code\",\n    (w = b = b || {})[\"username-password\"] = \"账号密码登录\",\n    w.qrcode = \"二维码登录\",\n    w[\"phone-code\"] = \"短信验证码登录\",\n    (T = x = x || {}).security = \"security-code\",\n    T.shield = \"shield-code\",\n    (S = E = E || {}).id_num = \"id-num\",\n    S.security_code = \"security-code\",\n    S.old_password = \"old-password\",\n    S.security_code_id_num = \"security-code&id-num\",\n    (A = _ = _ || {}).commerceSeller = \"commerce-seller\",\n    A.customer = \"customer\",\n    A.employee = \"employee\",\n    A.guangsha = \"guangsha\",\n    A.rentSaas = \"rent-saas\",\n    (C = k = k || {}).sms = \"sms\",\n    C.voice = \"voice\",\n    (N = D = D || {}).DEFAULT = \"DEFAULT\",\n    N.WHEN_LOGIN = \"WHEN_LOGIN\",\n    N.WHEN_VALIDATE_PASSWORD = \"WHEN_VALIDATE_PASSWORD\",\n    N.WHEN_REGISTER = \"WHEN_REGISTER\",\n    N.WHEN_RESET_PASSWORD = \"WHEN_RESET_PASSWORD\",\n    N.WHEN_LOGOUT = \"WHEN_LOGOUT\",\n    N.WHEN_SEND_SMS = \"WHEN_SEND_SMS\",\n    N.WHEN_RESET_PASSWORD_SEND_SMS = \"WHEN_RESET_PASSWORD_SEND_SMS\",\n    (R = O = O || {}).PASS = \"PASS\",\n    R.WARN = \"WARN\",\n    (P = I = I || {}).MALE = \"MALE\",\n    P.FEMALE = \"FEMALE\",\n    (B = j = j || {})[B.passwordlogin = 0] = \"passwordlogin\",\n    B[B.smslogin = 1] = \"smslogin\",\n    B[B.resetpassword = 2] = \"resetpassword\",\n    B[B.register = 3] = \"register\",\n    e.default = {\n        scene: L,\n        APIEndpoint: r,\n        PasswordAPIEndpoint: o,\n        captchaDomain: a,\n        captchaJSAddr: u,\n        mainAuthMethodName: v,\n        TitleEnum: b,\n        allianceMethods: x,\n        accountSystem: _,\n        Gender: I,\n        SceneKey: D,\n        AuthStatus: O,\n        APIDomainKe: h,\n        APIDomainLianjia: g,\n        Views: j\n    }\n},\n       1:function(t, e, n) {\n    \"use strict\";\n    n.r(e),\n    n.d(e, \"loadScriptWithPromise\", function() {\n        return f\n    }),\n    n.d(e, \"commonValidator\", function() {\n        return d\n    }),\n    n.d(e, \"triggerInput\", function() {\n        return p\n    }),\n    n.d(e, \"maskPhoneNumber\", function() {\n        return g\n    }),\n    n.d(e, \"ulog\", function() {\n        return m\n    }),\n    n.d(e, \"fetch\", function() {\n        return v\n    }),\n    n.d(e, \"Xml2Json\", function() {\n        return y\n    }),\n    n.d(e, \"parseUserInfo\", function() {\n        return b\n    }),\n    n.d(e, \"cookie\", function() {\n        return w\n    }),\n    n.d(e, \"getEnv\", function() {\n        return x\n    }),\n    n.d(e, \"parseURL\", function() {\n        return T\n    }),\n    n.d(e, \"env\", function() {\n        return E\n    }),\n    n.d(e, \"plat\", function() {\n        return S\n    }),\n    n.d(e, \"withCredential\", function() {\n        return _\n    }),\n    n.d(e, \"getQuery\", function() {\n        return A\n    });\n    var r = n(7)\n      , o = n.n(r)\n      , i = n(4)\n      , a = n.n(i);\n    a.a.defaults.withCredentials = !0;\n    function s(t) {\n        var e = document.createElement(\"b\");\n        return e.innerHTML = \"\\x3c!--[if IE \" + t + \"]><i></i><![endif]--\\x3e\",\n        1 === e.getElementsByTagName(\"i\").length\n    }\n    function c(s) {\n        return window.XDomainRequest ? new Promise(function(e, n) {\n            var t = s.method || \"GET\"\n              , r = s.timeout || 3e4\n              , i = s.data || s.params || {};\n            i instanceof Object && (i = JSON.stringify(i));\n            var o = new window.XDomainRequest;\n            o.open(t, s.url),\n            o.timeout = r,\n            o.onload = function() {\n                try {\n                    var t = JSON.parse(o.responseText);\n                    return e(t.data)\n                } catch (t) {\n                    n(t)\n                }\n                return n({})\n            }\n            ,\n            o.onprogress = function() {}\n            ,\n            o.ontimeout = function() {\n                return n(\"XDomainRequest timeout\")\n            }\n            ,\n            o.onerror = function() {\n                return n(\"XDomainRequest error\")\n            }\n            ,\n            setTimeout(function() {\n                o.send(i)\n            }, 0)\n        }\n        ) : a()(s)\n    }\n    var u, l, h, f = function(i) {\n        return new Promise(function(t, e) {\n            var n = o()(i);\n            if (document.querySelector(\"#md5\" + n))\n                return t(!0);\n            var r = document.createElement(\"script\");\n            r.src = i,\n            r.id = \"md5\" + n,\n            r.addEventListener(\"load\", function() {\n                t(!0)\n            }),\n            document.head.appendChild(r)\n        }\n        )\n    }, d = {\n        mail: function(t) {\n            return /.*\\@.+\\..+/.test(t)\n        },\n        mobile: function(t) {\n            return /1\\d{10}/.test(t)\n        },\n        pasword: function(t) {\n            return /(?!^[0-9]+$)(?!^[A-Za-z]+$)(?!^[_\\-+=(){},.;!~'@#$%^&*]+$).{8,}/.test(t)\n        }\n    }, p = function(t, e) {\n        var n = document.querySelector(t);\n        Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, \"value\").set.call(n, e);\n        var r = new Event(\"input\",{\n            bubbles: !0\n        });\n        n.dispatchEvent(r)\n    }, g = function(t) {\n        return t.slice(0, 3) + \"****\" + t.slice(7, t.length)\n    }, m = function() {}, v = function(t) {\n        return (t.url && function(t) {\n            var e = /^(https?):\\/\\/([a-zA-Z\\.\\-\\_]+)\\/?(:\\d+)?/.exec(t)\n              , n = /^(https?):\\/\\/([a-zA-Z\\.\\-\\_]+)\\/?(:\\d+)?/.exec(window.location.href)\n              , r = !1;\n            return null !== e && null !== n && (r = e[1] === n[1] && e[2] === n[2] && e[3] === n[3]),\n            r\n        }(t.url) && (s(9) || s(8) || s(7) || s(6) || s(5) || s(4)) ? c : a.a)(t)\n    }, y = function t(e) {\n        var n = {};\n        if (e.nodeType === Node.ELEMENT_NODE) {\n            var r = e.attributes;\n            if (0 < r.length)\n                for (var i = 0; i < r.length; i++)\n                    n[\"@\" + r[i].nodeName] = r[i].value\n        } else\n            e.nodeType === Node.TEXT_NODE && (n = \"\" === e.nodeValue.replace(/[\\ +\\r\\n]/g, \"\") ? \"\" : e.nodeValue);\n        if (e.hasChildNodes())\n            for (var o = e.childNodes, s = 0; s < o.length; s++) {\n                var a = o[s].nodeName;\n                if (void 0 === n[a]) {\n                    \"\" !== (u = t(o[s])) && (n[a] = u)\n                } else {\n                    if (void 0 === n[a].push) {\n                        var c = n[a];\n                        n[a] = [],\n                        n[a].push(c)\n                    }\n                    var u;\n                    \"\" !== (u = t(o[s])) && n[a].push(u)\n                }\n            }\n        return n\n    }, b = function(t) {\n        return {\n            username: t[\"cas:serviceResponse\"][\"cas:authenticationSuccess\"][\"cas:attributes\"][\"cas:displayName\"][\"#text\"],\n            ucid: t[\"cas:serviceResponse\"][\"cas:authenticationSuccess\"][\"cas:attributes\"][\"cas:ucid\"][\"#text\"]\n        }\n    }, w = {\n        set: function(t, e, n) {\n            var r = new Date;\n            r.setTime(r.getTime() + 24 * n * 60 * 60 * 1e3);\n            var i = \"expires=\" + r.toUTCString();\n            document.cookie = t + \"=\" + e + \";\" + i + \";path=/\"\n        },\n        get: function(t) {\n            for (var e = t + \"=\", n = document.cookie.split(\";\"), r = 0; r < n.length; r++) {\n                for (var i = n[r]; \" \" == i.charAt(0); )\n                    i = i.substring(1);\n                if (0 == i.indexOf(e))\n                    return i.substring(e.length, i.length)\n            }\n            return \"\"\n        }\n    }, x = function(t) {\n        var e = T(window.location.href);\n        return /dev/.test(t) || /^http:\\/\\/localhost/.test(e.url) || \"127.0.0.1\" === e.host ? \"dev\" : /test/.test(t) ? \"test\" : \"prod\"\n    }, T = function(t) {\n        if (!t)\n            return null;\n        var e = [\"url\", \"origin\", \"scheme\", \"slash\", \"host\", \"port\", \"path\", \"query\", \"hash\"]\n          , n = /^((?:([A-Za-z]+)?:?(\\/{0,3}))?([0-9.\\-A-Za-z]+\\.[0-9A-Za-z]+)?(?::(\\d+))?)(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$/.exec(t)\n          , r = {};\n        if (null !== n)\n            for (var i = 0, o = e.length; i < o; i += 1)\n                r[e[i]] = n[i] || \"\";\n        return r\n    }, E = (u = T(window.location.href).host,\n    x(u)), S = (l = T(window.location.href).host,\n    /lianjia/.test(l) ? \"lianjia\" : \"ke\"), _ = (h = T(window.location.href).host,\n    !!(/^(.*\\.)?lianjia\\.com/.test(h) || /^(.*\\.)?ke\\.com/.test(h) || /^(.*\\.)?deyoulife\\.com/.test(h))), A = function(t, e) {\n        var n = new RegExp(\"(^|&)\" + t + \"=([^&]*)(&|$)\",\"i\")\n          , r = e.split(\"?\")[1].match(n);\n        return null != r ? r[2] : null\n    };\n    \"prod\" !== E && (window.fillValueToEl || (window.fillValueToEl = function(t, e) {\n        return p(e, t)\n    }\n    )),\n    e.default = {\n        loadScriptWithPromise: f,\n        md5: o.a,\n        triggerInput: p,\n        commonValidator: d,\n        maskPhoneNumber: g,\n        ulog: m,\n        fetch: v,\n        parseUserInfo: b,\n        cookie: w,\n        getQuery: A\n    }\n},\n        7:function(t, e, n) {\n    var v, y, b, w, x;\n    v = n(30),\n    y = n(10).utf8,\n    b = n(31),\n    w = n(10).bin,\n    (x = function(t, e) {\n        t.constructor == String ? t = e && \"binary\" === e.encoding ? w.stringToBytes(t) : y.stringToBytes(t) : b(t) ? t = Array.prototype.slice.call(t, 0) : Array.isArray(t) || (t = t.toString());\n        for (var n = v.bytesToWords(t), r = 8 * t.length, i = 1732584193, o = -271733879, s = -1732584194, a = 271733878, c = 0; c < n.length; c++)\n            n[c] = 16711935 & (n[c] << 8 | n[c] >>> 24) | 4278255360 & (n[c] << 24 | n[c] >>> 8);\n        n[r >>> 5] |= 128 << r % 32,\n        n[14 + (64 + r >>> 9 << 4)] = r;\n        var u = x._ff\n          , l = x._gg\n          , h = x._hh\n          , f = x._ii;\n        for (c = 0; c < n.length; c += 16) {\n            var d = i\n              , p = o\n              , g = s\n              , m = a;\n            o = f(o = f(o = f(o = f(o = h(o = h(o = h(o = h(o = l(o = l(o = l(o = l(o = u(o = u(o = u(o = u(o, s = u(s, a = u(a, i = u(i, o, s, a, n[c + 0], 7, -680876936), o, s, n[c + 1], 12, -389564586), i, o, n[c + 2], 17, 606105819), a, i, n[c + 3], 22, -1044525330), s = u(s, a = u(a, i = u(i, o, s, a, n[c + 4], 7, -176418897), o, s, n[c + 5], 12, 1200080426), i, o, n[c + 6], 17, -1473231341), a, i, n[c + 7], 22, -45705983), s = u(s, a = u(a, i = u(i, o, s, a, n[c + 8], 7, 1770035416), o, s, n[c + 9], 12, -1958414417), i, o, n[c + 10], 17, -42063), a, i, n[c + 11], 22, -1990404162), s = u(s, a = u(a, i = u(i, o, s, a, n[c + 12], 7, 1804603682), o, s, n[c + 13], 12, -40341101), i, o, n[c + 14], 17, -1502002290), a, i, n[c + 15], 22, 1236535329), s = l(s, a = l(a, i = l(i, o, s, a, n[c + 1], 5, -165796510), o, s, n[c + 6], 9, -1069501632), i, o, n[c + 11], 14, 643717713), a, i, n[c + 0], 20, -373897302), s = l(s, a = l(a, i = l(i, o, s, a, n[c + 5], 5, -701558691), o, s, n[c + 10], 9, 38016083), i, o, n[c + 15], 14, -660478335), a, i, n[c + 4], 20, -405537848), s = l(s, a = l(a, i = l(i, o, s, a, n[c + 9], 5, 568446438), o, s, n[c + 14], 9, -1019803690), i, o, n[c + 3], 14, -187363961), a, i, n[c + 8], 20, 1163531501), s = l(s, a = l(a, i = l(i, o, s, a, n[c + 13], 5, -1444681467), o, s, n[c + 2], 9, -51403784), i, o, n[c + 7], 14, 1735328473), a, i, n[c + 12], 20, -1926607734), s = h(s, a = h(a, i = h(i, o, s, a, n[c + 5], 4, -378558), o, s, n[c + 8], 11, -2022574463), i, o, n[c + 11], 16, 1839030562), a, i, n[c + 14], 23, -35309556), s = h(s, a = h(a, i = h(i, o, s, a, n[c + 1], 4, -1530992060), o, s, n[c + 4], 11, 1272893353), i, o, n[c + 7], 16, -155497632), a, i, n[c + 10], 23, -1094730640), s = h(s, a = h(a, i = h(i, o, s, a, n[c + 13], 4, 681279174), o, s, n[c + 0], 11, -358537222), i, o, n[c + 3], 16, -722521979), a, i, n[c + 6], 23, 76029189), s = h(s, a = h(a, i = h(i, o, s, a, n[c + 9], 4, -640364487), o, s, n[c + 12], 11, -421815835), i, o, n[c + 15], 16, 530742520), a, i, n[c + 2], 23, -995338651), s = f(s, a = f(a, i = f(i, o, s, a, n[c + 0], 6, -198630844), o, s, n[c + 7], 10, 1126891415), i, o, n[c + 14], 15, -1416354905), a, i, n[c + 5], 21, -57434055), s = f(s, a = f(a, i = f(i, o, s, a, n[c + 12], 6, 1700485571), o, s, n[c + 3], 10, -1894986606), i, o, n[c + 10], 15, -1051523), a, i, n[c + 1], 21, -2054922799), s = f(s, a = f(a, i = f(i, o, s, a, n[c + 8], 6, 1873313359), o, s, n[c + 15], 10, -30611744), i, o, n[c + 6], 15, -1560198380), a, i, n[c + 13], 21, 1309151649), s = f(s, a = f(a, i = f(i, o, s, a, n[c + 4], 6, -145523070), o, s, n[c + 11], 10, -1120210379), i, o, n[c + 2], 15, 718787259), a, i, n[c + 9], 21, -343485551),\n            i = i + d >>> 0,\n            o = o + p >>> 0,\n            s = s + g >>> 0,\n            a = a + m >>> 0\n        }\n        return v.endian([i, o, s, a])\n    }\n    )._ff = function(t, e, n, r, i, o, s) {\n        var a = t + (e & n | ~e & r) + (i >>> 0) + s;\n        return (a << o | a >>> 32 - o) + e\n    }\n    ,\n    x._gg = function(t, e, n, r, i, o, s) {\n        var a = t + (e & r | n & ~r) + (i >>> 0) + s;\n        return (a << o | a >>> 32 - o) + e\n    }\n    ,\n    x._hh = function(t, e, n, r, i, o, s) {\n        var a = t + (e ^ n ^ r) + (i >>> 0) + s;\n        return (a << o | a >>> 32 - o) + e\n    }\n    ,\n    x._ii = function(t, e, n, r, i, o, s) {\n        var a = t + (n ^ (e | ~r)) + (i >>> 0) + s;\n        return (a << o | a >>> 32 - o) + e\n    }\n    ,\n    x._blocksize = 16,\n    x._digestsize = 16,\n    t.exports = function(t, e) {\n        if (null == t)\n            throw new Error(\"Illegal argument \" + t);\n        var n = v.wordsToBytes(x(t, e));\n        return e && e.asBytes ? n : e && e.asString ? w.bytesToString(n) : v.bytesToHex(n)\n    }\n},\n        30:function(t, e) {\n    var o, n;\n    o = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",\n    n = {\n        rotl: function(t, e) {\n            return t << e | t >>> 32 - e\n        },\n        rotr: function(t, e) {\n            return t << 32 - e | t >>> e\n        },\n        endian: function(t) {\n            if (t.constructor == Number)\n                return 16711935 & n.rotl(t, 8) | 4278255360 & n.rotl(t, 24);\n            for (var e = 0; e < t.length; e++)\n                t[e] = n.endian(t[e]);\n            return t\n        },\n        randomBytes: function(t) {\n            for (var e = []; 0 < t; t--)\n                e.push(Math.floor(256 * Math.random()));\n            return e\n        },\n        bytesToWords: function(t) {\n            for (var e = [], n = 0, r = 0; n < t.length; n++,\n            r += 8)\n                e[r >>> 5] |= t[n] << 24 - r % 32;\n            return e\n        },\n        wordsToBytes: function(t) {\n            for (var e = [], n = 0; n < 32 * t.length; n += 8)\n                e.push(t[n >>> 5] >>> 24 - n % 32 & 255);\n            return e\n        },\n        bytesToHex: function(t) {\n            for (var e = [], n = 0; n < t.length; n++)\n                e.push((t[n] >>> 4).toString(16)),\n                e.push((15 & t[n]).toString(16));\n            return e.join(\"\")\n        },\n        hexToBytes: function(t) {\n            for (var e = [], n = 0; n < t.length; n += 2)\n                e.push(parseInt(t.substr(n, 2), 16));\n            return e\n        },\n        bytesToBase64: function(t) {\n            for (var e = [], n = 0; n < t.length; n += 3)\n                for (var r = t[n] << 16 | t[n + 1] << 8 | t[n + 2], i = 0; i < 4; i++)\n                    8 * n + 6 * i <= 8 * t.length ? e.push(o.charAt(r >>> 6 * (3 - i) & 63)) : e.push(\"=\");\n            return e.join(\"\")\n        },\n        base64ToBytes: function(t) {\n            t = t.replace(/[^A-Z0-9+\\/]/gi, \"\");\n            for (var e = [], n = 0, r = 0; n < t.length; r = ++n % 4)\n                0 != r && e.push((o.indexOf(t.charAt(n - 1)) & Math.pow(2, -2 * r + 8) - 1) << 2 * r | o.indexOf(t.charAt(n)) >>> 6 - 2 * r);\n            return e\n        }\n    },\n    t.exports = n\n},\n        10: function(t, e) {\n    var n = {\n        utf8: {\n            stringToBytes: function(t) {\n                return n.bin.stringToBytes(unescape(encodeURIComponent(t)))\n            },\n            bytesToString: function(t) {\n                return decodeURIComponent(escape(n.bin.bytesToString(t)))\n            }\n        },\n        bin: {\n            stringToBytes: function(t) {\n                for (var e = [], n = 0; n < t.length; n++)\n                    e.push(255 & t.charCodeAt(n));\n                return e\n            },\n            bytesToString: function(t) {\n                for (var e = [], n = 0; n < t.length; n++)\n                    e.push(String.fromCharCode(t[n]));\n                return e.join(\"\")\n            }\n        }\n    };\n    t.exports = n\n},\n        31:function(t, e) {\n        function n(t) {\n            return !!t.constructor && \"function\" == typeof t.constructor.isBuffer && t.constructor.isBuffer(t)\n        }\n        t.exports = function(t) {\n            return null != t && (n(t) || function(t) {\n                return \"function\" == typeof t.readFloatLE && \"function\" == typeof t.slice && n(t.slice(0, 0))\n            }(t) || !!t._isBuffer)\n        }\n    },\n        4:function(t, e, n) {\n    t.exports = n(32)\n},\n        32: function(t, e, n) {\n    \"use strict\";\n    var r = n(3)\n      , i = n(11)\n      , o = n(34)\n      , s = n(17);\n    function a(t) {\n        var e = new o(t)\n          , n = i(o.prototype.request, e);\n        return r.extend(n, o.prototype, e),\n        r.extend(n, e),\n        n\n    }\n    var c = a(n(14));\n    c.Axios = o,\n    c.create = function(t) {\n        return a(s(c.defaults, t))\n    }\n    ,\n    c.Cancel = n(18),\n    c.CancelToken = n(47),\n    c.isCancel = n(13),\n    c.all = function(t) {\n        return Promise.all(t)\n    }\n    ,\n    c.spread = n(48),\n    t.exports = c,\n    t.exports.default = c\n},\n        3:function(t, e, n) {\n    \"use strict\";\n    var i = n(11)\n      , r = n(33)\n      , o = Object.prototype.toString;\n    function s(t) {\n        return \"[object Array]\" === o.call(t)\n    }\n    function a(t) {\n        return null !== t && \"object\" == typeof t\n    }\n    function c(t) {\n        return \"[object Function]\" === o.call(t)\n    }\n    function u(t, e) {\n        if (null != t)\n            if (\"object\" != typeof t && (t = [t]),\n            s(t))\n                for (var n = 0, r = t.length; n < r; n++)\n                    e.call(null, t[n], n, t);\n            else\n                for (var i in t)\n                    Object.prototype.hasOwnProperty.call(t, i) && e.call(null, t[i], i, t)\n    }\n    t.exports = {\n        isArray: s,\n        isArrayBuffer: function(t) {\n            return \"[object ArrayBuffer]\" === o.call(t)\n        },\n        isBuffer: r,\n        isFormData: function(t) {\n            return \"undefined\" != typeof FormData && t instanceof FormData\n        },\n        isArrayBufferView: function(t) {\n            return \"undefined\" != typeof ArrayBuffer && ArrayBuffer.isView ? ArrayBuffer.isView(t) : t && t.buffer && t.buffer instanceof ArrayBuffer\n        },\n        isString: function(t) {\n            return \"string\" == typeof t\n        },\n        isNumber: function(t) {\n            return \"number\" == typeof t\n        },\n        isObject: a,\n        isUndefined: function(t) {\n            return void 0 === t\n        },\n        isDate: function(t) {\n            return \"[object Date]\" === o.call(t)\n        },\n        isFile: function(t) {\n            return \"[object File]\" === o.call(t)\n        },\n        isBlob: function(t) {\n            return \"[object Blob]\" === o.call(t)\n        },\n        isFunction: c,\n        isStream: function(t) {\n            return a(t) && c(t.pipe)\n        },\n        isURLSearchParams: function(t) {\n            return \"undefined\" != typeof URLSearchParams && t instanceof URLSearchParams\n        },\n        isStandardBrowserEnv: function() {\n            return (\"undefined\" == typeof navigator || \"ReactNative\" !== navigator.product && \"NativeScript\" !== navigator.product && \"NS\" !== navigator.product) && (\"undefined\" != typeof window && \"undefined\" != typeof document)\n        },\n        forEach: u,\n        merge: function n() {\n            var r = {};\n            function t(t, e) {\n                \"object\" == typeof r[e] && \"object\" == typeof t ? r[e] = n(r[e], t) : r[e] = t\n            }\n            for (var e = 0, i = arguments.length; e < i; e++)\n                u(arguments[e], t);\n            return r\n        },\n        deepMerge: function n() {\n            var r = {};\n            function t(t, e) {\n                \"object\" == typeof r[e] && \"object\" == typeof t ? r[e] = n(r[e], t) : r[e] = \"object\" == typeof t ? n({}, t) : t\n            }\n            for (var e = 0, i = arguments.length; e < i; e++)\n                u(arguments[e], t);\n            return r\n        },\n        extend: function(n, t, r) {\n            return u(t, function(t, e) {\n                n[e] = r && \"function\" == typeof t ? i(t, r) : t\n            }),\n            n\n        },\n        trim: function(t) {\n            return t.replace(/^\\s*/, \"\").replace(/\\s*$/, \"\")\n        }\n    }\n},\n        11:function(t, e, n) {\n    \"use strict\";\n    t.exports = function(n, r) {\n        return function() {\n            for (var t = new Array(arguments.length), e = 0; e < t.length; e++)\n                t[e] = arguments[e];\n            return n.apply(r, t)\n        }\n    }\n},\n    33:function (t, e) {\n        t.exports = function(t) {\n            return null != t && null != t.constructor && \"function\" == typeof t.constructor.isBuffer && t.constructor.isBuffer(t)\n        }\n    },\n    34: function(t, e, n) {\n    \"use strict\";\n    var i = n(3)\n      , r = n(12)\n      , o = n(35)\n      , s = n(36)\n      , a = n(17);\n    function c(t) {\n        this.defaults = t,\n        this.interceptors = {\n            request: new o,\n            response: new o\n        }\n    }\n    c.prototype.request = function(t, e) {\n        \"string\" == typeof t ? (t = e || {}).url = arguments[0] : t = t || {},\n        (t = a(this.defaults, t)).method = t.method ? t.method.toLowerCase() : \"get\";\n        var n = [s, void 0]\n          , r = Promise.resolve(t);\n        for (this.interceptors.request.forEach(function(t) {\n            n.unshift(t.fulfilled, t.rejected)\n        }),\n        this.interceptors.response.forEach(function(t) {\n            n.push(t.fulfilled, t.rejected)\n        }); n.length; )\n            r = r.then(n.shift(), n.shift());\n        return r\n    }\n    ,\n    c.prototype.getUri = function(t) {\n        return t = a(this.defaults, t),\n        r(t.url, t.params, t.paramsSerializer).replace(/^\\?/, \"\")\n    }\n    ,\n    i.forEach([\"delete\", \"get\", \"head\", \"options\"], function(n) {\n        c.prototype[n] = function(t, e) {\n            return this.request(i.merge(e || {}, {\n                method: n,\n                url: t\n            }))\n        }\n    }),\n    i.forEach([\"post\", \"put\", \"patch\"], function(r) {\n        c.prototype[r] = function(t, e, n) {\n            return this.request(i.merge(n || {}, {\n                method: r,\n                url: t,\n                data: e\n            }))\n        }\n    }),\n    t.exports = c\n},\n    12: function(t, e, n) {\n    \"use strict\";\n    var s = n(3);\n    function a(t) {\n        return encodeURIComponent(t).replace(/%40/gi, \"@\").replace(/%3A/gi, \":\").replace(/%24/g, \"$\").replace(/%2C/gi, \",\").replace(/%20/g, \"+\").replace(/%5B/gi, \"[\").replace(/%5D/gi, \"]\")\n    }\n    t.exports = function(t, e, n) {\n        if (!e)\n            return t;\n        var r;\n        if (n)\n            r = n(e);\n        else if (s.isURLSearchParams(e))\n            r = e.toString();\n        else {\n            var i = [];\n            s.forEach(e, function(t, e) {\n                null != t && (s.isArray(t) ? e += \"[]\" : t = [t],\n                s.forEach(t, function(t) {\n                    s.isDate(t) ? t = t.toISOString() : s.isObject(t) && (t = JSON.stringify(t)),\n                    i.push(a(e) + \"=\" + a(t))\n                }))\n            }),\n            r = i.join(\"&\")\n        }\n        if (r) {\n            var o = t.indexOf(\"#\");\n            -1 !== o && (t = t.slice(0, o)),\n            t += (-1 === t.indexOf(\"?\") ? \"?\" : \"&\") + r\n        }\n        return t\n    }\n},\n    35:function(t, e, n) {\n    \"use strict\";\n    var r = n(3);\n    function i() {\n        this.handlers = []\n    }\n    i.prototype.use = function(t, e) {\n        return this.handlers.push({\n            fulfilled: t,\n            rejected: e\n        }),\n        this.handlers.length - 1\n    }\n    ,\n    i.prototype.eject = function(t) {\n        this.handlers[t] && (this.handlers[t] = null)\n    }\n    ,\n    i.prototype.forEach = function(e) {\n        r.forEach(this.handlers, function(t) {\n            null !== t && e(t)\n        })\n    }\n    ,\n    t.exports = i\n},\n    36:function(t, e, n) {\n    \"use strict\";\n    var r = n(3)\n      , i = n(37)\n      , o = n(13)\n      , s = n(14)\n      , a = n(45)\n      , c = n(46);\n    function u(t) {\n        t.cancelToken && t.cancelToken.throwIfRequested()\n    }\n    t.exports = function(e) {\n        return u(e),\n        e.baseURL && !a(e.url) && (e.url = c(e.baseURL, e.url)),\n        e.headers = e.headers || {},\n        e.data = i(e.data, e.headers, e.transformRequest),\n        e.headers = r.merge(e.headers.common || {}, e.headers[e.method] || {}, e.headers || {}),\n        r.forEach([\"delete\", \"get\", \"head\", \"post\", \"put\", \"patch\", \"common\"], function(t) {\n            delete e.headers[t]\n        }),\n        (e.adapter || s.adapter)(e).then(function(t) {\n            return u(e),\n            t.data = i(t.data, t.headers, e.transformResponse),\n            t\n        }, function(t) {\n            return o(t) || (u(e),\n            t && t.response && (t.response.data = i(t.response.data, t.response.headers, e.transformResponse))),\n            Promise.reject(t)\n        })\n    }\n},\n   37 : function(t, e, n) {\n    \"use strict\";\n    var r = n(3);\n    t.exports = function(e, n, t) {\n        return r.forEach(t, function(t) {\n            e = t(e, n)\n        }),\n        e\n    }\n},\n    38: function(t, e) {\n        var n, r, i = t.exports = {};\n        function o() {\n            throw new Error(\"setTimeout has not been defined\")\n        }\n        function s() {\n            throw new Error(\"clearTimeout has not been defined\")\n        }\n        function a(e) {\n            if (n === setTimeout)\n                return setTimeout(e, 0);\n            if ((n === o || !n) && setTimeout)\n                return n = setTimeout,\n                setTimeout(e, 0);\n            try {\n                return n(e, 0)\n            } catch (t) {\n                try {\n                    return n.call(null, e, 0)\n                } catch (t) {\n                    return n.call(this, e, 0)\n                }\n            }\n        }\n        !function() {\n            try {\n                n = \"function\" == typeof setTimeout ? setTimeout : o\n            } catch (t) {\n                n = o\n            }\n            try {\n                r = \"function\" == typeof clearTimeout ? clearTimeout : s\n            } catch (t) {\n                r = s\n            }\n        }();\n        var c, u = [], l = !1, h = -1;\n        function f() {\n            l && c && (l = !1,\n            c.length ? u = c.concat(u) : h = -1,\n            u.length && d())\n        }\n        function d() {\n            if (!l) {\n                var t = a(f);\n                l = !0;\n                for (var e = u.length; e; ) {\n                    for (c = u,\n                    u = []; ++h < e; )\n                        c && c[h].run();\n                    h = -1,\n                    e = u.length\n                }\n                c = null,\n                l = !1,\n                function(e) {\n                    if (r === clearTimeout)\n                        return clearTimeout(e);\n                    if ((r === s || !r) && clearTimeout)\n                        return r = clearTimeout,\n                        clearTimeout(e);\n                    try {\n                        r(e)\n                    } catch (t) {\n                        try {\n                            return r.call(null, e)\n                        } catch (t) {\n                            return r.call(this, e)\n                        }\n                    }\n                }(t)\n            }\n        }\n        function p(t, e) {\n            this.fun = t,\n            this.array = e\n        }\n        function g() {}\n        i.nextTick = function(t) {\n            var e = new Array(arguments.length - 1);\n            if (1 < arguments.length)\n                for (var n = 1; n < arguments.length; n++)\n                    e[n - 1] = arguments[n];\n            u.push(new p(t,e)),\n            1 !== u.length || l || a(d)\n        }\n        ,\n        p.prototype.run = function() {\n            this.fun.apply(null, this.array)\n        }\n        ,\n        i.title = \"browser\",\n        i.browser = !0,\n        i.env = {},\n        i.argv = [],\n        i.version = \"\",\n        i.versions = {},\n        i.on = g,\n        i.addListener = g,\n        i.once = g,\n        i.off = g,\n        i.removeListener = g,\n        i.removeAllListeners = g,\n        i.emit = g,\n        i.prependListener = g,\n        i.prependOnceListener = g,\n        i.listeners = function(t) {\n            return []\n        }\n        ,\n        i.binding = function(t) {\n            throw new Error(\"process.binding is not supported\")\n        }\n        ,\n        i.cwd = function() {\n            return \"/\"\n        }\n        ,\n        i.chdir = function(t) {\n            throw new Error(\"process.chdir is not supported\")\n        }\n        ,\n        i.umask = function() {\n            return 0\n        }\n    },\n    39: function(t, e, n) {\n        \"use strict\";\n        var i = n(3);\n        t.exports = function(n, r) {\n            i.forEach(n, function(t, e) {\n                e !== r && e.toUpperCase() === r.toUpperCase() && (n[r] = t,\n                delete n[e])\n            })\n        }\n    },\n      13: function(t, e, n) {\n        \"use strict\";\n        t.exports = function(t) {\n            return !(!t || !t.__CANCEL__)\n        }\n    },\n     14:function(a, t, c) {\n        \"use strict\";\n        (function(t) {\n            var n = c(3)\n              , r = c(39)\n              , e = {\n                \"Content-Type\": \"application/x-www-form-urlencoded\"\n            };\n            function i(t, e) {\n                !n.isUndefined(t) && n.isUndefined(t[\"Content-Type\"]) && (t[\"Content-Type\"] = e)\n            }\n            var o, s = {\n                adapter: (void 0 !== t && \"[object process]\" === Object.prototype.toString.call(t) ? o = c(15) : \"undefined\" != typeof XMLHttpRequest && (o = c(15)),\n                o),\n                transformRequest: [function(t, e) {\n                    return r(e, \"Accept\"),\n                    r(e, \"Content-Type\"),\n                    n.isFormData(t) || n.isArrayBuffer(t) || n.isBuffer(t) || n.isStream(t) || n.isFile(t) || n.isBlob(t) ? t : n.isArrayBufferView(t) ? t.buffer : n.isURLSearchParams(t) ? (i(e, \"application/x-www-form-urlencoded;charset=utf-8\"),\n                    t.toString()) : n.isObject(t) ? (i(e, \"application/json;charset=utf-8\"),\n                    JSON.stringify(t)) : t\n                }\n                ],\n                transformResponse: [function(t) {\n                    if (\"string\" == typeof t)\n                        try {\n                            t = JSON.parse(t)\n                        } catch (t) {}\n                    return t\n                }\n                ],\n                timeout: 0,\n                xsrfCookieName: \"XSRF-TOKEN\",\n                xsrfHeaderName: \"X-XSRF-TOKEN\",\n                maxContentLength: -1,\n                validateStatus: function(t) {\n                    return 200 <= t && t < 300\n                }\n            };\n            s.headers = {\n                common: {\n                    Accept: \"application/json, text/plain, */*\"\n                }\n            },\n            n.forEach([\"delete\", \"get\", \"head\"], function(t) {\n                s.headers[t] = {}\n            }),\n            n.forEach([\"post\", \"put\", \"patch\"], function(t) {\n                s.headers[t] = n.merge(e)\n            }),\n            a.exports = s\n        }\n        ).call(this, c(38))\n    },\n    45:function(t, e, n) {\n        \"use strict\";\n        t.exports = function(t) {\n            return /^([a-z][a-z\\d\\+\\-\\.]*:)?\\/\\//i.test(t)\n        }\n    }\n    ,46:function(t, e, n) {\n        \"use strict\";\n        t.exports = function(t, e) {\n            return e ? t.replace(/\\/+$/, \"\") + \"/\" + e.replace(/^\\/+/, \"\") : t\n        }\n    }\n    , 47:function(t, e, n) {\n        \"use strict\";\n        var r = n(18);\n        function i(t) {\n            if (\"function\" != typeof t)\n                throw new TypeError(\"executor must be a function.\");\n            var e;\n            this.promise = new Promise(function(t) {\n                e = t\n            }\n            );\n            var n = this;\n            t(function(t) {\n                n.reason || (n.reason = new r(t),\n                e(n.reason))\n            })\n        }\n        i.prototype.throwIfRequested = function() {\n            if (this.reason)\n                throw this.reason\n        }\n        ,\n        i.source = function() {\n            var e;\n            return {\n                token: new i(function(t) {\n                    e = t\n                }\n                ),\n                cancel: e\n            }\n        }\n        ,\n        t.exports = i\n    }\n    , 48:function(t, e, n) {\n        \"use strict\";\n        t.exports = function(e) {\n            return function(t) {\n                return e.apply(null, t)\n            }\n        }\n    },\n    17:function(t, e, n) {\n        \"use strict\";\n        var i = n(3);\n        t.exports = function(e, n) {\n            n = n || {};\n            var r = {};\n            return i.forEach([\"url\", \"method\", \"params\", \"data\"], function(t) {\n                void 0 !== n[t] && (r[t] = n[t])\n            }),\n            i.forEach([\"headers\", \"auth\", \"proxy\"], function(t) {\n                i.isObject(n[t]) ? r[t] = i.deepMerge(e[t], n[t]) : void 0 !== n[t] ? r[t] = n[t] : i.isObject(e[t]) ? r[t] = i.deepMerge(e[t]) : void 0 !== e[t] && (r[t] = e[t])\n            }),\n            i.forEach([\"baseURL\", \"transformRequest\", \"transformResponse\", \"paramsSerializer\", \"timeout\", \"withCredentials\", \"adapter\", \"responseType\", \"xsrfCookieName\", \"xsrfHeaderName\", \"onUploadProgress\", \"onDownloadProgress\", \"maxContentLength\", \"validateStatus\", \"maxRedirects\", \"httpAgent\", \"httpsAgent\", \"cancelToken\", \"socketPath\"], function(t) {\n                void 0 !== n[t] ? r[t] = n[t] : void 0 !== e[t] && (r[t] = e[t])\n            }),\n            r\n        }\n    },\n    18:function(t, e, n) {\n    \"use strict\";\n    function r(t) {\n        this.message = t\n    }\n    r.prototype.toString = function() {\n        return \"Cancel\" + (this.message ? \": \" + this.message : \"\")\n    }\n    ,\n    r.prototype.__CANCEL__ = !0,\n    t.exports = r\n},\n  }\n);\n\n\nfunction get_passwrod(phone){\n    aaa(50).default()\n    var e = \"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJxBJn2gY+D2OdldUxpsNwIGyKc/QRvqbWWGIdIewE7SxyyGHNcLdT+2bb6E6Ko7jBlEElUBkKJJ93G761dp6pXu7ORTjJ1mta99Bjud7+u/3473mG+QReoH4ux8idsd+E0TW0HWUP6zyfYy42HPSaN3pjetM30sVazdWxpvAH6wIDAQAB\";\n    ddd.ec.setPublicKey(e);\n    ddd.publicKey = e;\n    console.log(ddd.ec.encrypt(phone));\n    return ddd.ec.encrypt(phone)\n}\n"
  },
  {
    "path": "第三章：Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例三.js",
    "content": "/*!\n爬虫逆向进阶实战-JS逆向3.4.1 webpack案例三\n视频地址：https://www.bilibili.com/video/bv1MB4y1h7nK\n */\nvar aaa;\n!function(g) {\n    \"use strict\";\n    var r, e, t, i;\n    r = {\n        1: [function(t, i, n) {\n            i.exports = function(t, i) {\n                var n = Array(arguments.length - 1)\n                  , s = 0\n                  , r = 2\n                  , u = !0;\n                for (; r < arguments.length; )\n                    n[s++] = arguments[r++];\n                return new Promise(function(r, e) {\n                    n[s] = function(t) {\n                        if (u)\n                            if (u = !1,\n                            t)\n                                e(t);\n                            else {\n                                for (var i = Array(arguments.length - 1), n = 0; n < i.length; )\n                                    i[n++] = arguments[n];\n                                r.apply(null, i)\n                            }\n                    }\n                    ;\n                    try {\n                        t.apply(i || null, n)\n                    } catch (t) {\n                        u && (u = !1,\n                        e(t))\n                    }\n                }\n                )\n            }\n        }\n        , {}],\n        2: [function(t, i, n) {\n            n.length = function(t) {\n                var i = t.length;\n                if (!i)\n                    return 0;\n                for (var n = 0; 1 < --i % 4 && \"=\" == (t[0 | i] || \"\"); )\n                    ++n;\n                return Math.ceil(3 * t.length) / 4 - n\n            }\n            ;\n            for (var f = Array(64), h = Array(123), r = 0; r < 64; )\n                h[f[r] = r < 26 ? r + 65 : r < 52 ? r + 71 : r < 62 ? r - 4 : r - 59 | 43] = r++;\n            n.encode = function(t, i, n) {\n                for (var r, e = null, s = [], u = 0, o = 0; i < n; ) {\n                    var h = t[i++];\n                    switch (o) {\n                    case 0:\n                        s[u++] = f[h >> 2],\n                        r = (3 & h) << 4,\n                        o = 1;\n                        break;\n                    case 1:\n                        s[u++] = f[r | h >> 4],\n                        r = (15 & h) << 2,\n                        o = 2;\n                        break;\n                    case 2:\n                        s[u++] = f[r | h >> 6],\n                        s[u++] = f[63 & h],\n                        o = 0\n                    }\n                    8191 < u && ((e = e || []).push(String.fromCharCode.apply(String, s)),\n                    u = 0)\n                }\n                return o && (s[u++] = f[r],\n                s[u++] = 61,\n                1 === o && (s[u++] = 61)),\n                e ? (u && e.push(String.fromCharCode.apply(String, s.slice(0, u))),\n                e.join(\"\")) : String.fromCharCode.apply(String, s.slice(0, u))\n            }\n            ;\n            var c = \"invalid encoding\";\n            n.decode = function(t, i, n) {\n                for (var r, e = n, s = 0, u = 0; u < t.length; ) {\n                    var o = t.charCodeAt(u++);\n                    if (61 == o && 1 < s)\n                        break;\n                    if ((o = h[o]) === g)\n                        throw Error(c);\n                    switch (s) {\n                    case 0:\n                        r = o,\n                        s = 1;\n                        break;\n                    case 1:\n                        i[n++] = r << 2 | (48 & o) >> 4,\n                        r = o,\n                        s = 2;\n                        break;\n                    case 2:\n                        i[n++] = (15 & r) << 4 | (60 & o) >> 2,\n                        r = o,\n                        s = 3;\n                        break;\n                    case 3:\n                        i[n++] = (3 & r) << 6 | o,\n                        s = 0\n                    }\n                }\n                if (1 === s)\n                    throw Error(c);\n                return n - e\n            }\n            ,\n            n.test = function(t) {\n                return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(t)\n            }\n        }\n        , {}],\n        3: [function(t, i, n) {\n            function a(i, n) {\n                \"string\" == typeof i && (n = i,\n                i = g);\n                var h = [];\n                function f(t) {\n                    if (\"string\" != typeof t) {\n                        var i = c();\n                        if (a.verbose && console.log(\"codegen: \" + i),\n                        i = \"return \" + i,\n                        t) {\n                            for (var n = Object.keys(t), r = Array(n.length + 1), e = Array(n.length), s = 0; s < n.length; )\n                                r[s] = n[s],\n                                e[s] = t[n[s++]];\n                            return r[s] = i,\n                            Function.apply(null, r).apply(null, e)\n                        }\n                        return Function(i)()\n                    }\n                    for (var u = Array(arguments.length - 1), o = 0; o < u.length; )\n                        u[o] = arguments[++o];\n                    if (o = 0,\n                    t = t.replace(/%([%dfijs])/g, function(t, i) {\n                        var n = u[o++];\n                        switch (i) {\n                        case \"d\":\n                        case \"f\":\n                            return \"\" + +(\"\" + n);\n                        case \"i\":\n                            return \"\" + Math.floor(n);\n                        case \"j\":\n                            return JSON.stringify(n);\n                        case \"s\":\n                            return \"\" + n\n                        }\n                        return \"%\"\n                    }),\n                    o !== u.length)\n                        throw Error(\"parameter count mismatch\");\n                    return h.push(t),\n                    f\n                }\n                function c(t) {\n                    return \"function \" + (t || n || \"\") + \"(\" + (i && i.join(\",\") || \"\") + \"){\\n  \" + h.join(\"\\n  \") + \"\\n}\"\n                }\n                return f.toString = c,\n                f\n            }\n            (i.exports = a).verbose = !1\n        }\n        , {}],\n        4: [function(t, i, n) {\n            function r() {\n                this.t = {}\n            }\n            (i.exports = r).prototype.on = function(t, i, n) {\n                return (this.t[t] || (this.t[t] = [])).push({\n                    fn: i,\n                    ctx: n || this\n                }),\n                this\n            }\n            ,\n            r.prototype.off = function(t, i) {\n                if (t === g)\n                    this.t = {};\n                else if (i === g)\n                    this.t[t] = [];\n                else\n                    for (var n = this.t[t], r = 0; r < n.length; )\n                        n[r].fn === i ? n.splice(r, 1) : ++r;\n                return this\n            }\n            ,\n            r.prototype.emit = function(t) {\n                var i = this.t[t];\n                if (i) {\n                    for (var n = [], r = 1; r < arguments.length; )\n                        n.push(arguments[r++]);\n                    for (r = 0; r < i.length; )\n                        i[r].fn.apply(i[r++].ctx, n)\n                }\n                return this\n            }\n        }\n        , {}],\n        5: [function(t, i, n) {\n            i.exports = o;\n            var s = t(1)\n              , u = t(7)(\"fs\");\n            function o(n, r, e) {\n                return r = \"function\" == typeof r ? (e = r,\n                {}) : r || {},\n                e ? !r.xhr && u && u.readFile ? u.readFile(n, function(t, i) {\n                    return t && \"undefined\" != typeof XMLHttpRequest ? o.xhr(n, r, e) : t ? e(t) : e(null, r.binary ? i : i.toString(\"utf8\"))\n                }) : o.xhr(n, r, e) : s(o, this, n, r)\n            }\n            o.xhr = function(t, n, r) {\n                var e = new XMLHttpRequest;\n                e.onreadystatechange = function() {\n                    if (4 !== e.readyState)\n                        return g;\n                    if (0 !== e.status && 200 !== e.status)\n                        return r(Error(\"status \" + e.status));\n                    if (n.binary) {\n                        if (!(t = e.response))\n                            for (var t = [], i = 0; i < e.responseText.length; ++i)\n                                t.push(255 & e.responseText.charCodeAt(i));\n                        return r(null, \"undefined\" != typeof Uint8Array ? new Uint8Array(t) : t)\n                    }\n                    return r(null, e.responseText)\n                }\n                ,\n                n.binary && (\"overrideMimeType\"in e && e.overrideMimeType(\"text/plain; charset=x-user-defined\"),\n                e.responseType = \"arraybuffer\"),\n                e.open(\"GET\", t),\n                e.send()\n            }\n        }\n        , {\n            1: 1,\n            7: 7\n        }],\n        6: [function(t, i, n) {\n            function r(t) {\n                function i(t, i, n, r) {\n                    var e = i < 0 ? 1 : 0;\n                    t(0 === (i = e ? -i : i) ? 0 < 1 / i ? 0 : 2147483648 : isNaN(i) ? 2143289344 : 34028234663852886e22 < i ? (e << 31 | 2139095040) >>> 0 : i < 11754943508222875e-54 ? (e << 31 | Math.round(i / 1401298464324817e-60)) >>> 0 : (e << 31 | 127 + (e = Math.floor(Math.log(i) / Math.LN2)) << 23 | 8388607 & Math.round(i * Math.pow(2, -e) * 8388608)) >>> 0, n, r)\n                }\n                function n(t, i, n) {\n                    t = t(i, n),\n                    i = 2 * (t >> 31) + 1,\n                    n = t >>> 23 & 255,\n                    t &= 8388607;\n                    return 255 == n ? t ? NaN : 1 / 0 * i : 0 == n ? 1401298464324817e-60 * i * t : i * Math.pow(2, n - 150) * (8388608 + t)\n                }\n                function r(t, i, n) {\n                    o[0] = t,\n                    i[n] = h[0],\n                    i[n + 1] = h[1],\n                    i[n + 2] = h[2],\n                    i[n + 3] = h[3]\n                }\n                function e(t, i, n) {\n                    o[0] = t,\n                    i[n] = h[3],\n                    i[n + 1] = h[2],\n                    i[n + 2] = h[1],\n                    i[n + 3] = h[0]\n                }\n                function s(t, i) {\n                    return h[0] = t[i],\n                    h[1] = t[i + 1],\n                    h[2] = t[i + 2],\n                    h[3] = t[i + 3],\n                    o[0]\n                }\n                function u(t, i) {\n                    return h[3] = t[i],\n                    h[2] = t[i + 1],\n                    h[1] = t[i + 2],\n                    h[0] = t[i + 3],\n                    o[0]\n                }\n                var o, h, f, c, a;\n                function l(t, i, n, r, e, s) {\n                    var u, o = r < 0 ? 1 : 0;\n                    0 === (r = o ? -r : r) ? (t(0, e, s + i),\n                    t(0 < 1 / r ? 0 : 2147483648, e, s + n)) : isNaN(r) ? (t(0, e, s + i),\n                    t(2146959360, e, s + n)) : 17976931348623157e292 < r ? (t(0, e, s + i),\n                    t((o << 31 | 2146435072) >>> 0, e, s + n)) : r < 22250738585072014e-324 ? (t((u = r / 5e-324) >>> 0, e, s + i),\n                    t((o << 31 | u / 4294967296) >>> 0, e, s + n)) : (t(4503599627370496 * (u = r * Math.pow(2, -(r = 1024 === (r = Math.floor(Math.log(r) / Math.LN2)) ? 1023 : r))) >>> 0, e, s + i),\n                    t((o << 31 | r + 1023 << 20 | 1048576 * u & 1048575) >>> 0, e, s + n))\n                }\n                function v(t, i, n, r, e) {\n                    i = t(r, e + i),\n                    r = t(r, e + n),\n                    e = 2 * (r >> 31) + 1,\n                    n = r >>> 20 & 2047,\n                    i = 4294967296 * (1048575 & r) + i;\n                    return 2047 == n ? i ? NaN : 1 / 0 * e : 0 == n ? 5e-324 * e * i : e * Math.pow(2, n - 1075) * (i + 4503599627370496)\n                }\n                function d(t, i, n) {\n                    f[0] = t,\n                    i[n] = c[0],\n                    i[n + 1] = c[1],\n                    i[n + 2] = c[2],\n                    i[n + 3] = c[3],\n                    i[n + 4] = c[4],\n                    i[n + 5] = c[5],\n                    i[n + 6] = c[6],\n                    i[n + 7] = c[7]\n                }\n                function b(t, i, n) {\n                    f[0] = t,\n                    i[n] = c[7],\n                    i[n + 1] = c[6],\n                    i[n + 2] = c[5],\n                    i[n + 3] = c[4],\n                    i[n + 4] = c[3],\n                    i[n + 5] = c[2],\n                    i[n + 6] = c[1],\n                    i[n + 7] = c[0]\n                }\n                function p(t, i) {\n                    return c[0] = t[i],\n                    c[1] = t[i + 1],\n                    c[2] = t[i + 2],\n                    c[3] = t[i + 3],\n                    c[4] = t[i + 4],\n                    c[5] = t[i + 5],\n                    c[6] = t[i + 6],\n                    c[7] = t[i + 7],\n                    f[0]\n                }\n                function y(t, i) {\n                    return c[7] = t[i],\n                    c[6] = t[i + 1],\n                    c[5] = t[i + 2],\n                    c[4] = t[i + 3],\n                    c[3] = t[i + 4],\n                    c[2] = t[i + 5],\n                    c[1] = t[i + 6],\n                    c[0] = t[i + 7],\n                    f[0]\n                }\n                return \"undefined\" != typeof Float32Array ? (o = new Float32Array([-0]),\n                h = new Uint8Array(o.buffer),\n                a = 128 === h[3],\n                t.writeFloatLE = a ? r : e,\n                t.writeFloatBE = a ? e : r,\n                t.readFloatLE = a ? s : u,\n                t.readFloatBE = a ? u : s) : (t.writeFloatLE = i.bind(null, m),\n                t.writeFloatBE = i.bind(null, w),\n                t.readFloatLE = n.bind(null, g),\n                t.readFloatBE = n.bind(null, j)),\n                \"undefined\" != typeof Float64Array ? (f = new Float64Array([-0]),\n                c = new Uint8Array(f.buffer),\n                a = 128 === c[7],\n                t.writeDoubleLE = a ? d : b,\n                t.writeDoubleBE = a ? b : d,\n                t.readDoubleLE = a ? p : y,\n                t.readDoubleBE = a ? y : p) : (t.writeDoubleLE = l.bind(null, m, 0, 4),\n                t.writeDoubleBE = l.bind(null, w, 4, 0),\n                t.readDoubleLE = v.bind(null, g, 0, 4),\n                t.readDoubleBE = v.bind(null, j, 4, 0)),\n                t\n            }\n            function m(t, i, n) {\n                i[n] = 255 & t,\n                i[n + 1] = t >>> 8 & 255,\n                i[n + 2] = t >>> 16 & 255,\n                i[n + 3] = t >>> 24\n            }\n            function w(t, i, n) {\n                i[n] = t >>> 24,\n                i[n + 1] = t >>> 16 & 255,\n                i[n + 2] = t >>> 8 & 255,\n                i[n + 3] = 255 & t\n            }\n            function g(t, i) {\n                return (t[i] | t[i + 1] << 8 | t[i + 2] << 16 | t[i + 3] << 24) >>> 0\n            }\n            function j(t, i) {\n                return (t[i] << 24 | t[i + 1] << 16 | t[i + 2] << 8 | t[i + 3]) >>> 0\n            }\n            i.exports = r(r)\n        }\n        , {}],\n        7: [function(t, i, n) {\n            function r(t) {\n                try {\n                    var i = eval(\"require\")(t);\n                    if (i && (i.length || Object.keys(i).length))\n                        return i\n                } catch (t) {}\n                return null\n            }\n            i.exports = r\n        }\n        , {}],\n        8: [function(t, i, n) {\n            var n = n\n              , e = n.isAbsolute = function(t) {\n                return /^(?:\\/|\\w+:)/.test(t)\n            }\n              , r = n.normalize = function(t) {\n                var i = (t = t.replace(/\\\\/g, \"/\").replace(/\\/{2,}/g, \"/\")).split(\"/\")\n                  , n = e(t)\n                  , t = \"\";\n                n && (t = i.shift() + \"/\");\n                for (var r = 0; r < i.length; )\n                    \"..\" === i[r] ? 0 < r && \"..\" !== i[r - 1] ? i.splice(--r, 2) : n ? i.splice(r, 1) : ++r : \".\" === i[r] ? i.splice(r, 1) : ++r;\n                return t + i.join(\"/\")\n            }\n            ;\n            n.resolve = function(t, i, n) {\n                return n || (i = r(i)),\n                !e(i) && (t = (t = !n ? r(t) : t).replace(/(?:\\/|^)[^/]+$/, \"\")).length ? r(t + \"/\" + i) : i\n            }\n        }\n        , {}],\n        9: [function(t, i, n) {\n            i.exports = function(i, n, t) {\n                var r = t || 8192\n                  , e = r >>> 1\n                  , s = null\n                  , u = r;\n                return function(t) {\n                    if (t < 1 || e < t)\n                        return i(t);\n                    r < u + t && (s = i(r),\n                    u = 0);\n                    t = n.call(s, u, u += t);\n                    return 7 & u && (u = 1 + (7 | u)),\n                    t\n                }\n            }\n        }\n        , {}],\n        10: [function(t, i, n) {\n            n.length = function(t) {\n                for (var i, n = 0, r = 0; r < t.length; ++r)\n                    (i = t.charCodeAt(r)) < 128 ? n += 1 : i < 2048 ? n += 2 : 55296 == (64512 & i) && 56320 == (64512 & t.charCodeAt(r + 1)) ? (++r,\n                    n += 4) : n += 3;\n                return n\n            }\n            ,\n            n.read = function(t, i, n) {\n                if (n - i < 1)\n                    return \"\";\n                for (var r, e = null, s = [], u = 0; i < n; )\n                    (r = t[i++]) < 128 ? s[u++] = r : 191 < r && r < 224 ? s[u++] = (31 & r) << 6 | 63 & t[i++] : 239 < r && r < 365 ? (r = ((7 & r) << 18 | (63 & t[i++]) << 12 | (63 & t[i++]) << 6 | 63 & t[i++]) - 65536,\n                    s[u++] = 55296 + (r >> 10),\n                    s[u++] = 56320 + (1023 & r)) : s[u++] = (15 & r) << 12 | (63 & t[i++]) << 6 | 63 & t[i++],\n                    8191 < u && ((e = e || []).push(String.fromCharCode.apply(String, s)),\n                    u = 0);\n                return e ? (u && e.push(String.fromCharCode.apply(String, s.slice(0, u))),\n                e.join(\"\")) : String.fromCharCode.apply(String, s.slice(0, u))\n            }\n            ,\n            n.write = function(t, i, n) {\n                for (var r, e, s = n, u = 0; u < t.length; ++u)\n                    (r = t.charCodeAt(u)) < 128 ? i[n++] = r : (r < 2048 ? i[n++] = r >> 6 | 192 : (55296 == (64512 & r) && 56320 == (64512 & (e = t.charCodeAt(u + 1))) ? (++u,\n                    i[n++] = (r = 65536 + ((1023 & r) << 10) + (1023 & e)) >> 18 | 240,\n                    i[n++] = r >> 12 & 63 | 128) : i[n++] = r >> 12 | 224,\n                    i[n++] = r >> 6 & 63 | 128),\n                    i[n++] = 63 & r | 128);\n                return n - s\n            }\n        }\n        , {}],\n        11: [function(t, i, n) {\n            var n = n\n              , l = t(14)\n              , v = t(33);\n            function u(t, i, n, r) {\n                if (i.resolvedType)\n                    if (i.resolvedType instanceof l) {\n                        t(\"switch(d%s){\", r);\n                        for (var e = i.resolvedType.values, s = Object.keys(e), u = 0; u < s.length; ++u)\n                            i.repeated && e[s[u]] === i.typeDefault && t(\"default:\"),\n                            t(\"case%j:\", s[u])(\"case %i:\", e[s[u]])(\"m%s=%j\", r, e[s[u]])(\"break\");\n                        t(\"}\")\n                    } else\n                        t('if(typeof d%s!==\"object\")', r)(\"throw TypeError(%j)\", i.fullName + \": object expected\")(\"m%s=types[%i].fromObject(d%s)\", r, n, r);\n                else {\n                    var o = !1;\n                    switch (i.type) {\n                    case \"double\":\n                    case \"float\":\n                        t(\"m%s=Number(d%s)\", r, r);\n                        break;\n                    case \"uint32\":\n                    case \"fixed32\":\n                        t(\"m%s=d%s>>>0\", r, r);\n                        break;\n                    case \"int32\":\n                    case \"sint32\":\n                    case \"sfixed32\":\n                        t(\"m%s=d%s|0\", r, r);\n                        break;\n                    case \"uint64\":\n                        o = !0;\n                    case \"int64\":\n                    case \"sint64\":\n                    case \"fixed64\":\n                    case \"sfixed64\":\n                        t(\"if(util.Long)\")(\"(m%s=util.Long.fromValue(d%s)).unsigned=%j\", r, r, o)('else if(typeof d%s===\"string\")', r)(\"m%s=parseInt(d%s,10)\", r, r)('else if(typeof d%s===\"number\")', r)(\"m%s=d%s\", r, r)('else if(typeof d%s===\"object\")', r)(\"m%s=new util.LongBits(d%s.low>>>0,d%s.high>>>0).toNumber(%s)\", r, r, r, o ? \"true\" : \"\");\n                        break;\n                    case \"bytes\":\n                        t('if(typeof d%s===\"string\")', r)(\"util.base64.decode(d%s,m%s=util.newBuffer(util.base64.length(d%s)),0)\", r, r, r)(\"else if(d%s.length)\", r)(\"m%s=d%s\", r, r);\n                        break;\n                    case \"string\":\n                        t(\"m%s=String(d%s)\", r, r);\n                        break;\n                    case \"bool\":\n                        t(\"m%s=Boolean(d%s)\", r, r)\n                    }\n                }\n                return t\n            }\n            function d(t, i, n, r) {\n                if (i.resolvedType)\n                    i.resolvedType instanceof l ? t(\"d%s=o.enums===String?types[%i].values[m%s]:m%s\", r, n, r, r) : t(\"d%s=types[%i].toObject(m%s,o)\", r, n, r);\n                else {\n                    var e = !1;\n                    switch (i.type) {\n                    case \"double\":\n                    case \"float\":\n                        t(\"d%s=o.json&&!isFinite(m%s)?String(m%s):m%s\", r, r, r, r);\n                        break;\n                    case \"uint64\":\n                        e = !0;\n                    case \"int64\":\n                    case \"sint64\":\n                    case \"fixed64\":\n                    case \"sfixed64\":\n                        t('if(typeof m%s===\"number\")', r)(\"d%s=o.longs===String?String(m%s):m%s\", r, r, r)(\"else\")(\"d%s=o.longs===String?util.Long.prototype.toString.call(m%s):o.longs===Number?new util.LongBits(m%s.low>>>0,m%s.high>>>0).toNumber(%s):m%s\", r, r, r, r, e ? \"true\" : \"\", r);\n                        break;\n                    case \"bytes\":\n                        t(\"d%s=o.bytes===String?util.base64.encode(m%s,0,m%s.length):o.bytes===Array?Array.prototype.slice.call(m%s):m%s\", r, r, r, r, r);\n                        break;\n                    default:\n                        t(\"d%s=m%s\", r, r)\n                    }\n                }\n                return t\n            }\n            n.fromObject = function(t) {\n                var i = t.fieldsArray\n                  , n = v.codegen([\"d\"], t.name + \"$fromObject\")(\"if(d instanceof this.ctor)\")(\"return d\");\n                if (!i.length)\n                    return n(\"return new this.ctor\");\n                n(\"var m=new this.ctor\");\n                for (var r = 0; r < i.length; ++r) {\n                    var e = i[r].resolve()\n                      , s = v.safeProp(e.name);\n                    e.map ? (n(\"if(d%s){\", s)('if(typeof d%s!==\"object\")', s)(\"throw TypeError(%j)\", e.fullName + \": object expected\")(\"m%s={}\", s)(\"for(var ks=Object.keys(d%s),i=0;i<ks.length;++i){\", s),\n                    u(n, e, r, s + \"[ks[i]]\")(\"}\")(\"}\")) : e.repeated ? (n(\"if(d%s){\", s)(\"if(!Array.isArray(d%s))\", s)(\"throw TypeError(%j)\", e.fullName + \": array expected\")(\"m%s=[]\", s)(\"for(var i=0;i<d%s.length;++i){\", s),\n                    u(n, e, r, s + \"[i]\")(\"}\")(\"}\")) : (e.resolvedType instanceof l || n(\"if(d%s!=null){\", s),\n                    u(n, e, r, s),\n                    e.resolvedType instanceof l || n(\"}\"))\n                }\n                return n(\"return m\")\n            }\n            ,\n            n.toObject = function(t) {\n                var i = t.fieldsArray.slice().sort(v.compareFieldsById);\n                if (!i.length)\n                    return v.codegen()(\"return {}\");\n                for (var n = v.codegen([\"m\", \"o\"], t.name + \"$toObject\")(\"if(!o)\")(\"o={}\")(\"var d={}\"), r = [], e = [], s = [], u = 0; u < i.length; ++u)\n                    i[u].partOf || (i[u].resolve().repeated ? r : i[u].map ? e : s).push(i[u]);\n                if (r.length) {\n                    for (n(\"if(o.arrays||o.defaults){\"),\n                    u = 0; u < r.length; ++u)\n                        n(\"d%s=[]\", v.safeProp(r[u].name));\n                    n(\"}\")\n                }\n                if (e.length) {\n                    for (n(\"if(o.objects||o.defaults){\"),\n                    u = 0; u < e.length; ++u)\n                        n(\"d%s={}\", v.safeProp(e[u].name));\n                    n(\"}\")\n                }\n                if (s.length) {\n                    for (n(\"if(o.defaults){\"),\n                    u = 0; u < s.length; ++u) {\n                        var o, h = s[u], f = v.safeProp(h.name);\n                        h.resolvedType instanceof l ? n(\"d%s=o.enums===String?%j:%j\", f, h.resolvedType.valuesById[h.typeDefault], h.typeDefault) : h.long ? n(\"if(util.Long){\")(\"var n=new util.Long(%i,%i,%j)\", h.typeDefault.low, h.typeDefault.high, h.typeDefault.unsigned)(\"d%s=o.longs===String?n.toString():o.longs===Number?n.toNumber():n\", f)(\"}else\")(\"d%s=o.longs===String?%j:%i\", f, h.typeDefault.toString(), h.typeDefault.toNumber()) : h.bytes ? (o = \"[\" + Array.prototype.slice.call(h.typeDefault).join(\",\") + \"]\",\n                        n(\"if(o.bytes===String)d%s=%j\", f, String.fromCharCode.apply(String, h.typeDefault))(\"else{\")(\"d%s=%s\", f, o)(\"if(o.bytes!==Array)d%s=util.newBuffer(d%s)\", f, f)(\"}\")) : n(\"d%s=%j\", f, h.typeDefault)\n                    }\n                    n(\"}\")\n                }\n                for (var c = !1, u = 0; u < i.length; ++u) {\n                    var h = i[u]\n                      , a = t.i.indexOf(h)\n                      , f = v.safeProp(h.name);\n                    h.map ? (c || (c = !0,\n                    n(\"var ks2\")),\n                    n(\"if(m%s&&(ks2=Object.keys(m%s)).length){\", f, f)(\"d%s={}\", f)(\"for(var j=0;j<ks2.length;++j){\"),\n                    d(n, h, a, f + \"[ks2[j]]\")(\"}\")) : h.repeated ? (n(\"if(m%s&&m%s.length){\", f, f)(\"d%s=[]\", f)(\"for(var j=0;j<m%s.length;++j){\", f),\n                    d(n, h, a, f + \"[j]\")(\"}\")) : (n(\"if(m%s!=null&&m.hasOwnProperty(%j)){\", f, h.name),\n                    d(n, h, a, f),\n                    h.partOf && n(\"if(o.oneofs)\")(\"d%s=%j\", v.safeProp(h.partOf.name), h.name)),\n                    n(\"}\")\n                }\n                return n(\"return d\")\n            }\n        }\n        , {\n            14: 14,\n            33: 33\n        }],\n        12: [function(t, i, n) {\n            i.exports = function(t) {\n                var i = f.codegen([\"r\", \"l\"], t.name + \"$decode\")(\"if(!(r instanceof Reader))\")(\"r=Reader.create(r)\")(\"var c=l===undefined?r.len:r.pos+l,m=new this.ctor\" + (t.fieldsArray.filter(function(t) {\n                    return t.map\n                }).length ? \",k,value\" : \"\"))(\"while(r.pos<c){\")(\"var t=r.uint32()\");\n                t.group && i(\"if((t&7)===4)\")(\"break\");\n                i(\"switch(t>>>3){\");\n                for (var n = 0; n < t.fieldsArray.length; ++n) {\n                    var r = t.i[n].resolve()\n                      , e = r.resolvedType instanceof o ? \"int32\" : r.type\n                      , s = \"m\" + f.safeProp(r.name);\n                    i(\"case %i:\", r.id),\n                    r.map ? (i(\"if(%s===util.emptyObject)\", s)(\"%s={}\", s)(\"var c2 = r.uint32()+r.pos\"),\n                    h.defaults[r.keyType] !== g ? i(\"k=%j\", h.defaults[r.keyType]) : i(\"k=null\"),\n                    h.defaults[e] !== g ? i(\"value=%j\", h.defaults[e]) : i(\"value=null\"),\n                    i(\"while(r.pos<c2){\")(\"var tag2=r.uint32()\")(\"switch(tag2>>>3){\")(\"case 1: k=r.%s(); break\", r.keyType)(\"case 2:\"),\n                    h.basic[e] === g ? i(\"value=types[%i].decode(r,r.uint32())\", n) : i(\"value=r.%s()\", e),\n                    i(\"break\")(\"default:\")(\"r.skipType(tag2&7)\")(\"break\")(\"}\")(\"}\"),\n                    h.long[r.keyType] !== g ? i('%s[typeof k===\"object\"?util.longToHash(k):k]=value', s) : i(\"%s[k]=value\", s)) : r.repeated ? (i(\"if(!(%s&&%s.length))\", s, s)(\"%s=[]\", s),\n                    h.packed[e] !== g && i(\"if((t&7)===2){\")(\"var c2=r.uint32()+r.pos\")(\"while(r.pos<c2)\")(\"%s.push(r.%s())\", s, e)(\"}else\"),\n                    h.basic[e] === g ? i(r.resolvedType.group ? \"%s.push(types[%i].decode(r))\" : \"%s.push(types[%i].decode(r,r.uint32()))\", s, n) : i(\"%s.push(r.%s())\", s, e)) : h.basic[e] === g ? i(r.resolvedType.group ? \"%s=types[%i].decode(r)\" : \"%s=types[%i].decode(r,r.uint32())\", s, n) : i(\"%s=r.%s()\", s, e),\n                    i(\"break\")\n                }\n                for (i(\"default:\")(\"r.skipType(t&7)\")(\"break\")(\"}\")(\"}\"),\n                n = 0; n < t.i.length; ++n) {\n                    var u = t.i[n];\n                    u.required && i(\"if(!m.hasOwnProperty(%j))\", u.name)(\"throw util.ProtocolError(%j,{instance:m})\", \"missing required '\" + u.name + \"'\")\n                }\n                return i(\"return m\")\n            }\n            ;\n            var o = t(14)\n              , h = t(32)\n              , f = t(33)\n        }\n        , {\n            14: 14,\n            32: 32,\n            33: 33\n        }],\n        13: [function(t, i, n) {\n            i.exports = function(t) {\n                for (var i, n = a.codegen([\"m\", \"w\"], t.name + \"$encode\")(\"if(!w)\")(\"w=Writer.create()\"), r = t.fieldsArray.slice().sort(a.compareFieldsById), e = 0; e < r.length; ++e) {\n                    var s = r[e].resolve()\n                      , u = t.i.indexOf(s)\n                      , o = s.resolvedType instanceof f ? \"int32\" : s.type\n                      , h = c.basic[o];\n                    i = \"m\" + a.safeProp(s.name),\n                    s.map ? (n(\"if(%s!=null&&Object.hasOwnProperty.call(m,%j)){\", i, s.name)(\"for(var ks=Object.keys(%s),i=0;i<ks.length;++i){\", i)(\"w.uint32(%i).fork().uint32(%i).%s(ks[i])\", (s.id << 3 | 2) >>> 0, 8 | c.mapKey[s.keyType], s.keyType),\n                    h === g ? n(\"types[%i].encode(%s[ks[i]],w.uint32(18).fork()).ldelim().ldelim()\", u, i) : n(\".uint32(%i).%s(%s[ks[i]]).ldelim()\", 16 | h, o, i),\n                    n(\"}\")(\"}\")) : s.repeated ? (n(\"if(%s!=null&&%s.length){\", i, i),\n                    s.packed && c.packed[o] !== g ? n(\"w.uint32(%i).fork()\", (s.id << 3 | 2) >>> 0)(\"for(var i=0;i<%s.length;++i)\", i)(\"w.%s(%s[i])\", o, i)(\"w.ldelim()\") : (n(\"for(var i=0;i<%s.length;++i)\", i),\n                    h === g ? l(n, s, u, i + \"[i]\") : n(\"w.uint32(%i).%s(%s[i])\", (s.id << 3 | h) >>> 0, o, i)),\n                    n(\"}\")) : (s.optional && n(\"if(%s!=null&&Object.hasOwnProperty.call(m,%j))\", i, s.name),\n                    h === g ? l(n, s, u, i) : n(\"w.uint32(%i).%s(%s)\", (s.id << 3 | h) >>> 0, o, i))\n                }\n                return n(\"return w\")\n            }\n            ;\n            var f = t(14)\n              , c = t(32)\n              , a = t(33);\n            function l(t, i, n, r) {\n                return i.resolvedType.group ? t(\"types[%i].encode(%s,w.uint32(%i)).uint32(%i)\", n, r, (i.id << 3 | 3) >>> 0, (i.id << 3 | 4) >>> 0) : t(\"types[%i].encode(%s,w.uint32(%i).fork()).ldelim()\", n, r, (i.id << 3 | 2) >>> 0)\n            }\n        }\n        , {\n            14: 14,\n            32: 32,\n            33: 33\n        }],\n        14: [function(t, i, n) {\n            i.exports = s;\n            var o = t(22);\n            ((s.prototype = Object.create(o.prototype)).constructor = s).className = \"Enum\";\n            var r = t(21)\n              , e = t(33);\n            function s(t, i, n, r, e) {\n                if (o.call(this, t, n),\n                i && \"object\" != typeof i)\n                    throw TypeError(\"values must be an object\");\n                if (this.valuesById = {},\n                this.values = Object.create(this.valuesById),\n                this.comment = r,\n                this.comments = e || {},\n                this.reserved = g,\n                i)\n                    for (var s = Object.keys(i), u = 0; u < s.length; ++u)\n                        \"number\" == typeof i[s[u]] && (this.valuesById[this.values[s[u]] = i[s[u]]] = s[u])\n            }\n            s.fromJSON = function(t, i) {\n                t = new s(t,i.values,i.options,i.comment,i.comments);\n                return t.reserved = i.reserved,\n                t\n            }\n            ,\n            s.prototype.toJSON = function(t) {\n                t = !!t && !!t.keepComments;\n                return e.toObject([\"options\", this.options, \"values\", this.values, \"reserved\", this.reserved && this.reserved.length ? this.reserved : g, \"comment\", t ? this.comment : g, \"comments\", t ? this.comments : g])\n            }\n            ,\n            s.prototype.add = function(t, i, n) {\n                if (!e.isString(t))\n                    throw TypeError(\"name must be a string\");\n                if (!e.isInteger(i))\n                    throw TypeError(\"id must be an integer\");\n                if (this.values[t] !== g)\n                    throw Error(\"duplicate name '\" + t + \"' in \" + this);\n                if (this.isReservedId(i))\n                    throw Error(\"id \" + i + \" is reserved in \" + this);\n                if (this.isReservedName(t))\n                    throw Error(\"name '\" + t + \"' is reserved in \" + this);\n                if (this.valuesById[i] !== g) {\n                    if (!this.options || !this.options.allow_alias)\n                        throw Error(\"duplicate id \" + i + \" in \" + this);\n                    this.values[t] = i\n                } else\n                    this.valuesById[this.values[t] = i] = t;\n                return this.comments[t] = n || null,\n                this\n            }\n            ,\n            s.prototype.remove = function(t) {\n                if (!e.isString(t))\n                    throw TypeError(\"name must be a string\");\n                var i = this.values[t];\n                if (null == i)\n                    throw Error(\"name '\" + t + \"' does not exist in \" + this);\n                return delete this.valuesById[i],\n                delete this.values[t],\n                delete this.comments[t],\n                this\n            }\n            ,\n            s.prototype.isReservedId = function(t) {\n                return r.isReservedId(this.reserved, t)\n            }\n            ,\n            s.prototype.isReservedName = function(t) {\n                return r.isReservedName(this.reserved, t)\n            }\n        }\n        , {\n            21: 21,\n            22: 22,\n            33: 33\n        }],\n        15: [function(t, i, n) {\n            i.exports = u;\n            var o = t(22);\n            ((u.prototype = Object.create(o.prototype)).constructor = u).className = \"Field\";\n            var r, e = t(14), h = t(32), f = t(33), c = /^required|optional|repeated$/;\n            function u(t, i, n, r, e, s, u) {\n                if (f.isObject(r) ? (u = e,\n                s = r,\n                r = e = g) : f.isObject(e) && (u = s,\n                s = e,\n                e = g),\n                o.call(this, t, s),\n                !f.isInteger(i) || i < 0)\n                    throw TypeError(\"id must be a non-negative integer\");\n                if (!f.isString(n))\n                    throw TypeError(\"type must be a string\");\n                if (r !== g && !c.test(r = r.toString().toLowerCase()))\n                    throw TypeError(\"rule must be a string rule\");\n                if (e !== g && !f.isString(e))\n                    throw TypeError(\"extend must be a string\");\n                this.rule = (r = \"proto3_optional\" === r ? \"optional\" : r) && \"optional\" !== r ? r : g,\n                this.type = n,\n                this.id = i,\n                this.extend = e || g,\n                this.required = \"required\" === r,\n                this.optional = !this.required,\n                this.repeated = \"repeated\" === r,\n                this.map = !1,\n                this.message = null,\n                this.partOf = null,\n                this.typeDefault = null,\n                this.defaultValue = null,\n                this.long = !!f.Long && h.long[n] !== g,\n                this.bytes = \"bytes\" === n,\n                this.resolvedType = null,\n                this.extensionField = null,\n                this.declaringField = null,\n                this.n = null,\n                this.comment = u\n            }\n            u.fromJSON = function(t, i) {\n                return new u(t,i.id,i.type,i.rule,i.extend,i.options,i.comment)\n            }\n            ,\n            Object.defineProperty(u.prototype, \"packed\", {\n                get: function() {\n                    return null === this.n && (this.n = !1 !== this.getOption(\"packed\")),\n                    this.n\n                }\n            }),\n            u.prototype.setOption = function(t, i, n) {\n                return \"packed\" === t && (this.n = null),\n                o.prototype.setOption.call(this, t, i, n)\n            }\n            ,\n            u.prototype.toJSON = function(t) {\n                t = !!t && !!t.keepComments;\n                return f.toObject([\"rule\", \"optional\" !== this.rule && this.rule || g, \"type\", this.type, \"id\", this.id, \"extend\", this.extend, \"options\", this.options, \"comment\", t ? this.comment : g])\n            }\n            ,\n            u.prototype.resolve = function() {\n                return this.resolved ? this : ((this.typeDefault = h.defaults[this.type]) === g && (this.resolvedType = (this.declaringField || this).parent.lookupTypeOrEnum(this.type),\n                this.resolvedType instanceof r ? this.typeDefault = null : this.typeDefault = this.resolvedType.values[Object.keys(this.resolvedType.values)[0]]),\n                this.options && null != this.options.default && (this.typeDefault = this.options.default,\n                this.resolvedType instanceof e && \"string\" == typeof this.typeDefault && (this.typeDefault = this.resolvedType.values[this.typeDefault])),\n                this.options && (!0 !== this.options.packed && (this.options.packed === g || !this.resolvedType || this.resolvedType instanceof e) || delete this.options.packed,\n                Object.keys(this.options).length || (this.options = g)),\n                this.long ? (this.typeDefault = f.Long.fromNumber(this.typeDefault, \"u\" == (this.type[0] || \"\")),\n                Object.freeze && Object.freeze(this.typeDefault)) : this.bytes && \"string\" == typeof this.typeDefault && (f.base64.test(this.typeDefault) ? f.base64.decode(this.typeDefault, t = f.newBuffer(f.base64.length(this.typeDefault)), 0) : f.utf8.write(this.typeDefault, t = f.newBuffer(f.utf8.length(this.typeDefault)), 0),\n                this.typeDefault = t),\n                this.map ? this.defaultValue = f.emptyObject : this.repeated ? this.defaultValue = f.emptyArray : this.defaultValue = this.typeDefault,\n                this.parent instanceof r && (this.parent.ctor.prototype[this.name] = this.defaultValue),\n                o.prototype.resolve.call(this));\n                var t\n            }\n            ,\n            u.d = function(n, r, e, s) {\n                return \"function\" == typeof r ? r = f.decorateType(r).name : r && \"object\" == typeof r && (r = f.decorateEnum(r).name),\n                function(t, i) {\n                    f.decorateType(t.constructor).add(new u(i,n,r,e,{\n                        default: s\n                    }))\n                }\n            }\n            ,\n            u.r = function(t) {\n                r = t\n            }\n        }\n        , {\n            14: 14,\n            22: 22,\n            32: 32,\n            33: 33\n        }],\n        16: [function(t, i, n) {\n            var r = i.exports = t(17);\n            r.build = \"light\",\n            r.load = function(t, i, n) {\n                return (i = \"function\" == typeof i ? (n = i,\n                new r.Root) : i || new r.Root).load(t, n)\n            }\n            ,\n            r.loadSync = function(t, i) {\n                return (i = i || new r.Root).loadSync(t)\n            }\n            ,\n            r.encoder = t(13),\n            r.decoder = t(12),\n            r.verifier = t(36),\n            r.converter = t(11),\n            r.ReflectionObject = t(22),\n            r.Namespace = t(21),\n            r.Root = t(26),\n            r.Enum = t(14),\n            r.Type = t(31),\n            r.Field = t(15),\n            r.OneOf = t(23),\n            r.MapField = t(18),\n            r.Service = t(30),\n            r.Method = t(20),\n            r.Message = t(19),\n            r.wrappers = t(37),\n            r.types = t(32),\n            r.util = t(33),\n            r.ReflectionObject.r(r.Root),\n            r.Namespace.r(r.Type, r.Service, r.Enum),\n            r.Root.r(r.Type),\n            r.Field.r(r.Type)\n        }\n        , {\n            11: 11,\n            12: 12,\n            13: 13,\n            14: 14,\n            15: 15,\n            17: 17,\n            18: 18,\n            19: 19,\n            20: 20,\n            21: 21,\n            22: 22,\n            23: 23,\n            26: 26,\n            30: 30,\n            31: 31,\n            32: 32,\n            33: 33,\n            36: 36,\n            37: 37\n        }],\n        17: [function(t, i, n) {\n            var r = n;\n            function e() {\n                r.util.r(),\n                r.Writer.r(r.BufferWriter),\n                r.Reader.r(r.BufferReader)\n            }\n            r.build = \"minimal\",\n            r.Writer = t(38),\n            r.BufferWriter = t(39),\n            r.Reader = t(24),\n            r.BufferReader = t(25),\n            r.util = t(35),\n            r.rpc = t(28),\n            r.roots = t(27),\n            r.configure = e,\n            e()\n        }\n        , {\n            24: 24,\n            25: 25,\n            27: 27,\n            28: 28,\n            35: 35,\n            38: 38,\n            39: 39\n        }],\n        18: [function(t, i, n) {\n            i.exports = s;\n            var u = t(15);\n            ((s.prototype = Object.create(u.prototype)).constructor = s).className = \"MapField\";\n            var r = t(32)\n              , o = t(33);\n            function s(t, i, n, r, e, s) {\n                if (u.call(this, t, i, r, g, g, e, s),\n                !o.isString(n))\n                    throw TypeError(\"keyType must be a string\");\n                this.keyType = n,\n                this.resolvedKeyType = null,\n                this.map = !0\n            }\n            s.fromJSON = function(t, i) {\n                return new s(t,i.id,i.keyType,i.type,i.options,i.comment)\n            }\n            ,\n            s.prototype.toJSON = function(t) {\n                t = !!t && !!t.keepComments;\n                return o.toObject([\"keyType\", this.keyType, \"type\", this.type, \"id\", this.id, \"extend\", this.extend, \"options\", this.options, \"comment\", t ? this.comment : g])\n            }\n            ,\n            s.prototype.resolve = function() {\n                if (this.resolved)\n                    return this;\n                if (r.mapKey[this.keyType] === g)\n                    throw Error(\"invalid key type: \" + this.keyType);\n                return u.prototype.resolve.call(this)\n            }\n            ,\n            s.d = function(n, r, e) {\n                return \"function\" == typeof e ? e = o.decorateType(e).name : e && \"object\" == typeof e && (e = o.decorateEnum(e).name),\n                function(t, i) {\n                    o.decorateType(t.constructor).add(new s(i,n,r,e))\n                }\n            }\n        }\n        , {\n            15: 15,\n            32: 32,\n            33: 33\n        }],\n        19: [function(t, i, n) {\n            i.exports = e;\n            var r = t(35);\n            function e(t) {\n                if (t)\n                    for (var i = Object.keys(t), n = 0; n < i.length; ++n)\n                        this[i[n]] = t[i[n]]\n            }\n            e.create = function(t) {\n                return this.$type.create(t)\n            }\n            ,\n            e.encode = function(t, i) {\n                return this.$type.encode(t, i)\n            }\n            ,\n            e.encodeDelimited = function(t, i) {\n                return this.$type.encodeDelimited(t, i)\n            }\n            ,\n            e.decode = function(t) {\n                return this.$type.decode(t)\n            }\n            ,\n            e.decodeDelimited = function(t) {\n                return this.$type.decodeDelimited(t)\n            }\n            ,\n            e.verify = function(t) {\n                return this.$type.verify(t)\n            }\n            ,\n            e.fromObject = function(t) {\n                return this.$type.fromObject(t)\n            }\n            ,\n            e.toObject = function(t, i) {\n                return this.$type.toObject(t, i)\n            }\n            ,\n            e.prototype.toJSON = function() {\n                return this.$type.toObject(this, r.toJSONOptions)\n            }\n        }\n        , {\n            35: 35\n        }],\n        20: [function(t, i, n) {\n            i.exports = r;\n            var f = t(22);\n            ((r.prototype = Object.create(f.prototype)).constructor = r).className = \"Method\";\n            var c = t(33);\n            function r(t, i, n, r, e, s, u, o, h) {\n                if (c.isObject(e) ? (u = e,\n                e = s = g) : c.isObject(s) && (u = s,\n                s = g),\n                i !== g && !c.isString(i))\n                    throw TypeError(\"type must be a string\");\n                if (!c.isString(n))\n                    throw TypeError(\"requestType must be a string\");\n                if (!c.isString(r))\n                    throw TypeError(\"responseType must be a string\");\n                f.call(this, t, u),\n                this.type = i || \"rpc\",\n                this.requestType = n,\n                this.requestStream = !!e || g,\n                this.responseType = r,\n                this.responseStream = !!s || g,\n                this.resolvedRequestType = null,\n                this.resolvedResponseType = null,\n                this.comment = o,\n                this.parsedOptions = h\n            }\n            r.fromJSON = function(t, i) {\n                return new r(t,i.type,i.requestType,i.responseType,i.requestStream,i.responseStream,i.options,i.comment,i.parsedOptions)\n            }\n            ,\n            r.prototype.toJSON = function(t) {\n                t = !!t && !!t.keepComments;\n                return c.toObject([\"type\", \"rpc\" !== this.type && this.type || g, \"requestType\", this.requestType, \"requestStream\", this.requestStream, \"responseType\", this.responseType, \"responseStream\", this.responseStream, \"options\", this.options, \"comment\", t ? this.comment : g, \"parsedOptions\", this.parsedOptions])\n            }\n            ,\n            r.prototype.resolve = function() {\n                return this.resolved ? this : (this.resolvedRequestType = this.parent.lookupType(this.requestType),\n                this.resolvedResponseType = this.parent.lookupType(this.responseType),\n                f.prototype.resolve.call(this))\n            }\n        }\n        , {\n            22: 22,\n            33: 33\n        }],\n        21: [function(t, i, n) {\n            i.exports = c;\n            var r = t(22);\n            ((c.prototype = Object.create(r.prototype)).constructor = c).className = \"Namespace\";\n            var e, s, u, o = t(15), h = t(33);\n            function f(t, i) {\n                if (!t || !t.length)\n                    return g;\n                for (var n = {}, r = 0; r < t.length; ++r)\n                    n[t[r].name] = t[r].toJSON(i);\n                return n\n            }\n            function c(t, i) {\n                r.call(this, t, i),\n                this.nested = g,\n                this.e = null\n            }\n            function a(t) {\n                return t.e = null,\n                t\n            }\n            c.fromJSON = function(t, i) {\n                return new c(t,i.options).addJSON(i.nested)\n            }\n            ,\n            c.arrayToJSON = f,\n            c.isReservedId = function(t, i) {\n                if (t)\n                    for (var n = 0; n < t.length; ++n)\n                        if (\"string\" != typeof t[n] && t[n][0] <= i && t[n][1] > i)\n                            return !0;\n                return !1\n            }\n            ,\n            c.isReservedName = function(t, i) {\n                if (t)\n                    for (var n = 0; n < t.length; ++n)\n                        if (t[n] === i)\n                            return !0;\n                return !1\n            }\n            ,\n            Object.defineProperty(c.prototype, \"nestedArray\", {\n                get: function() {\n                    return this.e || (this.e = h.toArray(this.nested))\n                }\n            }),\n            c.prototype.toJSON = function(t) {\n                return h.toObject([\"options\", this.options, \"nested\", f(this.nestedArray, t)])\n            }\n            ,\n            c.prototype.addJSON = function(t) {\n                if (t)\n                    for (var i, n = Object.keys(t), r = 0; r < n.length; ++r)\n                        i = t[n[r]],\n                        this.add((i.fields !== g ? e : i.values !== g ? u : i.methods !== g ? s : i.id !== g ? o : c).fromJSON(n[r], i));\n                return this\n            }\n            ,\n            c.prototype.get = function(t) {\n                return this.nested && this.nested[t] || null\n            }\n            ,\n            c.prototype.getEnum = function(t) {\n                if (this.nested && this.nested[t]instanceof u)\n                    return this.nested[t].values;\n                throw Error(\"no such enum: \" + t)\n            }\n            ,\n            c.prototype.add = function(t) {\n                if (!(t instanceof o && t.extend !== g || t instanceof e || t instanceof u || t instanceof s || t instanceof c))\n                    throw TypeError(\"object must be a valid nested object\");\n                if (this.nested) {\n                    var i = this.get(t.name);\n                    if (i) {\n                        if (!(i instanceof c && t instanceof c) || i instanceof e || i instanceof s)\n                            throw Error(\"duplicate name '\" + t.name + \"' in \" + this);\n                        for (var n = i.nestedArray, r = 0; r < n.length; ++r)\n                            t.add(n[r]);\n                        this.remove(i),\n                        this.nested || (this.nested = {}),\n                        t.setOptions(i.options, !0)\n                    }\n                } else\n                    this.nested = {};\n                return (this.nested[t.name] = t).onAdd(this),\n                a(this)\n            }\n            ,\n            c.prototype.remove = function(t) {\n                if (!(t instanceof r))\n                    throw TypeError(\"object must be a ReflectionObject\");\n                if (t.parent !== this)\n                    throw Error(t + \" is not a member of \" + this);\n                return delete this.nested[t.name],\n                Object.keys(this.nested).length || (this.nested = g),\n                t.onRemove(this),\n                a(this)\n            }\n            ,\n            c.prototype.define = function(t, i) {\n                if (h.isString(t))\n                    t = t.split(\".\");\n                else if (!Array.isArray(t))\n                    throw TypeError(\"illegal path\");\n                if (t && t.length && \"\" === t[0])\n                    throw Error(\"path must be relative\");\n                for (var n = this; 0 < t.length; ) {\n                    var r = t.shift();\n                    if (n.nested && n.nested[r]) {\n                        if (!((n = n.nested[r])instanceof c))\n                            throw Error(\"path conflicts with non-namespace objects\")\n                    } else\n                        n.add(n = new c(r))\n                }\n                return i && n.addJSON(i),\n                n\n            }\n            ,\n            c.prototype.resolveAll = function() {\n                for (var t = this.nestedArray, i = 0; i < t.length; )\n                    t[i]instanceof c ? t[i++].resolveAll() : t[i++].resolve();\n                return this.resolve()\n            }\n            ,\n            c.prototype.lookup = function(t, i, n) {\n                if (\"boolean\" == typeof i ? (n = i,\n                i = g) : i && !Array.isArray(i) && (i = [i]),\n                h.isString(t) && t.length) {\n                    if (\".\" === t)\n                        return this.root;\n                    t = t.split(\".\")\n                } else if (!t.length)\n                    return this;\n                if (\"\" === t[0])\n                    return this.root.lookup(t.slice(1), i);\n                var r = this.get(t[0]);\n                if (r) {\n                    if (1 === t.length) {\n                        if (!i || ~i.indexOf(r.constructor))\n                            return r\n                    } else if (r instanceof c && (r = r.lookup(t.slice(1), i, !0)))\n                        return r\n                } else\n                    for (var e = 0; e < this.nestedArray.length; ++e)\n                        if (this.e[e]instanceof c && (r = this.e[e].lookup(t, i, !0)))\n                            return r;\n                return null === this.parent || n ? null : this.parent.lookup(t, i)\n            }\n            ,\n            c.prototype.lookupType = function(t) {\n                var i = this.lookup(t, [e]);\n                if (!i)\n                    throw Error(\"no such type: \" + t);\n                return i\n            }\n            ,\n            c.prototype.lookupEnum = function(t) {\n                var i = this.lookup(t, [u]);\n                if (!i)\n                    throw Error(\"no such Enum '\" + t + \"' in \" + this);\n                return i\n            }\n            ,\n            c.prototype.lookupTypeOrEnum = function(t) {\n                var i = this.lookup(t, [e, u]);\n                if (!i)\n                    throw Error(\"no such Type or Enum '\" + t + \"' in \" + this);\n                return i\n            }\n            ,\n            c.prototype.lookupService = function(t) {\n                var i = this.lookup(t, [s]);\n                if (!i)\n                    throw Error(\"no such Service '\" + t + \"' in \" + this);\n                return i\n            }\n            ,\n            c.r = function(t, i, n) {\n                e = t,\n                s = i,\n                u = n\n            }\n        }\n        , {\n            15: 15,\n            22: 22,\n            33: 33\n        }],\n        22: [function(t, i, n) {\n            (i.exports = e).className = \"ReflectionObject\";\n            var r, u = t(33);\n            function e(t, i) {\n                if (!u.isString(t))\n                    throw TypeError(\"name must be a string\");\n                if (i && !u.isObject(i))\n                    throw TypeError(\"options must be an object\");\n                this.options = i,\n                this.parsedOptions = null,\n                this.name = t,\n                this.parent = null,\n                this.resolved = !1,\n                this.comment = null,\n                this.filename = null\n            }\n            Object.defineProperties(e.prototype, {\n                root: {\n                    get: function() {\n                        for (var t = this; null !== t.parent; )\n                            t = t.parent;\n                        return t\n                    }\n                },\n                fullName: {\n                    get: function() {\n                        for (var t = [this.name], i = this.parent; i; )\n                            t.unshift(i.name),\n                            i = i.parent;\n                        return t.join(\".\")\n                    }\n                }\n            }),\n            e.prototype.toJSON = function() {\n                throw Error()\n            }\n            ,\n            e.prototype.onAdd = function(t) {\n                this.parent && this.parent !== t && this.parent.remove(this),\n                this.parent = t,\n                this.resolved = !1;\n                t = t.root;\n                t instanceof r && t.u(this)\n            }\n            ,\n            e.prototype.onRemove = function(t) {\n                t = t.root;\n                t instanceof r && t.o(this),\n                this.parent = null,\n                this.resolved = !1\n            }\n            ,\n            e.prototype.resolve = function() {\n                return this.resolved || this.root instanceof r && (this.resolved = !0),\n                this\n            }\n            ,\n            e.prototype.getOption = function(t) {\n                return this.options ? this.options[t] : g\n            }\n            ,\n            e.prototype.setOption = function(t, i, n) {\n                return n && this.options && this.options[t] !== g || ((this.options || (this.options = {}))[t] = i),\n                this\n            }\n            ,\n            e.prototype.setParsedOption = function(i, t, n) {\n                this.parsedOptions || (this.parsedOptions = []);\n                var r, e, s = this.parsedOptions;\n                return n ? (e = s.find(function(t) {\n                    return Object.prototype.hasOwnProperty.call(t, i)\n                })) ? (r = e[i],\n                u.setProperty(r, n, t)) : ((e = {})[i] = u.setProperty({}, n, t),\n                s.push(e)) : ((e = {})[i] = t,\n                s.push(e)),\n                this\n            }\n            ,\n            e.prototype.setOptions = function(t, i) {\n                if (t)\n                    for (var n = Object.keys(t), r = 0; r < n.length; ++r)\n                        this.setOption(n[r], t[n[r]], i);\n                return this\n            }\n            ,\n            e.prototype.toString = function() {\n                var t = this.constructor.className\n                  , i = this.fullName;\n                return i.length ? t + \" \" + i : t\n            }\n            ,\n            e.r = function(t) {\n                r = t\n            }\n        }\n        , {\n            33: 33\n        }],\n        23: [function(t, i, n) {\n            i.exports = u;\n            var e = t(22);\n            ((u.prototype = Object.create(e.prototype)).constructor = u).className = \"OneOf\";\n            var r = t(15)\n              , s = t(33);\n            function u(t, i, n, r) {\n                if (Array.isArray(i) || (n = i,\n                i = g),\n                e.call(this, t, n),\n                i !== g && !Array.isArray(i))\n                    throw TypeError(\"fieldNames must be an Array\");\n                this.oneof = i || [],\n                this.fieldsArray = [],\n                this.comment = r\n            }\n            function o(t) {\n                if (t.parent)\n                    for (var i = 0; i < t.fieldsArray.length; ++i)\n                        t.fieldsArray[i].parent || t.parent.add(t.fieldsArray[i])\n            }\n            u.fromJSON = function(t, i) {\n                return new u(t,i.oneof,i.options,i.comment)\n            }\n            ,\n            u.prototype.toJSON = function(t) {\n                t = !!t && !!t.keepComments;\n                return s.toObject([\"options\", this.options, \"oneof\", this.oneof, \"comment\", t ? this.comment : g])\n            }\n            ,\n            u.prototype.add = function(t) {\n                if (!(t instanceof r))\n                    throw TypeError(\"field must be a Field\");\n                return t.parent && t.parent !== this.parent && t.parent.remove(t),\n                this.oneof.push(t.name),\n                this.fieldsArray.push(t),\n                o(t.partOf = this),\n                this\n            }\n            ,\n            u.prototype.remove = function(t) {\n                if (!(t instanceof r))\n                    throw TypeError(\"field must be a Field\");\n                var i = this.fieldsArray.indexOf(t);\n                if (i < 0)\n                    throw Error(t + \" is not a member of \" + this);\n                return this.fieldsArray.splice(i, 1),\n                -1 < (i = this.oneof.indexOf(t.name)) && this.oneof.splice(i, 1),\n                t.partOf = null,\n                this\n            }\n            ,\n            u.prototype.onAdd = function(t) {\n                e.prototype.onAdd.call(this, t);\n                for (var i = 0; i < this.oneof.length; ++i) {\n                    var n = t.get(this.oneof[i]);\n                    n && !n.partOf && (n.partOf = this).fieldsArray.push(n)\n                }\n                o(this)\n            }\n            ,\n            u.prototype.onRemove = function(t) {\n                for (var i, n = 0; n < this.fieldsArray.length; ++n)\n                    (i = this.fieldsArray[n]).parent && i.parent.remove(i);\n                e.prototype.onRemove.call(this, t)\n            }\n            ,\n            u.d = function() {\n                for (var n = Array(arguments.length), t = 0; t < arguments.length; )\n                    n[t] = arguments[t++];\n                return function(t, i) {\n                    s.decorateType(t.constructor).add(new u(i,n)),\n                    Object.defineProperty(t, i, {\n                        get: s.oneOfGetter(n),\n                        set: s.oneOfSetter(n)\n                    })\n                }\n            }\n        }\n        , {\n            15: 15,\n            22: 22,\n            33: 33\n        }],\n        24: [function(t, i, n) {\n            i.exports = h;\n            var r, e = t(35), s = e.LongBits, u = e.utf8;\n            function o(t, i) {\n                return RangeError(\"index out of range: \" + t.pos + \" + \" + (i || 1) + \" > \" + t.len)\n            }\n            function h(t) {\n                this.buf = t,\n                this.pos = 0,\n                this.len = t.length\n            }\n            function f() {\n                return e.Buffer ? function(t) {\n                    return (h.create = function(t) {\n                        return e.Buffer.isBuffer(t) ? new r(t) : a(t)\n                    }\n                    )(t)\n                }\n                : a\n            }\n            var c, a = \"undefined\" != typeof Uint8Array ? function(t) {\n                if (t instanceof Uint8Array || Array.isArray(t))\n                    return new h(t);\n                throw Error(\"illegal buffer\")\n            }\n            : function(t) {\n                if (Array.isArray(t))\n                    return new h(t);\n                throw Error(\"illegal buffer\")\n            }\n            ;\n            function l() {\n                var t = new s(0,0)\n                  , i = 0;\n                if (!(4 < this.len - this.pos)) {\n                    for (; i < 3; ++i) {\n                        if (this.pos >= this.len)\n                            throw o(this);\n                        if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * i) >>> 0,\n                        this.buf[this.pos++] < 128)\n                            return t\n                    }\n                    return t.lo = (t.lo | (127 & this.buf[this.pos++]) << 7 * i) >>> 0,\n                    t\n                }\n                for (; i < 4; ++i)\n                    if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * i) >>> 0,\n                    this.buf[this.pos++] < 128)\n                        return t;\n                if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 28) >>> 0,\n                t.hi = (t.hi | (127 & this.buf[this.pos]) >> 4) >>> 0,\n                this.buf[this.pos++] < 128)\n                    return t;\n                if (i = 0,\n                4 < this.len - this.pos) {\n                    for (; i < 5; ++i)\n                        if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * i + 3) >>> 0,\n                        this.buf[this.pos++] < 128)\n                            return t\n                } else\n                    for (; i < 5; ++i) {\n                        if (this.pos >= this.len)\n                            throw o(this);\n                        if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * i + 3) >>> 0,\n                        this.buf[this.pos++] < 128)\n                            return t\n                    }\n                throw Error(\"invalid varint encoding\")\n            }\n            function v(t, i) {\n                return (t[i - 4] | t[i - 3] << 8 | t[i - 2] << 16 | t[i - 1] << 24) >>> 0\n            }\n            function d() {\n                if (this.pos + 8 > this.len)\n                    throw o(this, 8);\n                return new s(v(this.buf, this.pos += 4),v(this.buf, this.pos += 4))\n            }\n            h.create = f(),\n            h.prototype.h = e.Array.prototype.subarray || e.Array.prototype.slice,\n            h.prototype.uint32 = (c = 4294967295,\n            function() {\n                if (c = (127 & this.buf[this.pos]) >>> 0,\n                this.buf[this.pos++] < 128)\n                    return c;\n                if (c = (c | (127 & this.buf[this.pos]) << 7) >>> 0,\n                this.buf[this.pos++] < 128)\n                    return c;\n                if (c = (c | (127 & this.buf[this.pos]) << 14) >>> 0,\n                this.buf[this.pos++] < 128)\n                    return c;\n                if (c = (c | (127 & this.buf[this.pos]) << 21) >>> 0,\n                this.buf[this.pos++] < 128)\n                    return c;\n                if (c = (c | (15 & this.buf[this.pos]) << 28) >>> 0,\n                this.buf[this.pos++] < 128)\n                    return c;\n                if ((this.pos += 5) > this.len)\n                    throw this.pos = this.len,\n                    o(this, 10);\n                return c\n            }\n            ),\n            h.prototype.int32 = function() {\n                return 0 | this.uint32()\n            }\n            ,\n            h.prototype.sint32 = function() {\n                var t = this.uint32();\n                return t >>> 1 ^ -(1 & t) | 0\n            }\n            ,\n            h.prototype.bool = function() {\n                return 0 !== this.uint32()\n            }\n            ,\n            h.prototype.fixed32 = function() {\n                if (this.pos + 4 > this.len)\n                    throw o(this, 4);\n                return v(this.buf, this.pos += 4)\n            }\n            ,\n            h.prototype.sfixed32 = function() {\n                if (this.pos + 4 > this.len)\n                    throw o(this, 4);\n                return 0 | v(this.buf, this.pos += 4)\n            }\n            ,\n            h.prototype.float = function() {\n                if (this.pos + 4 > this.len)\n                    throw o(this, 4);\n                var t = e.float.readFloatLE(this.buf, this.pos);\n                return this.pos += 4,\n                t\n            }\n            ,\n            h.prototype.double = function() {\n                if (this.pos + 8 > this.len)\n                    throw o(this, 4);\n                var t = e.float.readDoubleLE(this.buf, this.pos);\n                return this.pos += 8,\n                t\n            }\n            ,\n            h.prototype.bytes = function() {\n                var t = this.uint32()\n                  , i = this.pos\n                  , n = this.pos + t;\n                if (n > this.len)\n                    throw o(this, t);\n                return this.pos += t,\n                Array.isArray(this.buf) ? this.buf.slice(i, n) : i === n ? new this.buf.constructor(0) : this.h.call(this.buf, i, n)\n            }\n            ,\n            h.prototype.string = function() {\n                var t = this.bytes();\n                return u.read(t, 0, t.length)\n            }\n            ,\n            h.prototype.skip = function(t) {\n                if (\"number\" == typeof t) {\n                    if (this.pos + t > this.len)\n                        throw o(this, t);\n                    this.pos += t\n                } else\n                    do {\n                        if (this.pos >= this.len)\n                            throw o(this)\n                    } while (128 & this.buf[this.pos++]);\n                return this\n            }\n            ,\n            h.prototype.skipType = function(t) {\n                switch (t) {\n                case 0:\n                    this.skip();\n                    break;\n                case 1:\n                    this.skip(8);\n                    break;\n                case 2:\n                    this.skip(this.uint32());\n                    break;\n                case 3:\n                    for (; 4 != (t = 7 & this.uint32()); )\n                        this.skipType(t);\n                    break;\n                case 5:\n                    this.skip(4);\n                    break;\n                default:\n                    throw Error(\"invalid wire type \" + t + \" at offset \" + this.pos)\n                }\n                return this\n            }\n            ,\n            h.r = function(t) {\n                r = t,\n                h.create = f(),\n                r.r();\n                var i = e.Long ? \"toLong\" : \"toNumber\";\n                e.merge(h.prototype, {\n                    int64: function() {\n                        return l.call(this)[i](!1)\n                    },\n                    uint64: function() {\n                        return l.call(this)[i](!0)\n                    },\n                    sint64: function() {\n                        return l.call(this).zzDecode()[i](!1)\n                    },\n                    fixed64: function() {\n                        return d.call(this)[i](!0)\n                    },\n                    sfixed64: function() {\n                        return d.call(this)[i](!1)\n                    }\n                })\n            }\n        }\n        , {\n            35: 35\n        }],\n        25: [function(t, i, n) {\n            i.exports = s;\n            var r = t(24);\n            (s.prototype = Object.create(r.prototype)).constructor = s;\n            var e = t(35);\n            function s(t) {\n                r.call(this, t)\n            }\n            s.r = function() {\n                e.Buffer && (s.prototype.h = e.Buffer.prototype.slice)\n            }\n            ,\n            s.prototype.string = function() {\n                var t = this.uint32();\n                return this.buf.utf8Slice ? this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + t, this.len)) : this.buf.toString(\"utf-8\", this.pos, this.pos = Math.min(this.pos + t, this.len))\n            }\n            ,\n            s.r()\n        }\n        , {\n            24: 24,\n            35: 35\n        }],\n        26: [function(t, i, n) {\n            i.exports = h;\n            var r = t(21);\n            ((h.prototype = Object.create(r.prototype)).constructor = h).className = \"Root\";\n            var e, v, d, s = t(15), u = t(14), o = t(23), b = t(33);\n            function h(t) {\n                r.call(this, \"\", t),\n                this.deferred = [],\n                this.files = []\n            }\n            function p() {}\n            h.fromJSON = function(t, i) {\n                return i = i || new h,\n                t.options && i.setOptions(t.options),\n                i.addJSON(t.nested)\n            }\n            ,\n            h.prototype.resolvePath = b.path.resolve,\n            h.prototype.fetch = b.fetch,\n            h.prototype.load = function t(i, s, e) {\n                \"function\" == typeof s && (e = s,\n                s = g);\n                var u = this;\n                if (!e)\n                    return b.asPromise(t, u, i, s);\n                var o = e === p;\n                function h(t, i) {\n                    if (e) {\n                        var n = e;\n                        if (e = null,\n                        o)\n                            throw t;\n                        n(t, i)\n                    }\n                }\n                function f(t) {\n                    var i = t.lastIndexOf(\"google/protobuf/\");\n                    if (-1 < i) {\n                        i = t.substring(i);\n                        if (i in d)\n                            return i\n                    }\n                    return null\n                }\n                function c(t, i) {\n                    try {\n                        if (b.isString(i) && \"{\" == (i[0] || \"\") && (i = JSON.parse(i)),\n                        b.isString(i)) {\n                            v.filename = t;\n                            var n, r = v(i, u, s), e = 0;\n                            if (r.imports)\n                                for (; e < r.imports.length; ++e)\n                                    (n = f(r.imports[e]) || u.resolvePath(t, r.imports[e])) && a(n);\n                            if (r.weakImports)\n                                for (e = 0; e < r.weakImports.length; ++e)\n                                    (n = f(r.weakImports[e]) || u.resolvePath(t, r.weakImports[e])) && a(n, !0)\n                        } else\n                            u.setOptions(i.options).addJSON(i.nested)\n                    } catch (t) {\n                        h(t)\n                    }\n                    o || l || h(null, u)\n                }\n                function a(n, r) {\n                    if (!~u.files.indexOf(n))\n                        if (u.files.push(n),\n                        n in d)\n                            o ? c(n, d[n]) : (++l,\n                            setTimeout(function() {\n                                --l,\n                                c(n, d[n])\n                            }));\n                        else if (o) {\n                            var t;\n                            try {\n                                t = b.fs.readFileSync(n).toString(\"utf8\")\n                            } catch (t) {\n                                return void (r || h(t))\n                            }\n                            c(n, t)\n                        } else\n                            ++l,\n                            u.fetch(n, function(t, i) {\n                                --l,\n                                e && (t ? r ? l || h(null, u) : h(t) : c(n, i))\n                            })\n                }\n                var l = 0;\n                b.isString(i) && (i = [i]);\n                for (var n, r = 0; r < i.length; ++r)\n                    (n = u.resolvePath(\"\", i[r])) && a(n);\n                return o ? u : (l || h(null, u),\n                g)\n            }\n            ,\n            h.prototype.loadSync = function(t, i) {\n                if (!b.isNode)\n                    throw Error(\"not supported\");\n                return this.load(t, i, p)\n            }\n            ,\n            h.prototype.resolveAll = function() {\n                if (this.deferred.length)\n                    throw Error(\"unresolvable extensions: \" + this.deferred.map(function(t) {\n                        return \"'extend \" + t.extend + \"' in \" + t.parent.fullName\n                    }).join(\", \"));\n                return r.prototype.resolveAll.call(this)\n            }\n            ;\n            var f = /^[A-Z]/;\n            function c(t, i) {\n                var n = i.parent.lookup(i.extend);\n                if (n) {\n                    var r = new s(i.fullName,i.id,i.type,i.rule,g,i.options);\n                    return (r.declaringField = i).extensionField = r,\n                    n.add(r),\n                    1\n                }\n            }\n            h.prototype.u = function(t) {\n                if (t instanceof s)\n                    t.extend === g || t.extensionField || c(0, t) || this.deferred.push(t);\n                else if (t instanceof u)\n                    f.test(t.name) && (t.parent[t.name] = t.values);\n                else if (!(t instanceof o)) {\n                    if (t instanceof e)\n                        for (var i = 0; i < this.deferred.length; )\n                            c(0, this.deferred[i]) ? this.deferred.splice(i, 1) : ++i;\n                    for (var n = 0; n < t.nestedArray.length; ++n)\n                        this.u(t.e[n]);\n                    f.test(t.name) && (t.parent[t.name] = t)\n                }\n            }\n            ,\n            h.prototype.o = function(t) {\n                var i;\n                if (t instanceof s)\n                    t.extend !== g && (t.extensionField ? (t.extensionField.parent.remove(t.extensionField),\n                    t.extensionField = null) : -1 < (i = this.deferred.indexOf(t)) && this.deferred.splice(i, 1));\n                else if (t instanceof u)\n                    f.test(t.name) && delete t.parent[t.name];\n                else if (t instanceof r) {\n                    for (var n = 0; n < t.nestedArray.length; ++n)\n                        this.o(t.e[n]);\n                    f.test(t.name) && delete t.parent[t.name]\n                }\n            }\n            ,\n            h.r = function(t, i, n) {\n                e = t,\n                v = i,\n                d = n\n            }\n        }\n        , {\n            14: 14,\n            15: 15,\n            21: 21,\n            23: 23,\n            33: 33\n        }],\n        27: [function(t, i, n) {\n            i.exports = {}\n        }\n        , {}],\n        28: [function(t, i, n) {\n            n.Service = t(29)\n        }\n        , {\n            29: 29\n        }],\n        29: [function(t, i, n) {\n            i.exports = r;\n            var o = t(35);\n            function r(t, i, n) {\n                if (\"function\" != typeof t)\n                    throw TypeError(\"rpcImpl must be a function\");\n                o.EventEmitter.call(this),\n                this.rpcImpl = t,\n                this.requestDelimited = !!i,\n                this.responseDelimited = !!n\n            }\n            ((r.prototype = Object.create(o.EventEmitter.prototype)).constructor = r).prototype.rpcCall = function t(n, i, r, e, s) {\n                if (!e)\n                    throw TypeError(\"request must be specified\");\n                var u = this;\n                if (!s)\n                    return o.asPromise(t, u, n, i, r, e);\n                if (!u.rpcImpl)\n                    return setTimeout(function() {\n                        s(Error(\"already ended\"))\n                    }, 0),\n                    g;\n                try {\n                    return u.rpcImpl(n, i[u.requestDelimited ? \"encodeDelimited\" : \"encode\"](e).finish(), function(t, i) {\n                        if (t)\n                            return u.emit(\"error\", t, n),\n                            s(t);\n                        if (null === i)\n                            return u.end(!0),\n                            g;\n                        if (!(i instanceof r))\n                            try {\n                                i = r[u.responseDelimited ? \"decodeDelimited\" : \"decode\"](i)\n                            } catch (t) {\n                                return u.emit(\"error\", t, n),\n                                s(t)\n                            }\n                        return u.emit(\"data\", i, n),\n                        s(null, i)\n                    })\n                } catch (t) {\n                    return u.emit(\"error\", t, n),\n                    setTimeout(function() {\n                        s(t)\n                    }, 0),\n                    g\n                }\n            }\n            ,\n            r.prototype.end = function(t) {\n                return this.rpcImpl && (t || this.rpcImpl(null, null, null),\n                this.rpcImpl = null,\n                this.emit(\"end\").off()),\n                this\n            }\n        }\n        , {\n            35: 35\n        }],\n        30: [function(t, i, n) {\n            i.exports = u;\n            var r = t(21);\n            ((u.prototype = Object.create(r.prototype)).constructor = u).className = \"Service\";\n            var s = t(20)\n              , o = t(33)\n              , h = t(28);\n            function u(t, i) {\n                r.call(this, t, i),\n                this.methods = {},\n                this.f = null\n            }\n            function e(t) {\n                return t.f = null,\n                t\n            }\n            u.fromJSON = function(t, i) {\n                var n = new u(t,i.options);\n                if (i.methods)\n                    for (var r = Object.keys(i.methods), e = 0; e < r.length; ++e)\n                        n.add(s.fromJSON(r[e], i.methods[r[e]]));\n                return i.nested && n.addJSON(i.nested),\n                n.comment = i.comment,\n                n\n            }\n            ,\n            u.prototype.toJSON = function(t) {\n                var i = r.prototype.toJSON.call(this, t)\n                  , n = !!t && !!t.keepComments;\n                return o.toObject([\"options\", i && i.options || g, \"methods\", r.arrayToJSON(this.methodsArray, t) || {}, \"nested\", i && i.nested || g, \"comment\", n ? this.comment : g])\n            }\n            ,\n            Object.defineProperty(u.prototype, \"methodsArray\", {\n                get: function() {\n                    return this.f || (this.f = o.toArray(this.methods))\n                }\n            }),\n            u.prototype.get = function(t) {\n                return this.methods[t] || r.prototype.get.call(this, t)\n            }\n            ,\n            u.prototype.resolveAll = function() {\n                for (var t = this.methodsArray, i = 0; i < t.length; ++i)\n                    t[i].resolve();\n                return r.prototype.resolve.call(this)\n            }\n            ,\n            u.prototype.add = function(t) {\n                if (this.get(t.name))\n                    throw Error(\"duplicate name '\" + t.name + \"' in \" + this);\n                return t instanceof s ? e((this.methods[t.name] = t).parent = this) : r.prototype.add.call(this, t)\n            }\n            ,\n            u.prototype.remove = function(t) {\n                if (t instanceof s) {\n                    if (this.methods[t.name] !== t)\n                        throw Error(t + \" is not a member of \" + this);\n                    return delete this.methods[t.name],\n                    t.parent = null,\n                    e(this)\n                }\n                return r.prototype.remove.call(this, t)\n            }\n            ,\n            u.prototype.create = function(t, i, n) {\n                for (var r, e = new h.Service(t,i,n), s = 0; s < this.methodsArray.length; ++s) {\n                    var u = o.lcFirst((r = this.f[s]).resolve().name).replace(/[^$\\w_]/g, \"\");\n                    e[u] = o.codegen([\"r\", \"c\"], o.isReserved(u) ? u + \"_\" : u)(\"return this.rpcCall(m,q,s,r,c)\")({\n                        m: r,\n                        q: r.resolvedRequestType.ctor,\n                        s: r.resolvedResponseType.ctor\n                    })\n                }\n                return e\n            }\n        }\n        , {\n            20: 20,\n            21: 21,\n            28: 28,\n            33: 33\n        }],\n        31: [function(t, i, n) {\n            i.exports = w;\n            var u = t(21);\n            ((w.prototype = Object.create(u.prototype)).constructor = w).className = \"Type\";\n            var o = t(14)\n              , h = t(23)\n              , f = t(15)\n              , c = t(18)\n              , a = t(30)\n              , e = t(19)\n              , s = t(24)\n              , l = t(38)\n              , v = t(33)\n              , d = t(13)\n              , b = t(12)\n              , p = t(36)\n              , y = t(11)\n              , m = t(37);\n            function w(t, i) {\n                u.call(this, t, i),\n                this.fields = {},\n                this.oneofs = g,\n                this.extensions = g,\n                this.reserved = g,\n                this.group = g,\n                this.c = null,\n                this.i = null,\n                this.a = null,\n                this.l = null\n            }\n            function r(t) {\n                return t.c = t.i = t.a = null,\n                delete t.encode,\n                delete t.decode,\n                delete t.verify,\n                t\n            }\n            Object.defineProperties(w.prototype, {\n                fieldsById: {\n                    get: function() {\n                        if (this.c)\n                            return this.c;\n                        this.c = {};\n                        for (var t = Object.keys(this.fields), i = 0; i < t.length; ++i) {\n                            var n = this.fields[t[i]]\n                              , r = n.id;\n                            if (this.c[r])\n                                throw Error(\"duplicate id \" + r + \" in \" + this);\n                            this.c[r] = n\n                        }\n                        return this.c\n                    }\n                },\n                fieldsArray: {\n                    get: function() {\n                        return this.i || (this.i = v.toArray(this.fields))\n                    }\n                },\n                oneofsArray: {\n                    get: function() {\n                        return this.a || (this.a = v.toArray(this.oneofs))\n                    }\n                },\n                ctor: {\n                    get: function() {\n                        return this.l || (this.ctor = w.generateConstructor(this)())\n                    },\n                    set: function(t) {\n                        var i = t.prototype;\n                        i instanceof e || ((t.prototype = new e).constructor = t,\n                        v.merge(t.prototype, i)),\n                        t.$type = t.prototype.$type = this,\n                        v.merge(t, e, !0),\n                        this.l = t;\n                        for (var n = 0; n < this.fieldsArray.length; ++n)\n                            this.i[n].resolve();\n                        for (var r = {}, n = 0; n < this.oneofsArray.length; ++n)\n                            r[this.a[n].resolve().name] = {\n                                get: v.oneOfGetter(this.a[n].oneof),\n                                set: v.oneOfSetter(this.a[n].oneof)\n                            };\n                        n && Object.defineProperties(t.prototype, r)\n                    }\n                }\n            }),\n            w.generateConstructor = function(t) {\n                for (var i, n = v.codegen([\"p\"], t.name), r = 0; r < t.fieldsArray.length; ++r)\n                    (i = t.i[r]).map ? n(\"this%s={}\", v.safeProp(i.name)) : i.repeated && n(\"this%s=[]\", v.safeProp(i.name));\n                return n(\"if(p)for(var ks=Object.keys(p),i=0;i<ks.length;++i)if(p[ks[i]]!=null)\")(\"this[ks[i]]=p[ks[i]]\")\n            }\n            ,\n            w.fromJSON = function(t, i) {\n                var n = new w(t,i.options);\n                n.extensions = i.extensions,\n                n.reserved = i.reserved;\n                for (var r = Object.keys(i.fields), e = 0; e < r.length; ++e)\n                    n.add((void 0 !== i.fields[r[e]].keyType ? c : f).fromJSON(r[e], i.fields[r[e]]));\n                if (i.oneofs)\n                    for (r = Object.keys(i.oneofs),\n                    e = 0; e < r.length; ++e)\n                        n.add(h.fromJSON(r[e], i.oneofs[r[e]]));\n                if (i.nested)\n                    for (r = Object.keys(i.nested),\n                    e = 0; e < r.length; ++e) {\n                        var s = i.nested[r[e]];\n                        n.add((s.id !== g ? f : s.fields !== g ? w : s.values !== g ? o : s.methods !== g ? a : u).fromJSON(r[e], s))\n                    }\n                return i.extensions && i.extensions.length && (n.extensions = i.extensions),\n                i.reserved && i.reserved.length && (n.reserved = i.reserved),\n                i.group && (n.group = !0),\n                i.comment && (n.comment = i.comment),\n                n\n            }\n            ,\n            w.prototype.toJSON = function(t) {\n                var i = u.prototype.toJSON.call(this, t)\n                  , n = !!t && !!t.keepComments;\n                return v.toObject([\"options\", i && i.options || g, \"oneofs\", u.arrayToJSON(this.oneofsArray, t), \"fields\", u.arrayToJSON(this.fieldsArray.filter(function(t) {\n                    return !t.declaringField\n                }), t) || {}, \"extensions\", this.extensions && this.extensions.length ? this.extensions : g, \"reserved\", this.reserved && this.reserved.length ? this.reserved : g, \"group\", this.group || g, \"nested\", i && i.nested || g, \"comment\", n ? this.comment : g])\n            }\n            ,\n            w.prototype.resolveAll = function() {\n                for (var t = this.fieldsArray, i = 0; i < t.length; )\n                    t[i++].resolve();\n                for (var n = this.oneofsArray, i = 0; i < n.length; )\n                    n[i++].resolve();\n                return u.prototype.resolveAll.call(this)\n            }\n            ,\n            w.prototype.get = function(t) {\n                return this.fields[t] || this.oneofs && this.oneofs[t] || this.nested && this.nested[t] || null\n            }\n            ,\n            w.prototype.add = function(t) {\n                if (this.get(t.name))\n                    throw Error(\"duplicate name '\" + t.name + \"' in \" + this);\n                if (t instanceof f && t.extend === g) {\n                    if ((this.c || this.fieldsById)[t.id])\n                        throw Error(\"duplicate id \" + t.id + \" in \" + this);\n                    if (this.isReservedId(t.id))\n                        throw Error(\"id \" + t.id + \" is reserved in \" + this);\n                    if (this.isReservedName(t.name))\n                        throw Error(\"name '\" + t.name + \"' is reserved in \" + this);\n                    return t.parent && t.parent.remove(t),\n                    (this.fields[t.name] = t).message = this,\n                    t.onAdd(this),\n                    r(this)\n                }\n                return t instanceof h ? (this.oneofs || (this.oneofs = {}),\n                (this.oneofs[t.name] = t).onAdd(this),\n                r(this)) : u.prototype.add.call(this, t)\n            }\n            ,\n            w.prototype.remove = function(t) {\n                if (t instanceof f && t.extend === g) {\n                    if (!this.fields || this.fields[t.name] !== t)\n                        throw Error(t + \" is not a member of \" + this);\n                    return delete this.fields[t.name],\n                    t.parent = null,\n                    t.onRemove(this),\n                    r(this)\n                }\n                if (t instanceof h) {\n                    if (!this.oneofs || this.oneofs[t.name] !== t)\n                        throw Error(t + \" is not a member of \" + this);\n                    return delete this.oneofs[t.name],\n                    t.parent = null,\n                    t.onRemove(this),\n                    r(this)\n                }\n                return u.prototype.remove.call(this, t)\n            }\n            ,\n            w.prototype.isReservedId = function(t) {\n                return u.isReservedId(this.reserved, t)\n            }\n            ,\n            w.prototype.isReservedName = function(t) {\n                return u.isReservedName(this.reserved, t)\n            }\n            ,\n            w.prototype.create = function(t) {\n                return new this.ctor(t)\n            }\n            ,\n            w.prototype.setup = function() {\n                for (var t = this.fullName, i = [], n = 0; n < this.fieldsArray.length; ++n)\n                    i.push(this.i[n].resolve().resolvedType);\n                this.encode = d(this)({\n                    Writer: l,\n                    types: i,\n                    util: v\n                }),\n                this.decode = b(this)({\n                    Reader: s,\n                    types: i,\n                    util: v\n                }),\n                this.verify = p(this)({\n                    types: i,\n                    util: v\n                }),\n                this.fromObject = y.fromObject(this)({\n                    types: i,\n                    util: v\n                }),\n                this.toObject = y.toObject(this)({\n                    types: i,\n                    util: v\n                });\n                var r = m[t];\n                return r && ((t = Object.create(this)).fromObject = this.fromObject,\n                this.fromObject = r.fromObject.bind(t),\n                t.toObject = this.toObject,\n                this.toObject = r.toObject.bind(t)),\n                this\n            }\n            ,\n            w.prototype.encode = function(t, i) {\n                return this.setup().encode(t, i)\n            }\n            ,\n            w.prototype.encodeDelimited = function(t, i) {\n                return this.encode(t, i && i.len ? i.fork() : i).ldelim()\n            }\n            ,\n            w.prototype.decode = function(t, i) {\n                return this.setup().decode(t, i)\n            }\n            ,\n            w.prototype.decodeDelimited = function(t) {\n                return t instanceof s || (t = s.create(t)),\n                this.decode(t, t.uint32())\n            }\n            ,\n            w.prototype.verify = function(t) {\n                return this.setup().verify(t)\n            }\n            ,\n            w.prototype.fromObject = function(t) {\n                return this.setup().fromObject(t)\n            }\n            ,\n            w.prototype.toObject = function(t, i) {\n                return this.setup().toObject(t, i)\n            }\n            ,\n            w.d = function(i) {\n                return function(t) {\n                    v.decorateType(t, i)\n                }\n            }\n        }\n        , {\n            11: 11,\n            12: 12,\n            13: 13,\n            14: 14,\n            15: 15,\n            18: 18,\n            19: 19,\n            21: 21,\n            23: 23,\n            24: 24,\n            30: 30,\n            33: 33,\n            36: 36,\n            37: 37,\n            38: 38\n        }],\n        32: [function(t, i, n) {\n            var n = n\n              , t = t(33)\n              , e = [\"double\", \"float\", \"int32\", \"uint32\", \"sint32\", \"fixed32\", \"sfixed32\", \"int64\", \"uint64\", \"sint64\", \"fixed64\", \"sfixed64\", \"bool\", \"string\", \"bytes\"];\n            function r(t, i) {\n                var n = 0\n                  , r = {};\n                for (i |= 0; n < t.length; )\n                    r[e[n + i]] = t[n++];\n                return r\n            }\n            n.basic = r([1, 5, 0, 0, 0, 5, 5, 0, 0, 0, 1, 1, 0, 2, 2]),\n            n.defaults = r([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, !1, \"\", t.emptyArray, null]),\n            n.long = r([0, 0, 0, 1, 1], 7),\n            n.mapKey = r([0, 0, 0, 5, 5, 0, 0, 0, 1, 1, 0, 2], 2),\n            n.packed = r([1, 5, 0, 0, 0, 5, 5, 0, 0, 0, 1, 1, 0])\n        }\n        , {\n            33: 33\n        }],\n        33: [function(n, t, i) {\n            var r, e, s = t.exports = n(35), u = n(27);\n            s.codegen = n(3),\n            s.fetch = n(5),\n            s.path = n(8),\n            s.fs = s.inquire(\"fs\"),\n            s.toArray = function(t) {\n                if (t) {\n                    for (var i = Object.keys(t), n = Array(i.length), r = 0; r < i.length; )\n                        n[r] = t[i[r++]];\n                    return n\n                }\n                return []\n            }\n            ,\n            s.toObject = function(t) {\n                for (var i = {}, n = 0; n < t.length; ) {\n                    var r = t[n++]\n                      , e = t[n++];\n                    e !== g && (i[r] = e)\n                }\n                return i\n            }\n            ;\n            var o = /\\\\/g\n              , h = /\"/g;\n            s.isReserved = function(t) {\n                return /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/.test(t)\n            }\n            ,\n            s.safeProp = function(t) {\n                return !/^[$\\w_]+$/.test(t) || s.isReserved(t) ? '[\"' + t.replace(o, \"\\\\\\\\\").replace(h, '\\\\\"') + '\"]' : \".\" + t\n            }\n            ,\n            s.ucFirst = function(t) {\n                return (t[0] || \"\").toUpperCase() + t.substring(1)\n            }\n            ;\n            var f = /_([a-z])/g;\n            s.camelCase = function(t) {\n                return t.substring(0, 1) + t.substring(1).replace(f, function(t, i) {\n                    return i.toUpperCase()\n                })\n            }\n            ,\n            s.compareFieldsById = function(t, i) {\n                return t.id - i.id\n            }\n            ,\n            s.decorateType = function(t, i) {\n                if (t.$type)\n                    return i && t.$type.name !== i && (s.decorateRoot.remove(t.$type),\n                    t.$type.name = i,\n                    s.decorateRoot.add(t.$type)),\n                    t.$type;\n                i = new (r = r || n(31))(i || t.name);\n                return s.decorateRoot.add(i),\n                i.ctor = t,\n                Object.defineProperty(t, \"$type\", {\n                    value: i,\n                    enumerable: !1\n                }),\n                Object.defineProperty(t.prototype, \"$type\", {\n                    value: i,\n                    enumerable: !1\n                }),\n                i\n            }\n            ;\n            var c = 0;\n            s.decorateEnum = function(t) {\n                if (t.$type)\n                    return t.$type;\n                var i = new (e = e || n(14))(\"Enum\" + c++,t);\n                return s.decorateRoot.add(i),\n                Object.defineProperty(t, \"$type\", {\n                    value: i,\n                    enumerable: !1\n                }),\n                i\n            }\n            ,\n            s.setProperty = function(t, i, n) {\n                if (\"object\" != typeof t)\n                    throw TypeError(\"dst must be an object\");\n                if (!i)\n                    throw TypeError(\"path must be specified\");\n                return function t(i, n, r) {\n                    var e = n.shift();\n                    return 0 < n.length ? i[e] = t(i[e] || {}, n, r) : ((n = i[e]) && (r = [].concat(n).concat(r)),\n                    i[e] = r),\n                    i\n                }(t, i = i.split(\".\"), n)\n            }\n            ,\n            Object.defineProperty(s, \"decorateRoot\", {\n                get: function() {\n                    return u.decorated || (u.decorated = new (n(26)))\n                }\n            })\n        }\n        , {\n            14: 14,\n            26: 26,\n            27: 27,\n            3: 3,\n            31: 31,\n            35: 35,\n            5: 5,\n            8: 8\n        }],\n        34: [function(t, i, n) {\n            i.exports = e;\n            var r = t(35);\n            function e(t, i) {\n                this.lo = t >>> 0,\n                this.hi = i >>> 0\n            }\n            var s = e.zero = new e(0,0);\n            s.toNumber = function() {\n                return 0\n            }\n            ,\n            s.zzEncode = s.zzDecode = function() {\n                return this\n            }\n            ,\n            s.length = function() {\n                return 1\n            }\n            ;\n            e.zeroHash = \"\\0\\0\\0\\0\\0\\0\\0\\0\";\n            e.fromNumber = function(t) {\n                if (0 === t)\n                    return s;\n                var i = t < 0\n                  , n = (t = i ? -t : t) >>> 0\n                  , t = (t - n) / 4294967296 >>> 0;\n                return i && (t = ~t >>> 0,\n                n = ~n >>> 0,\n                4294967295 < ++n && (n = 0,\n                4294967295 < ++t && (t = 0))),\n                new e(n,t)\n            }\n            ,\n            e.from = function(t) {\n                if (\"number\" == typeof t)\n                    return e.fromNumber(t);\n                if (r.isString(t)) {\n                    if (!r.Long)\n                        return e.fromNumber(parseInt(t, 10));\n                    t = r.Long.fromString(t)\n                }\n                return t.low || t.high ? new e(t.low >>> 0,t.high >>> 0) : s\n            }\n            ,\n            e.prototype.toNumber = function(t) {\n                if (!t && this.hi >>> 31) {\n                    var i = 1 + ~this.lo >>> 0\n                      , t = ~this.hi >>> 0;\n                    return -(i + 4294967296 * (t = !i ? t + 1 >>> 0 : t))\n                }\n                return this.lo + 4294967296 * this.hi\n            }\n            ,\n            e.prototype.toLong = function(t) {\n                return r.Long ? new r.Long(0 | this.lo,0 | this.hi,!!t) : {\n                    low: 0 | this.lo,\n                    high: 0 | this.hi,\n                    unsigned: !!t\n                }\n            }\n            ;\n            var u = String.prototype.charCodeAt;\n            e.fromHash = function(t) {\n                return \"\\0\\0\\0\\0\\0\\0\\0\\0\" === t ? s : new e((u.call(t, 0) | u.call(t, 1) << 8 | u.call(t, 2) << 16 | u.call(t, 3) << 24) >>> 0,(u.call(t, 4) | u.call(t, 5) << 8 | u.call(t, 6) << 16 | u.call(t, 7) << 24) >>> 0)\n            }\n            ,\n            e.prototype.toHash = function() {\n                return String.fromCharCode(255 & this.lo, this.lo >>> 8 & 255, this.lo >>> 16 & 255, this.lo >>> 24, 255 & this.hi, this.hi >>> 8 & 255, this.hi >>> 16 & 255, this.hi >>> 24)\n            }\n            ,\n            e.prototype.zzEncode = function() {\n                var t = this.hi >> 31;\n                return this.hi = ((this.hi << 1 | this.lo >>> 31) ^ t) >>> 0,\n                this.lo = (this.lo << 1 ^ t) >>> 0,\n                this\n            }\n            ,\n            e.prototype.zzDecode = function() {\n                var t = -(1 & this.lo);\n                return this.lo = ((this.lo >>> 1 | this.hi << 31) ^ t) >>> 0,\n                this.hi = (this.hi >>> 1 ^ t) >>> 0,\n                this\n            }\n            ,\n            e.prototype.length = function() {\n                var t = this.lo\n                  , i = (this.lo >>> 28 | this.hi << 4) >>> 0\n                  , n = this.hi >>> 24;\n                return 0 == n ? 0 == i ? t < 16384 ? t < 128 ? 1 : 2 : t < 2097152 ? 3 : 4 : i < 16384 ? i < 128 ? 5 : 6 : i < 2097152 ? 7 : 8 : n < 128 ? 9 : 10\n            }\n        }\n        , {\n            35: 35\n        }],\n        35: [function(t, i, n) {\n            var r = n;\n            function e(t, i, n) {\n                for (var r = Object.keys(i), e = 0; e < r.length; ++e)\n                    t[r[e]] !== g && n || (t[r[e]] = i[r[e]]);\n                return t\n            }\n            function s(t) {\n                function n(t, i) {\n                    if (!(this instanceof n))\n                        return new n(t,i);\n                    Object.defineProperty(this, \"message\", {\n                        get: function() {\n                            return t\n                        }\n                    }),\n                    Error.captureStackTrace ? Error.captureStackTrace(this, n) : Object.defineProperty(this, \"stack\", {\n                        value: Error().stack || \"\"\n                    }),\n                    i && e(this, i)\n                }\n                return (n.prototype = Object.create(Error.prototype)).constructor = n,\n                Object.defineProperty(n.prototype, \"name\", {\n                    get: function() {\n                        return t\n                    }\n                }),\n                n.prototype.toString = function() {\n                    return this.name + \": \" + this.message\n                }\n                ,\n                n\n            }\n            r.asPromise = t(1),\n            r.base64 = t(2),\n            r.EventEmitter = t(4),\n            r.float = t(6),\n            r.inquire = t(7),\n            r.utf8 = t(10),\n            r.pool = t(9),\n            r.LongBits = t(34),\n            r.isNode = !!(\"undefined\" != typeof global && global && global.process && global.process.versions && global.process.versions.node),\n            r.global = r.isNode && global || \"undefined\" != typeof window && window || \"undefined\" != typeof self && self || this,\n            r.emptyArray = Object.freeze ? Object.freeze([]) : [],\n            r.emptyObject = Object.freeze ? Object.freeze({}) : {},\n            r.isInteger = Number.isInteger || function(t) {\n                return \"number\" == typeof t && isFinite(t) && Math.floor(t) === t\n            }\n            ,\n            r.isString = function(t) {\n                return \"string\" == typeof t || t instanceof String\n            }\n            ,\n            r.isObject = function(t) {\n                return t && \"object\" == typeof t\n            }\n            ,\n            r.isset = r.isSet = function(t, i) {\n                var n = t[i];\n                return null != n && t.hasOwnProperty(i) && (\"object\" != typeof n || 0 < (Array.isArray(n) ? n : Object.keys(n)).length)\n            }\n            ,\n            r.Buffer = function() {\n                try {\n                    var t = r.inquire(\"buffer\").Buffer;\n                    return t.prototype.utf8Write ? t : null\n                } catch (t) {\n                    return null\n                }\n            }(),\n            r.v = null,\n            r.b = null,\n            r.newBuffer = function(t) {\n                return \"number\" == typeof t ? r.Buffer ? r.b(t) : new r.Array(t) : r.Buffer ? r.v(t) : \"undefined\" == typeof Uint8Array ? t : new Uint8Array(t)\n            }\n            ,\n            r.Array = \"undefined\" != typeof Uint8Array ? Uint8Array : Array,\n            r.Long = r.global.dcodeIO && r.global.dcodeIO.Long || r.global.Long || r.inquire(\"long\"),\n            r.key2Re = /^true|false|0|1$/,\n            r.key32Re = /^-?(?:0|[1-9][0-9]*)$/,\n            r.key64Re = /^(?:[\\\\x00-\\\\xff]{8}|-?(?:0|[1-9][0-9]*))$/,\n            r.longToHash = function(t) {\n                return t ? r.LongBits.from(t).toHash() : r.LongBits.zeroHash\n            }\n            ,\n            r.longFromHash = function(t, i) {\n                t = r.LongBits.fromHash(t);\n                return r.Long ? r.Long.fromBits(t.lo, t.hi, i) : t.toNumber(!!i)\n            }\n            ,\n            r.merge = e,\n            r.lcFirst = function(t) {\n                return (t[0] || \"\").toLowerCase() + t.substring(1)\n            }\n            ,\n            r.newError = s,\n            r.ProtocolError = s(\"ProtocolError\"),\n            r.oneOfGetter = function(t) {\n                for (var n = {}, i = 0; i < t.length; ++i)\n                    n[t[i]] = 1;\n                return function() {\n                    for (var t = Object.keys(this), i = t.length - 1; -1 < i; --i)\n                        if (1 === n[t[i]] && this[t[i]] !== g && null !== this[t[i]])\n                            return t[i]\n                }\n            }\n            ,\n            r.oneOfSetter = function(n) {\n                return function(t) {\n                    for (var i = 0; i < n.length; ++i)\n                        n[i] !== t && delete this[n[i]]\n                }\n            }\n            ,\n            r.toJSONOptions = {\n                longs: String,\n                enums: String,\n                bytes: String,\n                json: !0\n            },\n            r.r = function() {\n                var n = r.Buffer;\n                n ? (r.v = n.from !== Uint8Array.from && n.from || function(t, i) {\n                    return new n(t,i)\n                }\n                ,\n                r.b = n.allocUnsafe || function(t) {\n                    return new n(t)\n                }\n                ) : r.v = r.b = null\n            }\n        }\n        , {\n            1: 1,\n            10: 10,\n            2: 2,\n            34: 34,\n            4: 4,\n            6: 6,\n            7: 7,\n            9: 9\n        }],\n        36: [function(t, i, n) {\n            i.exports = function(t) {\n                var i = h.codegen([\"m\"], t.name + \"$verify\")('if(typeof m!==\"object\"||m===null)')(\"return%j\", \"object expected\")\n                  , n = t.oneofsArray\n                  , r = {};\n                n.length && i(\"var p={}\");\n                for (var e = 0; e < t.fieldsArray.length; ++e) {\n                    var s, u = t.i[e].resolve(), o = \"m\" + h.safeProp(u.name);\n                    u.optional && i(\"if(%s!=null&&m.hasOwnProperty(%j)){\", o, u.name),\n                    u.map ? (i(\"if(!util.isObject(%s))\", o)(\"return%j\", f(u, \"object\"))(\"var k=Object.keys(%s)\", o)(\"for(var i=0;i<k.length;++i){\"),\n                    function(t, i, n) {\n                        switch (i.keyType) {\n                        case \"int32\":\n                        case \"uint32\":\n                        case \"sint32\":\n                        case \"fixed32\":\n                        case \"sfixed32\":\n                            t(\"if(!util.key32Re.test(%s))\", n)(\"return%j\", f(i, \"integer key\"));\n                            break;\n                        case \"int64\":\n                        case \"uint64\":\n                        case \"sint64\":\n                        case \"fixed64\":\n                        case \"sfixed64\":\n                            t(\"if(!util.key64Re.test(%s))\", n)(\"return%j\", f(i, \"integer|Long key\"));\n                            break;\n                        case \"bool\":\n                            t(\"if(!util.key2Re.test(%s))\", n)(\"return%j\", f(i, \"boolean key\"))\n                        }\n                    }(i, u, \"k[i]\"),\n                    c(i, u, e, o + \"[k[i]]\")(\"}\")) : u.repeated ? (i(\"if(!Array.isArray(%s))\", o)(\"return%j\", f(u, \"array\"))(\"for(var i=0;i<%s.length;++i){\", o),\n                    c(i, u, e, o + \"[i]\")(\"}\")) : (u.partOf && (s = h.safeProp(u.partOf.name),\n                    1 === r[u.partOf.name] && i(\"if(p%s===1)\", s)(\"return%j\", u.partOf.name + \": multiple values\"),\n                    r[u.partOf.name] = 1,\n                    i(\"p%s=1\", s)),\n                    c(i, u, e, o)),\n                    u.optional && i(\"}\")\n                }\n                return i(\"return null\")\n            }\n            ;\n            var u = t(14)\n              , h = t(33);\n            function f(t, i) {\n                return t.name + \": \" + i + (t.repeated && \"array\" !== i ? \"[]\" : t.map && \"object\" !== i ? \"{k:\" + t.keyType + \"}\" : \"\") + \" expected\"\n            }\n            function c(t, i, n, r) {\n                if (i.resolvedType)\n                    if (i.resolvedType instanceof u) {\n                        t(\"switch(%s){\", r)(\"default:\")(\"return%j\", f(i, \"enum value\"));\n                        for (var e = Object.keys(i.resolvedType.values), s = 0; s < e.length; ++s)\n                            t(\"case %i:\", i.resolvedType.values[e[s]]);\n                        t(\"break\")(\"}\")\n                    } else\n                        t(\"{\")(\"var e=types[%i].verify(%s);\", n, r)(\"if(e)\")(\"return%j+e\", i.name + \".\")(\"}\");\n                else\n                    switch (i.type) {\n                    case \"int32\":\n                    case \"uint32\":\n                    case \"sint32\":\n                    case \"fixed32\":\n                    case \"sfixed32\":\n                        t(\"if(!util.isInteger(%s))\", r)(\"return%j\", f(i, \"integer\"));\n                        break;\n                    case \"int64\":\n                    case \"uint64\":\n                    case \"sint64\":\n                    case \"fixed64\":\n                    case \"sfixed64\":\n                        t(\"if(!util.isInteger(%s)&&!(%s&&util.isInteger(%s.low)&&util.isInteger(%s.high)))\", r, r, r, r)(\"return%j\", f(i, \"integer|Long\"));\n                        break;\n                    case \"float\":\n                    case \"double\":\n                        t('if(typeof %s!==\"number\")', r)(\"return%j\", f(i, \"number\"));\n                        break;\n                    case \"bool\":\n                        t('if(typeof %s!==\"boolean\")', r)(\"return%j\", f(i, \"boolean\"));\n                        break;\n                    case \"string\":\n                        t(\"if(!util.isString(%s))\", r)(\"return%j\", f(i, \"string\"));\n                        break;\n                    case \"bytes\":\n                        t('if(!(%s&&typeof %s.length===\"number\"||util.isString(%s)))', r, r, r)(\"return%j\", f(i, \"buffer\"))\n                    }\n                return t\n            }\n        }\n        , {\n            14: 14,\n            33: 33\n        }],\n        37: [function(t, i, n) {\n            var n = n\n              , s = t(19);\n            n[\".google.protobuf.Any\"] = {\n                fromObject: function(t) {\n                    if (t && t[\"@type\"]) {\n                        var i = t[\"@type\"].substring(1 + t[\"@type\"].lastIndexOf(\"/\"))\n                          , n = this.lookup(i);\n                        if (n) {\n                            i = \".\" == (t[\"@type\"][0] || \"\") ? t[\"@type\"].substr(1) : t[\"@type\"];\n                            return ~i.indexOf(\"/\") || (i = \"/\" + i),\n                            this.create({\n                                type_url: i,\n                                value: n.encode(n.fromObject(t)).finish()\n                            })\n                        }\n                    }\n                    return this.fromObject(t)\n                },\n                toObject: function(t, i) {\n                    var n, r = \"\", e = \"\";\n                    if (i && i.json && t.type_url && t.value && (e = t.type_url.substring(1 + t.type_url.lastIndexOf(\"/\")),\n                    r = t.type_url.substring(0, 1 + t.type_url.lastIndexOf(\"/\")),\n                    (n = this.lookup(e)) && (t = n.decode(t.value))),\n                    t instanceof this.ctor || !(t instanceof s))\n                        return this.toObject(t, i);\n                    i = t.$type.toObject(t, i),\n                    t = \".\" === t.$type.fullName[0] ? t.$type.fullName.substr(1) : t.$type.fullName;\n                    return i[\"@type\"] = e = (r = \"\" === r ? \"type.googleapis.com/\" : r) + t,\n                    i\n                }\n            }\n        }\n        , {\n            19: 19\n        }],\n        38: [function(t, i, n) {\n            i.exports = a;\n            var r, e = t(35), s = e.LongBits, u = e.base64, o = e.utf8;\n            function h(t, i, n) {\n                this.fn = t,\n                this.len = i,\n                this.next = g,\n                this.val = n\n            }\n            function f() {}\n            function c(t) {\n                this.head = t.head,\n                this.tail = t.tail,\n                this.len = t.len,\n                this.next = t.states\n            }\n            function a() {\n                this.len = 0,\n                this.head = new h(f,0,0),\n                this.tail = this.head,\n                this.states = null\n            }\n            function l() {\n                return e.Buffer ? function() {\n                    return (a.create = function() {\n                        return new r\n                    }\n                    )()\n                }\n                : function() {\n                    return new a\n                }\n            }\n            function v(t, i, n) {\n                i[n] = 255 & t\n            }\n            function d(t, i) {\n                this.len = t,\n                this.next = g,\n                this.val = i\n            }\n            function b(t, i, n) {\n                for (; t.hi; )\n                    i[n++] = 127 & t.lo | 128,\n                    t.lo = (t.lo >>> 7 | t.hi << 25) >>> 0,\n                    t.hi >>>= 7;\n                for (; 127 < t.lo; )\n                    i[n++] = 127 & t.lo | 128,\n                    t.lo = t.lo >>> 7;\n                i[n++] = t.lo\n            }\n            function p(t, i, n) {\n                i[n] = 255 & t,\n                i[n + 1] = t >>> 8 & 255,\n                i[n + 2] = t >>> 16 & 255,\n                i[n + 3] = t >>> 24\n            }\n            a.create = l(),\n            a.alloc = function(t) {\n                return new e.Array(t)\n            }\n            ,\n            e.Array !== Array && (a.alloc = e.pool(a.alloc, e.Array.prototype.subarray)),\n            a.prototype.p = function(t, i, n) {\n                return this.tail = this.tail.next = new h(t,i,n),\n                this.len += i,\n                this\n            }\n            ,\n            (d.prototype = Object.create(h.prototype)).fn = function(t, i, n) {\n                for (; 127 < t; )\n                    i[n++] = 127 & t | 128,\n                    t >>>= 7;\n                i[n] = t\n            }\n            ,\n            a.prototype.uint32 = function(t) {\n                return this.len += (this.tail = this.tail.next = new d((t >>>= 0) < 128 ? 1 : t < 16384 ? 2 : t < 2097152 ? 3 : t < 268435456 ? 4 : 5,t)).len,\n                this\n            }\n            ,\n            a.prototype.int32 = function(t) {\n                return t < 0 ? this.p(b, 10, s.fromNumber(t)) : this.uint32(t)\n            }\n            ,\n            a.prototype.sint32 = function(t) {\n                return this.uint32((t << 1 ^ t >> 31) >>> 0)\n            }\n            ,\n            a.prototype.int64 = a.prototype.uint64 = function(t) {\n                t = s.from(t);\n                return this.p(b, t.length(), t)\n            }\n            ,\n            a.prototype.sint64 = function(t) {\n                t = s.from(t).zzEncode();\n                return this.p(b, t.length(), t)\n            }\n            ,\n            a.prototype.bool = function(t) {\n                return this.p(v, 1, t ? 1 : 0)\n            }\n            ,\n            a.prototype.sfixed32 = a.prototype.fixed32 = function(t) {\n                return this.p(p, 4, t >>> 0)\n            }\n            ,\n            a.prototype.sfixed64 = a.prototype.fixed64 = function(t) {\n                t = s.from(t);\n                return this.p(p, 4, t.lo).p(p, 4, t.hi)\n            }\n            ,\n            a.prototype.float = function(t) {\n                return this.p(e.float.writeFloatLE, 4, t)\n            }\n            ,\n            a.prototype.double = function(t) {\n                return this.p(e.float.writeDoubleLE, 8, t)\n            }\n            ;\n            var y = e.Array.prototype.set ? function(t, i, n) {\n                i.set(t, n)\n            }\n            : function(t, i, n) {\n                for (var r = 0; r < t.length; ++r)\n                    i[n + r] = t[r]\n            }\n            ;\n            a.prototype.bytes = function(t) {\n                var i, n = t.length >>> 0;\n                return n ? (e.isString(t) && (i = a.alloc(n = u.length(t)),\n                u.decode(t, i, 0),\n                t = i),\n                this.uint32(n).p(y, n, t)) : this.p(v, 1, 0)\n            }\n            ,\n            a.prototype.string = function(t) {\n                var i = o.length(t);\n                return i ? this.uint32(i).p(o.write, i, t) : this.p(v, 1, 0)\n            }\n            ,\n            a.prototype.fork = function() {\n                return this.states = new c(this),\n                this.head = this.tail = new h(f,0,0),\n                this.len = 0,\n                this\n            }\n            ,\n            a.prototype.reset = function() {\n                return this.states ? (this.head = this.states.head,\n                this.tail = this.states.tail,\n                this.len = this.states.len,\n                this.states = this.states.next) : (this.head = this.tail = new h(f,0,0),\n                this.len = 0),\n                this\n            }\n            ,\n            a.prototype.ldelim = function() {\n                var t = this.head\n                  , i = this.tail\n                  , n = this.len;\n                return this.reset().uint32(n),\n                n && (this.tail.next = t.next,\n                this.tail = i,\n                this.len += n),\n                this\n            }\n            ,\n            a.prototype.finish = function() {\n                for (var t = this.head.next, i = this.constructor.alloc(this.len), n = 0; t; )\n                    t.fn(t.val, i, n),\n                    n += t.len,\n                    t = t.next;\n                return i\n            }\n            ,\n            a.r = function(t) {\n                r = t,\n                a.create = l(),\n                r.r()\n            }\n        }\n        , {\n            35: 35\n        }],\n        39: [function(t, i, n) {\n            i.exports = s;\n            var r = t(38);\n            (s.prototype = Object.create(r.prototype)).constructor = s;\n            var e = t(35);\n            function s() {\n                r.call(this)\n            }\n            function u(t, i, n) {\n                t.length < 40 ? e.utf8.write(t, i, n) : i.utf8Write ? i.utf8Write(t, n) : i.write(t, n)\n            }\n            s.r = function() {\n                s.alloc = e.b,\n                s.writeBytesBuffer = e.Buffer && e.Buffer.prototype instanceof Uint8Array && \"set\" === e.Buffer.prototype.set.name ? function(t, i, n) {\n                    i.set(t, n)\n                }\n                : function(t, i, n) {\n                    if (t.copy)\n                        t.copy(i, n, 0, t.length);\n                    else\n                        for (var r = 0; r < t.length; )\n                            i[n++] = t[r++]\n                }\n            }\n            ,\n            s.prototype.bytes = function(t) {\n                var i = (t = e.isString(t) ? e.v(t, \"base64\") : t).length >>> 0;\n                return this.uint32(i),\n                i && this.p(s.writeBytesBuffer, i, t),\n                this\n            }\n            ,\n            s.prototype.string = function(t) {\n                var i = e.Buffer.byteLength(t);\n                return this.uint32(i),\n                i && this.p(u, i, t),\n                this\n            }\n            ,\n            s.r()\n        }\n        , {\n            35: 35,\n            38: 38\n        }]\n    },\n    e = {},\n    t = [16],\n    i = function t(i) {\n        var n = e[i];\n        return n || r[i][0].call(n = e[i] = {\n            exports: {}\n        }, t, n, n.exports),\n        n.exports\n    }(t[0]),\n    i.util.global.protobuf = i,\n    \"function\" == typeof define && define.amd && define([\"long\"], function(t) {\n        return t && t.isLong && (i.util.Long = t,\n        i.configure()),\n        i\n    }),\n    \"object\" == typeof module && module && module.exports && (module.exports = i)\n    aaa =i;\n}();\n//# sourceMappingURL=protobuf.min.js.map\n\n\n\nfunction PolicyInfoByTypeIdParam_encode(m){\n  w= aaa.Writer.create()\n  if(m.policyType!=null&&Object.hasOwnProperty.call(m,\"policyType\"))\n  w.uint32(10).string(m.policyType)\n  if(m.centralId!=null&&Object.hasOwnProperty.call(m,\"centralId\"))\n  w.uint32(18).string(m.centralId)\n  if(m.province!=null&&Object.hasOwnProperty.call(m,\"province\"))\n  w.uint32(26).string(m.province)\n  if(m.city!=null&&Object.hasOwnProperty.call(m,\"city\"))\n  w.uint32(34).string(m.city)\n  if(m.downtown!=null&&Object.hasOwnProperty.call(m,\"downtown\"))\n  w.uint32(42).string(m.downtown)\n  if(m.garden!=null&&Object.hasOwnProperty.call(m,\"garden\"))\n  w.uint32(50).string(m.garden)\n  if(m.sort!=null&&Object.hasOwnProperty.call(m,\"sort\"))\n  w.uint32(56).uint32(m.sort)\n  if(m.pageNum!=null&&Object.hasOwnProperty.call(m,\"pageNum\"))\n  w.uint32(64).uint32(m.pageNum)\n  if(m.pageSize!=null&&Object.hasOwnProperty.call(m,\"pageSize\"))\n  w.uint32(72).uint32(m.pageSize)\n  return w\n}\n\n\n\ndata = {\n    centralId: \"\",\n    city: \"\",\n    downtown: \"\",\n    garden: \"\",\n    pageNum: 1,\n    pageSize: 7,\n    policyType: \"6\",\n    province: \"\",\n    sort: 0\n}\n\n\nbody = PolicyInfoByTypeIdParam_encode(data).finish().slice()\n\nlet e={ \"url\":\"http://www.spolicy.com/info_api/policyType/showPolicyType\",\n        \"method\":\"POST\",\n        \"data\" : body};\nvar h = new XMLHttpRequest;h.open(e.method, e.url, true);\nh.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");  \nh.setRequestHeader(\"content-type\",\"application/octet-stream\");\n        h.onreadystatechange=function(){\n            if (h.status===200){\n              console.log(h)\n            }\n        }\nh.send(e.data);\n"
  },
  {
    "path": "第三章：Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例二.js",
    "content": " function reqId() {\n        var t = {};\n        var e = undefined;\n        var n = undefined;\n        var r = [123, 48, 115, 203, 231, 115];\n        var o = 9996;\n        var d = 0;\n        var h = Date.now();\n\n        var i = e && n || 0\n          , b = e || []\n          , f = (t = t || {}).node || r\n          , v = void 0 !== t.clockseq ? t.clockseq : o;\n        if (null == f || null == v) {\n            var m = l();\n            null == f && (f = r = [1 | m[0], m[1], m[2], m[3], m[4], m[5]]),\n            null == v && (v = o = 16383 & (m[6] << 8 | m[7]))\n        }\n        var y = void 0 !== t.msecs ? t.msecs : (new Date).getTime()\n          , w = void 0 !== t.nsecs ? t.nsecs : d + 1\n          , dt = y - h + (w - d) / 1e4;\n\n        if (dt < 0 && void 0 === t.clockseq && (v = v + 1 & 16383),\n        (dt < 0 || y > h) && void 0 === t.nsecs && (w = 0),\n        w >= 1e4)\n            throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");\n        h = y,\n        d = w,\n        o = v;\n        var x = (1e4 * (268435455 & (y += 122192928e5)) + w) % 4294967296;\n        b[i++] = x >>> 24 & 255,\n        b[i++] = x >>> 16 & 255,\n        b[i++] = x >>> 8 & 255,\n        b[i++] = 255 & x;\n        var _ = y / 4294967296 * 1e4 & 268435455;\n        b[i++] = _ >>> 8 & 255,\n        b[i++] = 255 & _,\n        b[i++] = _ >>> 24 & 15 | 16,\n        b[i++] = _ >>> 16 & 255,\n        b[i++] = v >>> 8 | 128,\n        b[i++] = 255 & v;\n        for (var A = 0; A < 6; ++A)\n            b[i + A] = f[A];\n        return e || c(b)\n}\n\n\nfunction c(t, e) {\n        var n =[\"00\",\"01\",\"02\",\"03\",\"04\",\"05\",\"06\",\"07\",\"08\",\"09\",\"0a\",\"0b\",\"0c\",\"0d\",\"0e\",\"0f\",\"10\",\"11\",\"12\",\"13\",\"14\",\"15\",\"16\",\"17\",\"18\",\"19\",\"1a\",\"1b\",\"1c\",\"1d\",\"1e\",\"1f\",\"20\",\"21\",\"22\",\"23\",\"24\",\"25\",\"26\",\"27\",\"28\",\"29\",\"2a\",\"2b\",\"2c\",\"2d\",\"2e\",\"2f\",\"30\",\"31\",\"32\",\"33\",\"34\",\"35\",\"36\",\"37\",\"38\",\"39\",\"3a\",\"3b\",\"3c\",\"3d\",\"3e\",\"3f\",\"40\",\"41\",\"42\",\"43\",\"44\",\"45\",\"46\",\"47\",\"48\",\"49\",\"4a\",\"4b\",\"4c\",\"4d\",\"4e\",\"4f\",\"50\",\"51\",\"52\",\"53\",\"54\",\"55\",\"56\",\"57\",\"58\",\"59\",\"5a\",\"5b\",\"5c\",\"5d\",\"5e\",\"5f\",\"60\",\"61\",\"62\",\"63\",\"64\",\"65\",\"66\",\"67\",\"68\",\"69\",\"6a\",\"6b\",\"6c\",\"6d\",\"6e\",\"6f\",\"70\",\"71\",\"72\",\"73\",\"74\",\"75\",\"76\",\"77\",\"78\",\"79\",\"7a\",\"7b\",\"7c\",\"7d\",\"7e\",\"7f\",\"80\",\"81\",\"82\",\"83\",\"84\",\"85\",\"86\",\"87\",\"88\",\"89\",\"8a\",\"8b\",\"8c\",\"8d\",\"8e\",\"8f\",\"90\",\"91\",\"92\",\"93\",\"94\",\"95\",\"96\",\"97\",\"98\",\"99\",\"9a\",\"9b\",\"9c\",\"9d\",\"9e\",\"9f\",\"a0\",\"a1\",\"a2\",\"a3\",\"a4\",\"a5\",\"a6\",\"a7\",\"a8\",\"a9\",\"aa\",\"ab\",\"ac\",\"ad\",\"ae\",\"af\",\"b0\",\"b1\",\"b2\",\"b3\",\"b4\",\"b5\",\"b6\",\"b7\",\"b8\",\"b9\",\"ba\",\"bb\",\"bc\",\"bd\",\"be\",\"bf\",\"c0\",\"c1\",\"c2\",\"c3\",\"c4\",\"c5\",\"c6\",\"c7\",\"c8\",\"c9\",\"ca\",\"cb\",\"cc\",\"cd\",\"ce\",\"cf\",\"d0\",\"d1\",\"d2\",\"d3\",\"d4\",\"d5\",\"d6\",\"d7\",\"d8\",\"d9\",\"da\",\"db\",\"dc\",\"dd\",\"de\",\"df\",\"e0\",\"e1\",\"e2\",\"e3\",\"e4\",\"e5\",\"e6\",\"e7\",\"e8\",\"e9\",\"ea\",\"eb\",\"ec\",\"ed\",\"ee\",\"ef\",\"f0\",\"f1\",\"f2\",\"f3\",\"f4\",\"f5\",\"f6\",\"f7\",\"f8\",\"f9\",\"fa\",\"fb\",\"fc\",\"fd\",\"fe\",\"ff\"];\n        var i = e || 0\n          , r = n;\n        return [r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], \"-\", r[t[i++]], r[t[i++]], \"-\", r[t[i++]], r[t[i++]], \"-\", r[t[i++]], r[t[i++]], \"-\", r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]]].join(\"\")\n    }\n\n\nconsole.log(reqId())\n"
  },
  {
    "path": "第三章：Web Js逆向/3.4 常见的压缩和混淆/3.4.7 lsb隐写/lsb.py",
    "content": "from PIL import Image\n\ndef plus(str):\n    # 返回指定长度的字符串，原字符串右对齐，前面填充0。\n    return str.zfill(8)\n\ndef get_key(strr):\n    str_ = \"\"\n    for i in range(len(strr)):\n        # 将要隐藏的文件内容转换为二进制并拼接起来\n        str_ = str_ + plus(bin(ord(strr[i])).replace('0b', ''))\n    return str_\n\ndef mod(x, y):\n    return x % y\n\ndef func(old_img, str2, new_img):\n    # str1为载体图片路径，str2为隐写文件，str3为加密图片保存的路径\n    im = Image.open(old_img)\n    # 获取图片的宽和高\n    width = im.size[0]\n    height = im.size[1]\n    count = 0\n    key = get_key(str2)\n    keylen = len(key)\n    for h in range(0, height):\n        for w in range(0, width):\n            pixel = im.getpixel((w, h))\n            a = pixel[0]\n            b = pixel[1]\n            c = pixel[2]\n            if count == keylen:\n                break\n            # 信息隐藏：分别将每个像素点的RGB值余2，去掉最低位的值\n            # 再从需要隐藏的信息中取出一位，转换为整型，两值相加\n            a = a - mod(a, 2) + int(key[count])\n            count += 1\n            if count == keylen:\n                im.putpixel((w, h), (a, b, c))\n                break\n            b = b - mod(b, 2) + int(key[count])\n            count += 1\n            if count == keylen:\n                im.putpixel((w, h), (a, b, c))\n                break\n            c = c - mod(c, 2) + int(key[count])\n            count += 1\n            if count == keylen:\n                im.putpixel((w, h), (a, b, c))\n                break\n            if count % 3 == 0:\n                im.putpixel((w, h), (a, b, c))\n    im.save(new_img)\n\n# 原图\nold_img = r\"timg.jpg\"\nnew_img = r\"timg2.jpg\"\nfunc(old_img,\"Lx Is Good Man\",new_img)"
  },
  {
    "path": "第三章：Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.js",
    "content": "let password = \"lx123\";\nlet key = \"1234567890abcdef\"\n// AES加密\ncfg = {\n mode: CryptoJs.mode.ECB,\n padding: CryptoJs.pad.Pkcs7\n}\nlet encPwd = CryptoJs.AES.encrypt(password, key, cfg).toString()\n\n// AES解密\nlet key = CryptoJs.enc.Utf8.parse(\"1234567890abcdef\")\ncfg = {\n mode: CryptoJs.mode.ECB,\n padding: CryptoJs.pad.Pkcs7\n}\nencPwd = \"+4X1GzDcLdd5yb3PiZLxdw==\"\ndecPwd = CryptoJs.AES.decrypt(encPwd, key, cfg).toString(CryptoJs.enc.Utf8) // 指定解码方式\nconsole.log(decPwd)  // lx123"
  },
  {
    "path": "第三章：Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.py",
    "content": "import base64\nfrom Crypto.Cipher import AES\n\n# AES\n# 需要补位，str不是16的倍数那就补足为16的倍数\ndef add_to_16(value):\n    while len(value) % 16 != 0:\n        value += '\\0'\n    return str.encode(value)  # 返回bytes\n\n# 加密方法\ndef encrypt(key, text):\n    aes = AES.new(add_to_16(key), AES.MODE_ECB)  # 初始化加密器\n    encrypt_aes = aes.encrypt(add_to_16(text))  # 先进行aes加密\n    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')\n    return encrypted_text\n\n# 解密方法\ndef decrypt(key, text):\n    aes = AES.new(add_to_16(key), AES.MODE_ECB)  # 初始化加密器\n    base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))\n    decrypted_text = str(aes.decrypt(base64_decrypted), encoding='utf-8').replace('\\0', '')  # 执行解密密并转码返回str\n    return decrypted_text"
  },
  {
    "path": "第三章：Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.js",
    "content": "window = global;\nconst JSEncrypt = require('jsencrypt');\npublickey = '公钥';\n\n// 加密\nlet jse = new JSEncrypt();\njse.setPublicKey(publickey);\nvar encStr = jse.encrypt('username');\n\n// 解密\nprivatekey = '私钥';\njse.setPrivateKey(privatekey);\nvar Str = jse.decrypt(encStr);"
  },
  {
    "path": "第三章：Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.py",
    "content": "import base64\nimport rsa\nfrom rsa import common\n\nclass RsaUtil(object):\n    PUBLIC_KEY_PATH = 'public_key.pem'  # 公钥\n    PRIVATE_KEY_PATH = 'private_key.pem'  # 私钥\n\n    # 初始化key\n    def __init__(self,\n                 company_pub_file=PUBLIC_KEY_PATH,\n                 company_pri_file=PRIVATE_KEY_PATH):\n\n        if company_pub_file:\n            self.company_public_key = rsa.PublicKey.load_pkcs1_openssl_pem(open(company_pub_file).read())\n        if company_pri_file:\n            self.company_private_key = rsa.PrivateKey.load_pkcs1(open(company_pri_file).read())\n\n    def get_max_length(self, rsa_key, encrypt=True):\n        \"\"\"加密内容过长时 需要分段加密 换算每一段的长度.\n            :param rsa_key: 钥匙.\n            :param encrypt: 是否是加密.\n        \"\"\"\n        blocksize = common.byte_size(rsa_key.n)\n        reserve_size = 11  # 预留位为11\n        if not encrypt:  # 解密时不需要考虑预留位\n            reserve_size = 0\n        maxlength = blocksize - reserve_size\n        return maxlength\n\n    def encrypt_by_public_key(self, message):\n        \"\"\"使用公钥加密.\n            :param message: 需要加密的内容.\n            加密之后需要对接过进行base64转码\n        \"\"\"\n        encrypt_result = b''\n        max_length = self.get_max_length(self.company_public_key)\n        while message:\n            input = message[:max_length]\n            message = message[max_length:]\n            out = rsa.encrypt(input, self.company_public_key)\n            encrypt_result += out\n        encrypt_result = base64.b64encode(encrypt_result)\n        return encrypt_result\n\n    def decrypt_by_private_key(self, message):\n        \"\"\"使用私钥解密.\n            :param message: 需要加密的内容.\n            解密之后的内容直接是字符串，不需要在进行转义\n        \"\"\"\n        decrypt_result = b\"\"\n\n        max_length = self.get_max_length(self.company_private_key, False)\n        decrypt_message = base64.b64decode(message)\n        while decrypt_message:\n            input = decrypt_message[:max_length]\n            decrypt_message = decrypt_message[max_length:]\n            out = rsa.decrypt(input, self.company_private_key)\n            decrypt_result += out\n        return decrypt_result\n\n    def sign_by_private_key(self, data):\n        \"\"\"私钥签名.\n            :param data: 需要签名的内容.\n            使用SHA-1 方法进行签名（也可以使用MD5）\n            签名之后，需要转义后输出\n        \"\"\"\n        signature = rsa.sign(str(data), priv_key=self.company_private_key, hash='SHA-1')\n        return base64.b64encode(signature)\n\n    def verify_by_public_key(self, message, signature):\n        \"\"\"公钥验签.\n            :param message: 验签的内容.\n            :param signature: 对验签内容签名的值（签名之后，会进行b64encode转码，所以验签前也需转码）.\n        \"\"\"\n        signature = base64.b64decode(signature)\n        return rsa.verify(message, signature, self.company_public_key)"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.1 virustotal逆向入门案例/js3.6.1.py",
    "content": "import execjs\nimport requests\nfrom lxpy import copy_headers_dict\n\nurl = 'https://www.virustotal.com/ui/search?limit=20&relationships%5Bcomment%5D=author%2Citem&query=1'\nheaders = copy_headers_dict('''\naccept: application/json\naccept-encoding: gzip, deflate, br\naccept-ianguage: en-US,en;q=0.9,es;q=0.8\naccept-language: zh-CN,zh;q=0.9\ncontent-type: application/json\ncookie: _ga=GA1.2.747208657.1642417044; _gid=GA1.2.988701706.1642417044\nreferer: https://www.virustotal.com/\nsec-ch-ua: \" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"97\", \"Chromium\";v=\"97\"\nsec-ch-ua-mobile: ?0\nsec-ch-ua-platform: \"Windows\"\nsec-fetch-dest: empty\nsec-fetch-mode: cors\nsec-fetch-site: same-origin\nuser-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36\nx-app-version: v1x57x0\nx-tool: vt-ui-main\n''')\n\njs = '''\nfunction get_anti(){\n            const e = Date.now() / 1e3;\n             return Buffer.from((`${(()=>{\n                const e = 1e10 * (1 + Math.random() % 5e4);\n                return e < 50 ? \"-1\" : e.toFixed(0)\n            }\n            )()}-ZG9udCBiZSBldmls-${e}`)).toString('base64');\n        }\n'''\nxvt_anti = execjs.compile(js).call('get_anti')\nheaders.update({'x-vt-anti-abuse-header':xvt_anti})\n\nprint(requests.get(url, headers=headers).text)"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.2 newrank榜单逆向案例/js3.6.2.py",
    "content": "import requests\nimport execjs\n\nclass XbRank():\n    def __init__(self):\n        self.session=requests.session()\n        self.headers = {\n            'accept-language': 'zh-CN,zh;q=0.9',\n            'origin': 'https://newrank.cn',\n            'referer': 'https://newrank.cn/public/info/search.html?value=pythonlx&isBind=false',\n            'sec-ch-ua': '\" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\"',\n            'sec-ch-ua-mobile': '?0',\n            'sec-fetch-dest': 'empty',\n            'sec-fetch-mode': 'cors',\n            'sec-fetch-site': 'same-origin',\n            'cookie': 'UM_distinctid=17e67d04321599-0bb674ea32cd44-f791b31-1fa400-17e67d04322e09; CNZZDATA1253878005=868574852-1642412670-%7C1642412670',\n            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',\n            'x-requested-with': 'XMLHttpRequest',\n    }\n\n\n    def getxyz(self,path):\n        js = '''\n                 function nonce() {\n                for (var a = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\"], b = 0; b < 500; b++)\n                    for (var c = \"\", d = 0; d < 9; d++) {\n                        var e = Math.floor(16 * Math.random());\n                        c += a[e]\n                    }\n                return c\n            }\n\n        function b(a) {\n                function b(a) {\n                    return d(c(e(a)))\n                }\n                function c(a) {\n                    return g(h(f(a), 8 * a.length))\n                }\n                function d(a) {\n                    for (var b, c = p ? \"0123456789ABCDEF\" : \"0123456789abcdef\", d = \"\", e = 0; e < a.length; e++)\n                        b = a.charCodeAt(e),\n                        d += c.charAt(b >>> 4 & 15) + c.charAt(15 & b);\n                    return d\n                }\n                function e(a) {\n                    for (var b, c, d = \"\", e = -1; ++e < a.length; )\n                        b = a.charCodeAt(e),\n                        c = e + 1 < a.length ? a.charCodeAt(e + 1) : 0,\n                        55296 <= b && b <= 56319 && 56320 <= c && c <= 57343 && (b = 65536 + ((1023 & b) << 10) + (1023 & c),\n                        e++),\n                        b <= 127 ? d += String.fromCharCode(b) : b <= 2047 ? d += String.fromCharCode(192 | b >>> 6 & 31, 128 | 63 & b) : b <= 65535 ? d += String.fromCharCode(224 | b >>> 12 & 15, 128 | b >>> 6 & 63, 128 | 63 & b) : b <= 2097151 && (d += String.fromCharCode(240 | b >>> 18 & 7, 128 | b >>> 12 & 63, 128 | b >>> 6 & 63, 128 | 63 & b));\n                    return d\n                }\n                function f(a) {\n                    for (var b = Array(a.length >> 2), c = 0; c < b.length; c++)\n                        b[c] = 0;\n                    for (var c = 0; c < 8 * a.length; c += 8)\n                        b[c >> 5] |= (255 & a.charCodeAt(c / 8)) << c % 32;\n                    return b\n                }\n                function g(a) {\n                    for (var b = \"\", c = 0; c < 32 * a.length; c += 8)\n                        b += String.fromCharCode(a[c >> 5] >>> c % 32 & 255);\n                    return b\n                }\n                function h(a, b) {\n                    a[b >> 5] |= 128 << b % 32,\n                    a[14 + (b + 64 >>> 9 << 4)] = b;\n                    for (var c = 1732584193, d = -271733879, e = -1732584194, f = 271733878, g = 0; g < a.length; g += 16) {\n                        var h = c\n                          , i = d\n                          , o = e\n                          , p = f;\n                        c = j(c, d, e, f, a[g + 0], 7, -680876936),\n                        f = j(f, c, d, e, a[g + 1], 12, -389564586),\n                        e = j(e, f, c, d, a[g + 2], 17, 606105819),\n                        d = j(d, e, f, c, a[g + 3], 22, -1044525330),\n                        c = j(c, d, e, f, a[g + 4], 7, -176418897),\n                        f = j(f, c, d, e, a[g + 5], 12, 1200080426),\n                        e = j(e, f, c, d, a[g + 6], 17, -1473231341),\n                        d = j(d, e, f, c, a[g + 7], 22, -45705983),\n                        c = j(c, d, e, f, a[g + 8], 7, 1770035416),\n                        f = j(f, c, d, e, a[g + 9], 12, -1958414417),\n                        e = j(e, f, c, d, a[g + 10], 17, -42063),\n                        d = j(d, e, f, c, a[g + 11], 22, -1990404162),\n                        c = j(c, d, e, f, a[g + 12], 7, 1804603682),\n                        f = j(f, c, d, e, a[g + 13], 12, -40341101),\n                        e = j(e, f, c, d, a[g + 14], 17, -1502002290),\n                        d = j(d, e, f, c, a[g + 15], 22, 1236535329),\n                        c = k(c, d, e, f, a[g + 1], 5, -165796510),\n                        f = k(f, c, d, e, a[g + 6], 9, -1069501632),\n                        e = k(e, f, c, d, a[g + 11], 14, 643717713),\n                        d = k(d, e, f, c, a[g + 0], 20, -373897302),\n                        c = k(c, d, e, f, a[g + 5], 5, -701558691),\n                        f = k(f, c, d, e, a[g + 10], 9, 38016083),\n                        e = k(e, f, c, d, a[g + 15], 14, -660478335),\n                        d = k(d, e, f, c, a[g + 4], 20, -405537848),\n                        c = k(c, d, e, f, a[g + 9], 5, 568446438),\n                        f = k(f, c, d, e, a[g + 14], 9, -1019803690),\n                        e = k(e, f, c, d, a[g + 3], 14, -187363961),\n                        d = k(d, e, f, c, a[g + 8], 20, 1163531501),\n                        c = k(c, d, e, f, a[g + 13], 5, -1444681467),\n                        f = k(f, c, d, e, a[g + 2], 9, -51403784),\n                        e = k(e, f, c, d, a[g + 7], 14, 1735328473),\n                        d = k(d, e, f, c, a[g + 12], 20, -1926607734),\n                        c = l(c, d, e, f, a[g + 5], 4, -378558),\n                        f = l(f, c, d, e, a[g + 8], 11, -2022574463),\n                        e = l(e, f, c, d, a[g + 11], 16, 1839030562),\n                        d = l(d, e, f, c, a[g + 14], 23, -35309556),\n                        c = l(c, d, e, f, a[g + 1], 4, -1530992060),\n                        f = l(f, c, d, e, a[g + 4], 11, 1272893353),\n                        e = l(e, f, c, d, a[g + 7], 16, -155497632),\n                        d = l(d, e, f, c, a[g + 10], 23, -1094730640),\n                        c = l(c, d, e, f, a[g + 13], 4, 681279174),\n                        f = l(f, c, d, e, a[g + 0], 11, -358537222),\n                        e = l(e, f, c, d, a[g + 3], 16, -722521979),\n                        d = l(d, e, f, c, a[g + 6], 23, 76029189),\n                        c = l(c, d, e, f, a[g + 9], 4, -640364487),\n                        f = l(f, c, d, e, a[g + 12], 11, -421815835),\n                        e = l(e, f, c, d, a[g + 15], 16, 530742520),\n                        d = l(d, e, f, c, a[g + 2], 23, -995338651),\n                        c = m(c, d, e, f, a[g + 0], 6, -198630844),\n                        f = m(f, c, d, e, a[g + 7], 10, 1126891415),\n                        e = m(e, f, c, d, a[g + 14], 15, -1416354905),\n                        d = m(d, e, f, c, a[g + 5], 21, -57434055),\n                        c = m(c, d, e, f, a[g + 12], 6, 1700485571),\n                        f = m(f, c, d, e, a[g + 3], 10, -1894986606),\n                        e = m(e, f, c, d, a[g + 10], 15, -1051523),\n                        d = m(d, e, f, c, a[g + 1], 21, -2054922799),\n                        c = m(c, d, e, f, a[g + 8], 6, 1873313359),\n                        f = m(f, c, d, e, a[g + 15], 10, -30611744),\n                        e = m(e, f, c, d, a[g + 6], 15, -1560198380),\n                        d = m(d, e, f, c, a[g + 13], 21, 1309151649),\n                        c = m(c, d, e, f, a[g + 4], 6, -145523070),\n                        f = m(f, c, d, e, a[g + 11], 10, -1120210379),\n                        e = m(e, f, c, d, a[g + 2], 15, 718787259),\n                        d = m(d, e, f, c, a[g + 9], 21, -343485551),\n                        c = n(c, h),\n                        d = n(d, i),\n                        e = n(e, o),\n                        f = n(f, p)\n                    }\n                    return Array(c, d, e, f)\n                }\n                function i(a, b, c, d, e, f) {\n                    return n(o(n(n(b, a), n(d, f)), e), c)\n                }\n                function j(a, b, c, d, e, f, g) {\n                    return i(b & c | ~b & d, a, b, e, f, g)\n                }\n                function k(a, b, c, d, e, f, g) {\n                    return i(b & d | c & ~d, a, b, e, f, g)\n                }\n                function l(a, b, c, d, e, f, g) {\n                    return i(b ^ c ^ d, a, b, e, f, g)\n                }\n                function m(a, b, c, d, e, f, g) {\n                    return i(c ^ (b | ~d), a, b, e, f, g)\n                }\n                function n(a, b) {\n                    var c = (65535 & a) + (65535 & b);\n                    return (a >> 16) + (b >> 16) + (c >> 16) << 16 | 65535 & c\n                }\n                function o(a, b) {\n                    return a << b | a >>> 32 - b\n                }\n                var p = 0;\n                return b(a)\n            }\n        '''\n        ctx = execjs.compile(js)\n        nonce=ctx.eval('nonce()')\n        path = path.replace('*****',nonce)\n        xyz=ctx.eval(path)\n        return nonce,xyz\n\n\n    def getMedia(self,page=1):\n        \"\"\" 获取新榜资讯 \"\"\"\n        url = \"https://www.newrank.cn/xdnphb/index/getMedia\"\n        path='b(\"/xdnphb/index/getMedia?AppKey=joker&keyword=&pageNumber={}&pageSize=10&nonce={}\")'.format(page,'*****')\n        nonce, xyz =self.getxyz(path)\n        data = {\n            \"keyword\":\"\",\n            \"pageNumber\": str(page),\n            \"pageSize\": \"10\",\n            \"nonce\": nonce,\n            \"xyz\": xyz,\n        }\n        res=self.session.post(url=url, headers=self.headers, data=data).text\n        return res\n\n\n    def getRank1(self):\n        \"\"\" 微信-榜单 \"\"\"\n        rank_name = '百科'\n        rank_name_group = '生活'\n        date = '2022-01-17'\n        path='b(\"/xdnphb/main/v1/day/rank?AppKey=joker&end={}&rank_name={}&rank_name_group={}&start={}&nonce=*****\")'.format(date,rank_name,rank_name_group,date)\n        nonce,xyz=self.getxyz(path)\n        print(nonce,xyz)\n        getRankUrl = 'https://www.newrank.cn/xdnphb/main/v1/day/rank'\n        self.data={\n            \"end\": date,\n            \"rank_name\": rank_name,\n            \"rank_name_group\": rank_name_group,\n            \"start\": date,\n            \"nonce\": nonce,\n            \"xyz\": xyz,\n        }\n        res=self.session.post(url=getRankUrl,headers=self.headers,data=self.data).json()\n        return res\n\n\n    def getRank2(self):\n        \"\"\" 视频号-榜单 \"\"\"\n        path='b(\"/xdnphb/data/weixinuser/getMainIndexRank?\")'\n        nonce,xyz=self.getxyz(path)\n        getUrl =  f'https://www.newrank.cn/xdnphb/nr/xinshi/video/getMainIndexRank?nonce={nonce}&xyz={xyz}'\n        self.data={\"interval\":\"day\",\n                   \"rank_date\":\"2021-07-11\",\n                   \"type\":\"科技互联网\",\n                   \"start\":1,\n                   \"size\":50}\n        res=self.session.post(url=getUrl,headers=self.headers,json=self.data).text\n        return res\n\n\n    def getRank3(self):\n        \"\"\" 抖音号-榜单 \"\"\"\n        getRankUrl = f'https://gw.newrank.cn/api/xd/xdnphb/nr/cloud/douyin/rank/mainHotAccountAllRankList'\n        self.data={\"size\":50,\"start\":1,\"type\":\"才艺\",\"date_type\":\"days\",\"date\":\"2021-07-10\"}\n        self.headers.update({'n-token': '9116298d52d64bbfb2bafa92267f74f2'})\n        res=self.session.post(url=getRankUrl,headers=self.headers,json=self.data).text\n        return res\n\n\n    def getRank4(self):\n        \"\"\" 快手号-榜单 \"\"\"\n        path='b(\"/xdnphb/nr/cloud/ks/mini/rank/accountAllRankList?\")'\n        nonce,xyz=self.getxyz(path)\n        getRankUrl = f'https://www.newrank.cn/xdnphb/nr/cloud/ks/mini/rank/accountAllRankList?nonce={nonce}&xyz={xyz}'\n        self.data={\"type\":\"美食\",\"rankDate\":\"2021-07-10\",\"start\":1,\"size\":100,\"rankType\":\"realTime\",\"sort\":\"newrankIndex\"}\n        res=self.session.post(url=getRankUrl,headers=self.headers,json=self.data).text\n        return res\n\n\n    def getRank5(self):\n        \"\"\" bilibili-榜单 \"\"\"\n        path='b(\"/nr/bili/rank/complexMainRank?\")'\n        nonce,xyz=self.getxyz(path)\n        getRankUrl =  f'https://www.newrank.cn/nr/bili/rank/complexMainRank?nonce={nonce}&xyz={xyz}'\n        self.data={\"numeric\":\"时尚\",\"rankDate\":\"2021-07-11\",\"start\":1,\"size\":50,\"rankType\":\"0\",\"type\":\"0\"}\n        res=self.session.post(url=getRankUrl,headers=self.headers,json=self.data).text\n        return res\n\n\n\nif __name__==\"__main__\":\n    xb = XbRank()\n    print(xb.getRank2())\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.3 MD5加密逆向案例/js3.6.3.py",
    "content": "from lxpy.encrypt import md5\n\nprint(md5.get_md5('11'))"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.4 RSA参数加密逆向案例/js3.6.4.py",
    "content": "from Cryptodome.PublicKey import RSA\nfrom Cryptodome.Cipher import PKCS1_v1_5\nimport base64\n\ndef encrypt_str(data):\n    key = \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgDq4OqxuEisnk2F0EJFmw4xKa5IrcqEYHvqxPs2CHEg2kolhfWA2SjNuGAHxyDDE5MLtOvzuXjBx/5YJtc9zj2xR/0moesS+Vi/xtG1tkVaTCba+TV+Y5C61iyr3FGqr+KOD4/XECu0Xky1W9ZmmaFADmZi7+6gO9wjgVpU9aLcBcw/loHOeJrCqjp7pA98hRJRY+MML8MK15mnC4ebooOva+mJlstW6t/1lghR8WNV8cocxgcHHuXBxgns2MlACQbSdJ8c6Z3RQeRZBzyjfey6JCCfbEKouVrWIUuPphBL3OANfgp0B+QG31bapvePTfXU48TYK0M5kE+8LgbbWQIDAQAB\"\n    rsakey = RSA.import_key(base64.b64decode(key))\n    cipher = PKCS1_v1_5.new(rsakey)\n    cipher_text = base64.b64encode(cipher.encrypt(data.encode(encoding=\"utf-8\")))\n    return cipher_text\n\n\npassword = encrypt_str(\"11\")\nprint(password)\n"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.5 AES数据加密逆向案例/run.py",
    "content": "import requests\nimport base64,json,re\nfrom Crypto.Cipher import AES\n\ndef decrypt(info: str) -> list:\n    key = '3sd&d24h@$udD2s*'.encode(encoding='utf-8')\n    cipher = AES.new(key, mode=AES.MODE_ECB)\n    json_str = str(cipher.decrypt(base64.b64decode(info)), encoding='utf-8')\n    data = re.sub('[\\x00-\\x09|\\x0b-\\x0c|\\x0e-\\x1f]', '', json_str)\n    return json.loads(data)\n\nheaders = {}# 需要把你的header复制进去\n\nurl = \"https://api.hanghangcha.com/hhc/tag\"  # 产业图谱接口\nres = requests.get(url,headers=headers)\npayload = json.loads(res.content)['data']\ndata = decrypt(payload)\nprint(data)"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/js3.6.6.py",
    "content": "import execjs\n\njs = '''\n// npm install crypto-js\n\nvar CryptoJS = require(\"crypto-js\");\n\nfunction lx(hh) {\n    var aa = hh.split(\"/\");\n    var aaa = aa.length;\n    var bbb = aa[aaa - 1].split('.');\n    var ccc = bbb[0];\n    var cccc = bbb[1];\n    var r = /^\\+?[1-9][0-9]*$/;\n\n    var srcs = CryptoJS.enc.Utf8.parse(ccc);\n    var s = \"qnbyzzwmdgghmcnm\";\n    var k = CryptoJS.enc.Utf8.parse(s);\n    var en = CryptoJS.AES.encrypt(srcs, k, {\n        mode: CryptoJS.mode.ECB,\n        padding: CryptoJS.pad.Pkcs7\n    });\n    var ddd = en.toString();\n    ddd = ddd.replace(/\\//g, \"^\");\n    ddd = ddd.substring(0, ddd.length - 2);\n    var bbbb = ddd + '.' + bbb[1];\n    aa[aaa - 1] = bbbb;\n    var uuu = '';\n    for (i = 0; i < aaa; i++) {\n        uuu += aa[i] + '/'\n    }\n    uuu = uuu.substring(0, uuu.length - 1);\n    return uuu;\n}\n'''\n\nhh=\"http://ggzy.zwfwb.tj.gov.cn:80/jyxxcgjg/970369.jhtml\"\nurl = execjs.compile(js).call('lx',hh)\nprint(url)\n"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/package.json",
    "content": "{\n  \"dependencies\": {\n    \"crypto-js\": \"^4.1.1\"\n  }\n}\n"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/test.js",
    "content": "var CryptoJS = require(\"crypto-js\");\n\nfunction lx(hh) {\n    var aa = hh.split(\"/\");\n    var aaa = aa.length;\n    var bbb = aa[aaa - 1].split('.');\n    var ccc = bbb[0];\n    var cccc = bbb[1];\n    var r = /^\\+?[1-9][0-9]*$/;\n\n    var srcs = CryptoJS.enc.Utf8.parse(ccc);\n    var s = \"qnbyzzwmdgghmcnm\";\n    var k = CryptoJS.enc.Utf8.parse(s);\n    var en = CryptoJS.AES.encrypt(srcs, k, {\n        mode: CryptoJS.mode.ECB,\n        padding: CryptoJS.pad.Pkcs7\n    });\n    var ddd = en.toString();\n    ddd = ddd.replace(/\\//g, \"^\");\n    ddd = ddd.substring(0, ddd.length - 2);\n    var bbbb = ddd + '.' + bbb[1];\n    aa[aaa - 1] = bbbb;\n    var uuu = '';\n    for (i = 0; i < aaa; i++) {\n        uuu += aa[i] + '/'\n    }\n    uuu = uuu.substring(0, uuu.length - 1);\n    return uuu;\n}\nvar hh=\"http://ggzy.zwfwb.tj.gov.cn:80/jyxxcgjg/970369.jhtml\";\nconsole.log(lx(hh));"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/run.py",
    "content": "# -*- coding: utf-8 -*-\n# @Time    : 2021/12/8 10:58\n# @IDE ：PyCharm\n\nimport requests\nimport re\nimport execjs\n\nheaders = {\n    # 如果被拦截，把headers补齐\n    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'\n\n}\n\nsess = requests.session()\nurl = 'https://www.cnvd.org.cn/flaw/list.htm'\n\ndef start():\n    r =sess.get(url,headers=headers,verify=False)\n    text = r.text\n    cookie = re.search('<script>document.cookie=(.*?);location',text).group(1)\n    x = execjs.eval(cookie).split(';')[0].split('=')\n    sess.cookies[x[0]] = x[1]\n    print(x[0],x[1])\n\ndef then():\n    '''获取第二次请求的cookie'''\n    r1 = sess.get(url,headers=headers,verify=False)\n    text = r1.text\n    data = re.search(';go\\((.*?)\\)</script>',text).group(1)\n    hash = re.search('\"ha\":\"(.*?)\",',data).group(1)\n    # get_cookie_2是执行JS，完整代码请下载\n    cookie = get_cookie_2(data,hash).split(';')[0].split('=')\n    sess.cookies[cookie[0]] =cookie[1]\n\ndef end(page=1):\n    data = {'number': '请输入精确编号', 'startDate': '', 'endDate': '', 'field': '', 'order': '', 'numPerPage': '10', 'offset': page*10, 'max': '10'}\n    r1 = sess.post('https://www.cnvd.org.cn/flaw/list.htm?flag=true',headers=headers,data=data,verify=False)\n    print(r1.text)\n\n\ndef get_cookie_2(data,hash):\n    node = execjs.get()\n    path=f'./t_{hash}.js'\n    with open(path,'r',encoding='utf-8') as f:\n        ctx = node.compile(f.read())\n        funcName = f'go({data})'\n        pwd = ctx.eval(funcName)\n        return pwd\n\n\nif __name__ == '__main__':\n    start()\n    then()\n    end()\n"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_md5.js",
    "content": "window = {}\nwindow.navigator={\n'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'\n}\nfunction hash(_0x1502a6) {\n  function _0x4a30e6(_0x2ea6d4, _0x522caa) {\n    return _0x2ea6d4 << _0x522caa | _0x2ea6d4 >>> 32 - _0x522caa;\n  }\n\n  function _0x310ed6(_0x28f8be, _0x1b6c23) {\n    var _0x2cdaf, _0x5e54a4, _0x101c95, _0x1dd704, _0x5788f8;\n\n    _0x101c95 = _0x28f8be & 2147483648;\n    _0x1dd704 = _0x1b6c23 & 2147483648;\n    _0x2cdaf = _0x28f8be & 1073741824;\n    _0x5e54a4 = _0x1b6c23 & 1073741824;\n    _0x5788f8 = (_0x28f8be & 1073741823) + (_0x1b6c23 & 1073741823);\n\n    if (_0x2cdaf & _0x5e54a4) {\n      return _0x5788f8 ^ 2147483648 ^ _0x101c95 ^ _0x1dd704;\n    }\n\n    if (_0x2cdaf | _0x5e54a4) {\n      if (_0x5788f8 & 1073741824) {\n        return _0x5788f8 ^ 3221225472 ^ _0x101c95 ^ _0x1dd704;\n      } else {\n        return _0x5788f8 ^ 1073741824 ^ _0x101c95 ^ _0x1dd704;\n      }\n    } else {\n      return _0x5788f8 ^ _0x101c95 ^ _0x1dd704;\n    }\n  }\n\n  function _0x46d0b1(_0x3b37cc, _0x341375, _0x2fc6de) {\n    return _0x3b37cc & _0x341375 | ~_0x3b37cc & _0x2fc6de;\n  }\n\n  function _0xd50fd1(_0x47204c, _0x1dc758, _0x44c0fb) {\n    return _0x47204c & _0x44c0fb | _0x1dc758 & ~_0x44c0fb;\n  }\n\n  function _0x35b4c6(_0x477c88, _0x4dc0bf, _0x352ef4) {\n    return _0x477c88 ^ _0x4dc0bf ^ _0x352ef4;\n  }\n\n  function _0x556522(_0x356dac, _0x1b0899, _0x9fcb5b) {\n    return _0x1b0899 ^ (_0x356dac | ~_0x9fcb5b);\n  }\n\n  function _0x28c82a(_0x29ad55, _0x9d146f, _0xefb3b1, _0x5971fb, _0x4d05c0, _0x534b3e, _0x17d415) {\n    _0x29ad55 = _0x310ed6(_0x29ad55, _0x310ed6(_0x310ed6(_0x46d0b1(_0x9d146f, _0xefb3b1, _0x5971fb), _0x4d05c0), _0x17d415));\n    return _0x310ed6(_0x4a30e6(_0x29ad55, _0x534b3e), _0x9d146f);\n  }\n\n  function _0x6a1761(_0xadedd3, _0x4676b4, _0x3e62e4, _0x3c2512, _0x659e9e, _0x21f4da, _0x3e0c76) {\n    _0xadedd3 = _0x310ed6(_0xadedd3, _0x310ed6(_0x310ed6(_0xd50fd1(_0x4676b4, _0x3e62e4, _0x3c2512), _0x659e9e), _0x3e0c76));\n    return _0x310ed6(_0x4a30e6(_0xadedd3, _0x21f4da), _0x4676b4);\n  }\n\n  function _0x2a4a91(_0x4b4638, _0x472a89, _0x5e4e16, _0x3888b2, _0x4e74dc, _0x316a7d, _0x4cf99a) {\n    _0x4b4638 = _0x310ed6(_0x4b4638, _0x310ed6(_0x310ed6(_0x35b4c6(_0x472a89, _0x5e4e16, _0x3888b2), _0x4e74dc), _0x4cf99a));\n    return _0x310ed6(_0x4a30e6(_0x4b4638, _0x316a7d), _0x472a89);\n  }\n\n  function _0x3b9fc8(_0x4c16ec, _0x3aa156, _0x4d0799, _0x573d5f, _0x533c36, _0x663a85, _0x27414f) {\n    _0x4c16ec = _0x310ed6(_0x4c16ec, _0x310ed6(_0x310ed6(_0x556522(_0x3aa156, _0x4d0799, _0x573d5f), _0x533c36), _0x27414f));\n    return _0x310ed6(_0x4a30e6(_0x4c16ec, _0x663a85), _0x3aa156);\n  }\n\n  function _0x2fed37(_0x516a09) {\n    var _0x599f7b;\n\n    var _0x1b4436 = _0x516a09[\"length\"];\n\n    var _0x427f94 = _0x1b4436 + 8;\n\n    var _0x5c1538 = (_0x427f94 - _0x427f94 % 64) / 64;\n\n    var _0x4a4a84 = (_0x5c1538 + 1) * 16;\n\n    var _0xfd255a = Array(_0x4a4a84 - 1);\n\n    var _0x37d2af = 0;\n    var _0x199862 = 0;\n\n    while (_0x199862 < _0x1b4436) {\n      _0x599f7b = (_0x199862 - _0x199862 % 4) / 4;\n      _0x37d2af = _0x199862 % 4 * 8;\n      _0xfd255a[_0x599f7b] = _0xfd255a[_0x599f7b] | _0x516a09[\"charCodeAt\"](_0x199862) << _0x37d2af;\n      _0x199862++;\n    }\n\n    _0x599f7b = (_0x199862 - _0x199862 % 4) / 4;\n    _0x37d2af = _0x199862 % 4 * 8;\n    _0xfd255a[_0x599f7b] = _0xfd255a[_0x599f7b] | 128 << _0x37d2af;\n    _0xfd255a[_0x4a4a84 - 2] = _0x1b4436 << 3;\n    _0xfd255a[_0x4a4a84 - 1] = _0x1b4436 >>> 29;\n    return _0xfd255a;\n  }\n\n  function _0xe68e4a(_0x4eb6f7) {\n    var _0x45b2c8 = \"\",\n        _0x393ae1 = \"\",\n        _0x1e16e0,\n        _0x30b994;\n\n    for (_0x30b994 = 0; _0x30b994 <= 3; _0x30b994++) {\n      _0x1e16e0 = _0x4eb6f7 >>> _0x30b994 * 8 & 255;\n      _0x393ae1 = \"0\" + _0x1e16e0[\"toString\"](16);\n      _0x45b2c8 = _0x45b2c8 + _0x393ae1[\"substr\"](_0x393ae1[\"length\"] - 2, 2);\n    }\n\n    return _0x45b2c8;\n  }\n\n  var _0x36cde0 = Array();\n\n  var _0x47a255, _0x1a5c2a, _0xecb31, _0x4d24cf, _0x49db35, _0x1df490, _0x556813, _0x5dc91d, _0x14adb7;\n\n  var _0x24af54 = 7,\n      _0x5a822b = 12,\n      _0x3bfc54 = 17,\n      _0x3f8aea = 22;\n  var _0x3738d3 = 5,\n      _0x4324e8 = 9,\n      _0x230e41 = 14,\n      _0x4286f0 = 20;\n  var _0x470748 = 4,\n      _0x5525e3 = 11,\n      _0x34b532 = 16,\n      _0xc1dd6 = 23;\n  var _0x26a2d5 = 6,\n      _0x5ad210 = 10,\n      _0x509fcc = 15,\n      _0x20edf6 = 21;\n  _0x36cde0 = _0x2fed37(_0x1502a6);\n  _0x1df490 = 1732584193;\n  _0x556813 = 4023233417;\n  _0x5dc91d = 2562383102;\n  _0x14adb7 = 271733878;\n\n  for (_0x47a255 = 0; _0x47a255 < _0x36cde0[\"length\"]; _0x47a255 += 16) {\n    _0x1a5c2a = _0x1df490;\n    _0xecb31 = _0x556813;\n    _0x4d24cf = _0x5dc91d;\n    _0x49db35 = _0x14adb7;\n    _0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 0], _0x24af54, 3614090360);\n    _0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 1], _0x5a822b, 3905402710);\n    _0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 2], _0x3bfc54, 606105819);\n    _0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 3], _0x3f8aea, 3250441966);\n    _0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 4], _0x24af54, 4118548399);\n    _0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 5], _0x5a822b, 1200080426);\n    _0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 6], _0x3bfc54, 2821735955);\n    _0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 7], _0x3f8aea, 4249261313);\n    _0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 8], _0x24af54, 1770035416);\n    _0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 9], _0x5a822b, 2336552879);\n    _0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 10], _0x3bfc54, 4294925233);\n    _0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 11], _0x3f8aea, 2304563134);\n    _0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 12], _0x24af54, 1804603682);\n    _0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 13], _0x5a822b, 4254626195);\n    _0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 14], _0x3bfc54, 2792965006);\n    _0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 15], _0x3f8aea, 1236535329);\n    _0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 1], _0x3738d3, 4129170786);\n    _0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 6], _0x4324e8, 3225465664);\n    _0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 11], _0x230e41, 643717713);\n    _0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 0], _0x4286f0, 3921069994);\n    _0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 5], _0x3738d3, 3593408605);\n    _0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 10], _0x4324e8, 38016083);\n    _0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 15], _0x230e41, 3634488961);\n    _0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 4], _0x4286f0, 3889429448);\n    _0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 9], _0x3738d3, 568446438);\n    _0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 14], _0x4324e8, 3275163606);\n    _0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 3], _0x230e41, 4107603335);\n    _0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 8], _0x4286f0, 1163531501);\n    _0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 13], _0x3738d3, 2850285829);\n    _0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 2], _0x4324e8, 4243563512);\n    _0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 7], _0x230e41, 1735328473);\n    _0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 12], _0x4286f0, 2368359562);\n    _0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 5], _0x470748, 4294588738);\n    _0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 8], _0x5525e3, 2272392833);\n    _0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 11], _0x34b532, 1839030562);\n    _0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 14], _0xc1dd6, 4259657740);\n    _0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 1], _0x470748, 2763975236);\n    _0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 4], _0x5525e3, 1272893353);\n    _0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 7], _0x34b532, 4139469664);\n    _0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 10], _0xc1dd6, 3200236656);\n    _0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 13], _0x470748, 681279174);\n    _0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 0], _0x5525e3, 3936430074);\n    _0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 3], _0x34b532, 3572445317);\n    _0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 6], _0xc1dd6, 76029189);\n    _0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 9], _0x470748, 3654602809);\n    _0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 12], _0x5525e3, 3873151461);\n    _0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 15], _0x34b532, 530742520);\n    _0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 2], _0xc1dd6, 3299628645);\n    _0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 0], _0x26a2d5, 4096336452);\n    _0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 7], _0x5ad210, 1126891415);\n    _0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 14], _0x509fcc, 2878612391);\n    _0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 5], _0x20edf6, 4237533241);\n    _0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 12], _0x26a2d5, 1700485571);\n    _0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 3], _0x5ad210, 2399980690);\n    _0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 10], _0x509fcc, 4293915773);\n    _0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 1], _0x20edf6, 2240044497);\n    _0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 8], _0x26a2d5, 1873313359);\n    _0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 15], _0x5ad210, 4264355552);\n    _0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 6], _0x509fcc, 2734768916);\n    _0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 13], _0x20edf6, 1309151649);\n    _0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 4], _0x26a2d5, 4149444226);\n    _0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 11], _0x5ad210, 3174756917);\n    _0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 2], _0x509fcc, 718787259);\n    _0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 9], _0x20edf6, 3951481745);\n    _0x1df490 = _0x310ed6(_0x1df490, _0x1a5c2a);\n    _0x556813 = _0x310ed6(_0x556813, _0xecb31);\n    _0x5dc91d = _0x310ed6(_0x5dc91d, _0x4d24cf);\n    _0x14adb7 = _0x310ed6(_0x14adb7, _0x49db35);\n  }\n\n  var _0x1b2afe = _0xe68e4a(_0x1df490) + _0xe68e4a(_0x556813) + _0xe68e4a(_0x5dc91d) + _0xe68e4a(_0x14adb7);\n\n  return _0x1b2afe[\"toLowerCase\"]();\n}\n\nfunction go(_0x3dcb2b) {\n  function _0x3176b1() {\n    var _0x4ed7b4 = window[\"navigator\"][\"userAgent\"],\n        _0x4f1f22 = [\"Phantom\"];\n\n    for (var _0xe1d6a1 = 0; _0xe1d6a1 < _0x4f1f22[\"length\"]; _0xe1d6a1++) {\n      if (_0x4ed7b4[\"indexOf\"](_0x4f1f22[_0xe1d6a1]) != -1) {\n        return true;\n      }\n    }\n\n    if (window[\"callPhantom\"] || window[\"_phantom\"] || window[\"Headless\"] || window[\"navigator\"][\"webdriver\"] || window[\"navigator\"][\"__driver_evaluate\"] || window[\"navigator\"][\"__webdriver_evaluate\"]) {\n      return true;\n    }\n  }\n\n  if (_0x3176b1()) {\n    return;\n  }\n\n  var _0xd2394e = new Date();\n\n  function _0xf762a5(_0xc5acfd, _0x2a3cc5) {\n    var _0x134453 = _0x3dcb2b[\"chars\"][\"length\"];\n\n    for (var _0x9d4cd5 = 0; _0x9d4cd5 < _0x134453; _0x9d4cd5++) {\n      for (var _0x40802b = 0; _0x40802b < _0x134453; _0x40802b++) {\n        var _0x31753d = _0x2a3cc5[0] + _0x3dcb2b[\"chars\"][\"substr\"](_0x9d4cd5, 1) + _0x3dcb2b[\"chars\"][\"substr\"](_0x40802b, 1) + _0x2a3cc5[1];\n\n        if (hash(_0x31753d) == _0xc5acfd) {\n          return [_0x31753d, new Date() - _0xd2394e];\n        }\n      }\n    }\n  }\n\n  var _0x4d8b5f = _0xf762a5(_0x3dcb2b[\"ct\"], _0x3dcb2b[\"bts\"]);\n\n  if (_0x4d8b5f) {\n    var _0x531b56;\n\n    if (_0x3dcb2b[\"wt\"]) {\n      _0x531b56 = parseInt(_0x3dcb2b[\"wt\"]) > _0x4d8b5f[1] ? parseInt(_0x3dcb2b[\"wt\"]) - _0x4d8b5f[1] : 500;\n    } else {\n      _0x531b56 = 1500;\n    }\n\n      let c= _0x3dcb2b[\"tn\"] + \"=\" + _0x4d8b5f[0] + \";Max-age=\" + _0x3dcb2b[\"vt\"] + \"; path = /\";\n        console.log(c);\n        return c\n  } else {\n    alert(\"\\u8BF7\\u6C42\\u9A8C\\u8BC1\\xE5\\xA4\\xB1\\xE8\\xB4\\xA5\");\n  }\n}\n\ngo({\n  \"bts\": [\"1628087072.474|0|W1w\", \"wx0d3OdXraK9vfHU8Ub82M%3D\"],\n  \"chars\": \"VWCQTYxwjInsvsInUJsKMX\",\n  \"ct\": \"d2f22b3c4d6fa52cd2483003c121de68\",\n  \"ha\": \"md5\",\n  \"tn\": \"__jsl_clearance_s\",\n  \"vt\": \"3600\",\n  \"wt\": \"1500\"\n});"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha1.js",
    "content": "window = {}\nwindow.navigator={\n'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'\n}\nfunction hash(_0x3cb311) {\n  function _0x163c9c(_0x46ff88, _0x5150cb) {\n    return (_0x46ff88 & 2147483647) + (_0x5150cb & 2147483647) ^ _0x46ff88 & 2147483648 ^ _0x5150cb & 2147483648;\n  }\n\n  function _0x26ec8d(_0x3d80d1) {\n    var _0x4e7763 = \"0123456789abcdef\";\n    var _0x1603cb = \"\";\n\n    for (var _0x4a1d1d = 7; _0x4a1d1d >= 0; _0x4a1d1d--) {\n      _0x1603cb += _0x4e7763[\"charAt\"](_0x3d80d1 >> _0x4a1d1d * 4 & 15);\n    }\n\n    return _0x1603cb;\n  }\n\n  function _0x153602(_0x2c0782) {\n    var _0x1cd5a1 = (_0x2c0782[\"length\"] + 8 >> 6) + 1,\n        _0x1db977 = new Array(_0x1cd5a1 * 16);\n\n    for (var _0x17fd51 = 0; _0x17fd51 < _0x1cd5a1 * 16; _0x17fd51++) {\n      _0x1db977[_0x17fd51] = 0;\n    }\n\n    for (_0x17fd51 = 0; _0x17fd51 < _0x2c0782[\"length\"]; _0x17fd51++) {\n      _0x1db977[_0x17fd51 >> 2] |= _0x2c0782[\"charCodeAt\"](_0x17fd51) << 24 - (_0x17fd51 & 3) * 8;\n    }\n\n    _0x1db977[_0x17fd51 >> 2] |= 128 << 24 - (_0x17fd51 & 3) * 8;\n    _0x1db977[_0x1cd5a1 * 16 - 1] = _0x2c0782[\"length\"] * 8;\n    return _0x1db977;\n  }\n\n  function _0x37aa8c(_0x1b0f9a, _0x48e60d) {\n    return _0x1b0f9a << _0x48e60d | _0x1b0f9a >>> 32 - _0x48e60d;\n  }\n\n  function _0x3ba558(_0x3e8bd0, _0x360d42, _0x2cf1fe, _0x2d6f7f) {\n    if (_0x3e8bd0 < 20) {\n      return _0x360d42 & _0x2cf1fe | ~_0x360d42 & _0x2d6f7f;\n    }\n\n    if (_0x3e8bd0 < 40) {\n      return _0x360d42 ^ _0x2cf1fe ^ _0x2d6f7f;\n    }\n\n    if (_0x3e8bd0 < 60) {\n      return _0x360d42 & _0x2cf1fe | _0x360d42 & _0x2d6f7f | _0x2cf1fe & _0x2d6f7f;\n    }\n\n    return _0x360d42 ^ _0x2cf1fe ^ _0x2d6f7f;\n  }\n\n  function _0x23a48b(_0x3f81a0) {\n    return _0x3f81a0 < 20 ? 1518500249 : _0x3f81a0 < 40 ? 1859775393 : _0x3f81a0 < 60 ? -1894007588 : -899497514;\n  }\n\n  var _0x1cdcad = _0x153602(_0x3cb311);\n\n  var _0x32dc39 = new Array(80);\n\n  var _0xccaec7 = 1732584193;\n\n  var _0x32e008 = -271733879;\n\n  var _0x485153 = -1732584194;\n\n  var _0x489b5b = 271733878;\n\n  var _0x205716 = -1009589776;\n\n  for (var _0x41a7c6 = 0; _0x41a7c6 < _0x1cdcad[\"length\"]; _0x41a7c6 += 16) {\n    var _0x152b2d = _0xccaec7;\n    var _0x1cd17d = _0x32e008;\n    var _0xf419f9 = _0x485153;\n    var _0x536541 = _0x489b5b;\n    var _0x34be50 = _0x205716;\n\n    for (var _0x6d61ab = 0; _0x6d61ab < 80; _0x6d61ab++) {\n      if (_0x6d61ab < 16) {\n        _0x32dc39[_0x6d61ab] = _0x1cdcad[_0x41a7c6 + _0x6d61ab];\n      } else {\n        _0x32dc39[_0x6d61ab] = _0x37aa8c(_0x32dc39[_0x6d61ab - 3] ^ _0x32dc39[_0x6d61ab - 8] ^ _0x32dc39[_0x6d61ab - 14] ^ _0x32dc39[_0x6d61ab - 16], 1);\n      }\n\n      t = _0x163c9c(_0x163c9c(_0x37aa8c(_0xccaec7, 5), _0x3ba558(_0x6d61ab, _0x32e008, _0x485153, _0x489b5b)), _0x163c9c(_0x163c9c(_0x205716, _0x32dc39[_0x6d61ab]), _0x23a48b(_0x6d61ab)));\n      _0x205716 = _0x489b5b;\n      _0x489b5b = _0x485153;\n      _0x485153 = _0x37aa8c(_0x32e008, 30);\n      _0x32e008 = _0xccaec7;\n      _0xccaec7 = t;\n    }\n\n    _0xccaec7 = _0x163c9c(_0xccaec7, _0x152b2d);\n    _0x32e008 = _0x163c9c(_0x32e008, _0x1cd17d);\n    _0x485153 = _0x163c9c(_0x485153, _0xf419f9);\n    _0x489b5b = _0x163c9c(_0x489b5b, _0x536541);\n    _0x205716 = _0x163c9c(_0x205716, _0x34be50);\n  }\n\n  return _0x26ec8d(_0xccaec7) + _0x26ec8d(_0x32e008) + _0x26ec8d(_0x485153) + _0x26ec8d(_0x489b5b) + _0x26ec8d(_0x205716);\n}\n\nfunction go(_0x3643f0) {\n  function _0x939e9d() {\n    var _0x25184e = window[\"navigator\"][\"userAgent\"],\n        _0x3d9896 = [\"Phantom\"];\n\n    for (var _0x41f164 = 0; _0x41f164 < _0x3d9896[\"length\"]; _0x41f164++) {\n      if (_0x25184e[\"indexOf\"](_0x3d9896[_0x41f164]) != -1) {\n        return true;\n      }\n    }\n\n    if (window[\"callPhantom\"] || window[\"_phantom\"] || window[\"Headless\"] || window[\"navigator\"][\"webdriver\"] || window[\"navigator\"][\"__driver_evaluate\"] || window[\"navigator\"][\"__webdriver_evaluate\"]) {\n      return true;\n    }\n  }\n\n  if (_0x939e9d()) {\n    return;\n  }\n\n  var _0x4a8c9f = new Date();\n\n  function _0x30c06b(_0x56f5b0, _0x447494) {\n    var _0x59337c = _0x3643f0[\"chars\"][\"length\"];\n\n    for (var _0x197671 = 0; _0x197671 < _0x59337c; _0x197671++) {\n      for (var _0x47ac04 = 0; _0x47ac04 < _0x59337c; _0x47ac04++) {\n        var _0x357062 = _0x447494[0] + _0x3643f0[\"chars\"][\"substr\"](_0x197671, 1) + _0x3643f0[\"chars\"][\"substr\"](_0x47ac04, 1) + _0x447494[1];\n\n        if (hash(_0x357062) == _0x56f5b0) {\n          return [_0x357062, new Date() - _0x4a8c9f];\n        }\n      }\n    }\n  }\n\n  var _0x4f0d12 = _0x30c06b(_0x3643f0[\"ct\"], _0x3643f0[\"bts\"]);\n\n  if (_0x4f0d12) {\n    var _0x1dae31;\n\n    if (_0x3643f0[\"wt\"]) {\n      _0x1dae31 = parseInt(_0x3643f0[\"wt\"]) > _0x4f0d12[1] ? parseInt(_0x3643f0[\"wt\"]) - _0x4f0d12[1] : 500;\n    } else {\n      _0x1dae31 = 1500;\n    }\n\n      let c = _0x3643f0[\"tn\"] + \"=\" + _0x4f0d12[0] + \";Max-age=\" + _0x3643f0[\"vt\"] + \"; path = /\";\n      console.log(c);\n      return c\n  } else {\n    alert(\"\\u8BF7\\u6C42\\u9A8C\\u8BC1\\xE5\\xA4\\xB1\\xE8\\xB4\\xA5\");\n  }\n}\n\ngo({\n  \"bts\": [\"1628088065.4|0|rZGRv\", \"gwlQ6aBQ9ZCDZeup2IEk%3D\"],\n  \"chars\": \"vMJCKTooRTjlkttqnCeuEL\",\n  \"ct\": \"db970e51a07226e63edcf9153c748160de4a3622\",\n  \"ha\": \"sha1\",\n  \"tn\": \"__jsl_clearance_s\",\n  \"vt\": \"3600\",\n  \"wt\": \"1500\"\n});"
  },
  {
    "path": "第三章：Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha256.js",
    "content": "window = {}\nwindow.navigator={\n'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'\n}\n\nfunction hash(_0xb3a2f3) {\n  var _0x436214 = 8;\n  var _0x3ebd36 = 0;\n\n  function _0x70fb8(_0x3b1fbb, _0x4a616c) {\n    var _0x5df8da = (_0x3b1fbb & 65535) + (_0x4a616c & 65535);\n\n    var _0x23a7a2 = (_0x3b1fbb >> 16) + (_0x4a616c >> 16) + (_0x5df8da >> 16);\n\n    return _0x23a7a2 << 16 | _0x5df8da & 65535;\n  }\n\n  function _0x4e57dd(_0x4d810e, _0x184aac) {\n    return _0x4d810e >>> _0x184aac | _0x4d810e << 32 - _0x184aac;\n  }\n\n  function _0x36087b(_0x152685, _0x48a182) {\n    return _0x152685 >>> _0x48a182;\n  }\n\n  function _0x399548(_0x4dcebb, _0xab0153, _0x7dbf5b) {\n    return _0x4dcebb & _0xab0153 ^ ~_0x4dcebb & _0x7dbf5b;\n  }\n\n  function _0x48ee3a(_0x333fa7, _0x55d2ec, _0x17a443) {\n    return _0x333fa7 & _0x55d2ec ^ _0x333fa7 & _0x17a443 ^ _0x55d2ec & _0x17a443;\n  }\n\n  function _0x310842(_0x2be1b1) {\n    return _0x4e57dd(_0x2be1b1, 2) ^ _0x4e57dd(_0x2be1b1, 13) ^ _0x4e57dd(_0x2be1b1, 22);\n  }\n\n  function _0x7d5a12(_0x647765) {\n    return _0x4e57dd(_0x647765, 6) ^ _0x4e57dd(_0x647765, 11) ^ _0x4e57dd(_0x647765, 25);\n  }\n\n  function _0x1cdddc(_0x8ec478) {\n    return _0x4e57dd(_0x8ec478, 7) ^ _0x4e57dd(_0x8ec478, 18) ^ _0x36087b(_0x8ec478, 3);\n  }\n\n  function _0x38e736(_0x57bc8e) {\n    return _0x4e57dd(_0x57bc8e, 17) ^ _0x4e57dd(_0x57bc8e, 19) ^ _0x36087b(_0x57bc8e, 10);\n  }\n\n  function _0x58103a(_0x3b9164, _0x1e15fd) {\n    var _0xea397a = new Array(1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298);\n\n    var _0x429abc = new Array(1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225);\n\n    var _0x2b18db = new Array(64);\n\n    var _0x57b507, _0x2f7eb6, _0x3a62a0, _0x38f7e0, _0x880a21, _0x5a6598, _0xa6d654, _0x3f0a05, _0x1f3b08, _0x521f34;\n\n    var _0x4bc8b6, _0x394ae6;\n\n    _0x3b9164[_0x1e15fd >> 5] |= 128 << 24 - _0x1e15fd % 32;\n    _0x3b9164[(_0x1e15fd + 64 >> 9 << 4) + 15] = _0x1e15fd;\n\n    for (var _0x1f3b08 = 0; _0x1f3b08 < _0x3b9164[\"length\"]; _0x1f3b08 += 16) {\n      _0x57b507 = _0x429abc[0];\n      _0x2f7eb6 = _0x429abc[1];\n      _0x3a62a0 = _0x429abc[2];\n      _0x38f7e0 = _0x429abc[3];\n      _0x880a21 = _0x429abc[4];\n      _0x5a6598 = _0x429abc[5];\n      _0xa6d654 = _0x429abc[6];\n      _0x3f0a05 = _0x429abc[7];\n\n      for (var _0x521f34 = 0; _0x521f34 < 64; _0x521f34++) {\n        if (_0x521f34 < 16) {\n          _0x2b18db[_0x521f34] = _0x3b9164[_0x521f34 + _0x1f3b08];\n        } else {\n          _0x2b18db[_0x521f34] = _0x70fb8(_0x70fb8(_0x70fb8(_0x38e736(_0x2b18db[_0x521f34 - 2]), _0x2b18db[_0x521f34 - 7]), _0x1cdddc(_0x2b18db[_0x521f34 - 15])), _0x2b18db[_0x521f34 - 16]);\n        }\n\n        _0x4bc8b6 = _0x70fb8(_0x70fb8(_0x70fb8(_0x70fb8(_0x3f0a05, _0x7d5a12(_0x880a21)), _0x399548(_0x880a21, _0x5a6598, _0xa6d654)), _0xea397a[_0x521f34]), _0x2b18db[_0x521f34]);\n        _0x394ae6 = _0x70fb8(_0x310842(_0x57b507), _0x48ee3a(_0x57b507, _0x2f7eb6, _0x3a62a0));\n        _0x3f0a05 = _0xa6d654;\n        _0xa6d654 = _0x5a6598;\n        _0x5a6598 = _0x880a21;\n        _0x880a21 = _0x70fb8(_0x38f7e0, _0x4bc8b6);\n        _0x38f7e0 = _0x3a62a0;\n        _0x3a62a0 = _0x2f7eb6;\n        _0x2f7eb6 = _0x57b507;\n        _0x57b507 = _0x70fb8(_0x4bc8b6, _0x394ae6);\n      }\n\n      _0x429abc[0] = _0x70fb8(_0x57b507, _0x429abc[0]);\n      _0x429abc[1] = _0x70fb8(_0x2f7eb6, _0x429abc[1]);\n      _0x429abc[2] = _0x70fb8(_0x3a62a0, _0x429abc[2]);\n      _0x429abc[3] = _0x70fb8(_0x38f7e0, _0x429abc[3]);\n      _0x429abc[4] = _0x70fb8(_0x880a21, _0x429abc[4]);\n      _0x429abc[5] = _0x70fb8(_0x5a6598, _0x429abc[5]);\n      _0x429abc[6] = _0x70fb8(_0xa6d654, _0x429abc[6]);\n      _0x429abc[7] = _0x70fb8(_0x3f0a05, _0x429abc[7]);\n    }\n\n    return _0x429abc;\n  }\n\n  function _0xe1c49c(_0x1f224c) {\n    var _0xb5927 = Array();\n\n    var _0xc3530a = 255;\n\n    for (var _0x1c5849 = 0; _0x1c5849 < _0x1f224c[\"length\"] * _0x436214; _0x1c5849 += _0x436214) {\n      _0xb5927[_0x1c5849 >> 5] |= (_0x1f224c[\"charCodeAt\"](_0x1c5849 / _0x436214) & _0xc3530a) << 24 - _0x1c5849 % 32;\n    }\n\n    return _0xb5927;\n  }\n\n  function _0x4756fb(_0x57f4af) {\n    var _0x1d8407 = new RegExp(\"\\n\", \"g\");\n\n    _0x57f4af = _0x57f4af[\"replace\"](_0x1d8407, \"\\n\");\n    var _0x577056 = \"\";\n\n    for (var _0x2ed237 = 0; _0x2ed237 < _0x57f4af[\"length\"]; _0x2ed237++) {\n      var _0x6189ac = _0x57f4af[\"charCodeAt\"](_0x2ed237);\n\n      if (_0x6189ac < 128) {\n        _0x577056 += String[\"fromCharCode\"](_0x6189ac);\n      } else {\n        if (_0x6189ac > 127 && _0x6189ac < 2048) {\n          _0x577056 += String[\"fromCharCode\"](_0x6189ac >> 6 | 192);\n          _0x577056 += String[\"fromCharCode\"](_0x6189ac & 63 | 128);\n        } else {\n          _0x577056 += String[\"fromCharCode\"](_0x6189ac >> 12 | 224);\n          _0x577056 += String[\"fromCharCode\"](_0x6189ac >> 6 & 63 | 128);\n          _0x577056 += String[\"fromCharCode\"](_0x6189ac & 63 | 128);\n        }\n      }\n    }\n\n    return _0x577056;\n  }\n\n  function _0x37f0cd(_0x536fde) {\n    var _0x57d084 = \"0123456789abcdef\";\n    var _0x5f16c6 = \"\";\n\n    for (var _0x39c170 = 0; _0x39c170 < _0x536fde[\"length\"] * 4; _0x39c170++) {\n      _0x5f16c6 += _0x57d084[\"charAt\"](_0x536fde[_0x39c170 >> 2] >> (3 - _0x39c170 % 4) * 8 + 4 & 15) + _0x57d084[\"charAt\"](_0x536fde[_0x39c170 >> 2] >> (3 - _0x39c170 % 4) * 8 & 15);\n    }\n\n    return _0x5f16c6;\n  }\n\n  _0xb3a2f3 = _0x4756fb(_0xb3a2f3);\n  return _0x37f0cd(_0x58103a(_0xe1c49c(_0xb3a2f3), _0xb3a2f3[\"length\"] * _0x436214));\n}\n\nfunction go(_0x50cd53) {\n  function _0x42fc6c() {\n    var _0x20ef9d = window[\"navigator\"][\"userAgent\"],\n        _0x54abc6 = [\"Phantom\"];\n\n    for (var _0x27b17f = 0; _0x27b17f < _0x54abc6[\"length\"]; _0x27b17f++) {\n      if (_0x20ef9d[\"indexOf\"](_0x54abc6[_0x27b17f]) != -1) {\n        return true;\n      }\n    }\n\n    if (window[\"callPhantom\"] || window[\"_phantom\"] || window[\"Headless\"] || window[\"navigator\"][\"webdriver\"] || window[\"navigator\"][\"__driver_evaluate\"] || window[\"navigator\"][\"__webdriver_evaluate\"]) {\n      return true;\n    }\n  }\n\n  if (_0x42fc6c()) {\n    return;\n  }\n\n  var _0x171728 = new Date();\n\n  function _0x107d5a(_0x3569e5, _0x3a4385) {\n    var _0x26d368 = _0x50cd53[\"chars\"][\"length\"];\n\n    for (var _0x2f27d0 = 0; _0x2f27d0 < _0x26d368; _0x2f27d0++) {\n      for (var _0x2726ec = 0; _0x2726ec < _0x26d368; _0x2726ec++) {\n        var _0x58eac9 = _0x3a4385[0] + _0x50cd53[\"chars\"][\"substr\"](_0x2f27d0, 1) + _0x50cd53[\"chars\"][\"substr\"](_0x2726ec, 1) + _0x3a4385[1];\n\n        if (hash(_0x58eac9) == _0x3569e5) {\n          return [_0x58eac9, new Date() - _0x171728];\n        }\n      }\n    }\n  }\n\n  var _0x454576 = _0x107d5a(_0x50cd53[\"ct\"], _0x50cd53[\"bts\"]);\n\n  if (_0x454576) {\n    var _0x3fef91;\n\n    if (_0x50cd53[\"wt\"]) {\n      _0x3fef91 = parseInt(_0x50cd53[\"wt\"]) > _0x454576[1] ? parseInt(_0x50cd53[\"wt\"]) - _0x454576[1] : 500;\n    } else {\n      _0x3fef91 = 1500;\n    }\n\n\n      let c = _0x50cd53[\"tn\"] + \"=\" + _0x454576[0] + \";Max-age=\" + _0x50cd53[\"vt\"] + \"; path = /\";\n      return c;\n\n  } else {\n    alert(\"\\u8BF7\\u6C42\\u9A8C\\u8BC1\\xE5\\xA4\\xB1\\xE8\\xB4\\xA5\");\n  }\n}\n\nconsole.log(go({\"bts\":[\"1628085220.599|0|tiI\",\"3%2FYgQQn8dPhB2M%2FaZ%2Br%2FxM%3D\"],\"chars\":\"fcWjlrafYQYbXeqadeXCvr\",\"ct\":\"49fe40ac16199b24ad4c096b09d73d39dbc07cccab4aa2d53a6304acdc31e931\",\"ha\":\"sha256\",\"tn\":\"__jsl_clearance_s\",\"vt\":\"3600\",\"wt\":\"1500\"}\n));"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/js-hook.txt",
    "content": "\n## Hook setInterval \n```js\nlet _setInterval=setInterval;\nsetInterval=function(a,b){\n\tif(a.toString().indexOf(\"debugger\")!=-1){\n\t\treturn null;\n\t}\n\t_setInterval(a,b);\n}\n```\n\n## Hook Cookie Info\n```js\nvar cookie_cache = document.cookie;\nObject.defineProperty(document, 'cookie', {\n    get: function() {\n        console.log('Getting cookie');\n        return cookie_cache;\n    },\n    set: function(val) {\n        console.log('Setting cookie', val);\n        var cookie = val.split(\";\")[0];\n        var ncookie = cookie.split(\"=\");\n        var flag = false;\n        var cache = cookie_cache.split(\"; \");\n        cache = cache.map(function(a){\n            if (a.split(\"=\")[0] === ncookie[0]){\n                flag = true;\n                return cookie;\n            }\n            return a;\n        })\n        cookie_cache = cache.join(\"; \");\n        if (!flag){\n            cookie_cache += cookie + \"; \";\n        }\n        this._value = val;\n        return cookie_cache;\n    },\n});\n```\n\n\n## Hook Json Info\n```js\nvar my_stringify = JSON.stringify;\nJSON.stringify = function (params){\n    console.log(\"json_stringify:\", params);\n    return json_stringify(params);\n};\n\nvar my_parse = JSON.parse;\nJSON.parse = function (params){\n    console.log(\"json_parse:\", params);\n    return json_parse(params);\n};\n```\n\n## Hook WebSocket\n```js\nWebSocket.prototype.senda = WebSocket.prototype.send;\nWebSocket.prototype.send = function (data){\n console.info(\"Hook WebSocket\", data);\n return this.senda(data)\n}\n```\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/readme.md",
    "content": "常被检测的环境中，有windows、location、navigate、document、native、canvas等。\n\n除了这些属性外，还有针对于自动化的检测、node环境的检测、以及浏览器指纹检测、TLS指纹校验等。\n\n所谓的补环境是指在Node环境中去运行浏览器的代码，因为Node环境和浏览器环境是不同的，比如DOM渲染和浏览器内置方法，而经常需要补的内容也是这些。\n\n笔者总结的补环境有两种方式，一是在本地Node中扣代码补环境，二是通过驱动开启一个浏览器环境去执行代码，但是需要记得补驱动的特征。\n\n不过最优的方法还是在本地补，所以这里简单分享一些补的方法和代码。\n\n---\n\n3.7.0 中给出的几个文件是笔者准备的一些工具类，笔者自己写的和收集于网络的都贴上来。\n\n由于这块内容不太好总结，环境并不是通用的。用文字来描述的话，要么贴已经补过的代码，要么贴一键hook的脚本。\n\n虽然每次补之前直接把各种环境堆上去碰运气也是一种方法，但是碰到独特的检测点等于直接从0开始。\n\n毕竟刚开始都是打着debugger缺啥补啥，大家先掌握那些基本的语法。\n\n\n---\n\n所以先知道怎么补之后，再来决定用什么方法获取对象的属性或方法。\n\n```js\ndocument = {\n    createElement:function(x){\n        return {}\n    }\n}\n\nvar _getXxx = {\n    toString: function() {\n        return \"\"\n    }\n};\n\n_getXxx.__proto__.getA = function getA(x) {\n    return {}\n};\n```\n\n\n比如给document补一些方法\n\n```js\nvar document = {\n    createEvent: function createEvent() {},\n    addEventListener: function addEventListener(x) {},\n    createElement: function createElement(x) {\n        if(x===\"\"){} else {}\n    }\n};\n```\n\n比如给 getLX_method 对象增加方法。\n```js\nvar getLX_method = {};\ngetLX_method.__proto__.getExtension = function getExtension(x) {\n    return {}\n}\ngetLX_method.__proto__.getParameter = function getParameter(x) {\n    return \"\"\n}\n```\n\n比如补 canvas 的话，我们只需要看它调用的方法和返回的结果，然后去一次性绘制图片，取出base64值放到toDataURL()中即可。\n\n```js\ndocument = {\n\tcreateElement: function createElement(x) {\n\t\treturn canvas\n\t}\n};\n\ncanvas = {\n\ttoDataURL: function toDataURL() {\n\t\treturn \"data:image/png;base64,i.....ggg==\"\n\t},\n\tgetContext: function getContext(x) {\n        if (x === \"xxx\") {\n            return \n        } else {\n            return CanvasContext \n        }\n\t}\n};\n\nCanvasContext = {\n\tarc: function arc() {},\n\tstroke: function stroke() {},\n\tfillText: function fillText() {},\n\ttoString: function() {\n        return \"[object]\"\n    }\n};\n\ncanvas[Symbol.toStringTag] = \"HTMLCanvasElement\";\n```\n\n重写String的查找方法\n```js\n\tvar _indexOf = String.prototype.indexOf;\n\tString.prototype.indexOf = function (searchValue, fromIndex) {\n\tif (searchValue == 'lx') {\n\t\treturn-1;\n}\n\treturn _indexOf.apply(this, [searchValue, fromIndex]);\n}\n```\n\n重写toString方法：\n```js\nvar newString = Function.prototype.toString;\n\tFunction.prototype.toString = function () {\n\t\tif (this == Window || this == Location || this == Function.prototype.toString) {\n\t\treturn\"function Window() { [native code] }\";\n\t}\n\treturn newString.apply(this);\n};\n```\n\n\n\n再给大家分享一些补环境经验：\n\n1、检测环境记心里，指纹信息重获取。\n\n2、dom操作记一记，Jsdom多练习。\n\n3、不可变对象记得Object.freeze()\n\n4、多用debugger巧用proxy\n\n5、内置方法防重写\n\n6、形成框架方便二次修改\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t0 浏览器指纹解读.md",
    "content": "科普文，简单解读浏览器指纹相关内容，如有描述不周望谅解。\n\n\n---\n\n## 浏览器指纹\n浏览器指纹很重要，在数据采集、搜索引擎、埋点分析、网站测试等方面都有体现。\n\n指纹通常是指服务端的为了做识别而收集的客户端设备信息。即使没有cookie，指纹也可用于识别个人用户或设备。\n\n\n比如常用于记录的指纹 Header、Cookie、IP、DNS、UserAgent，Font（字体列表），Language，localStorage、Plugin（插件），Canvas（渲染绘图），WebGL（3D渲染图形），Web Vendor，Timezone（时区），WebRTC，ScreenResolution（分辨率），Platform（系统），Audio（音频设置和硬件特征指纹），以及enumerateDevices（其他媒体设备）、CPU、GPU信息等等。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/07e1f9d7dc444e798ddae4cf9221cfac.png)\n\n像用户代理、HTML元素属性、Dom对象操作等都属于基本指纹。\n像图形渲染、音频指纹、硬件指纹这些属于高级指纹，生成或者模拟都有一定难度。\n像浏览记录、访问频率等属于行为指纹，常用于恶意访问的判定，具体判定规则需要测试。\n\n\n当你浏览页面时，网站可以根据你的浏览器指纹进行跟踪，此外还有一些网站会根据指纹信息生成设备ID然后发送行为日志。\n所以在你访问了一个网站后，它虽然没有cookie，但是有一个唯一的指纹，所以无论是推送广告还是行为检测都非常容易。\n\n\n在线查看浏览器指纹：\n- https://www.deviceinfo.me/  （非常详细的设备信息）\n- https://www.yalala.com/     （单一特征的指纹）\n- http://uniquemachine.org/   （特征合一的指纹）\n- https://pixelscan.net/  （像素扫描信息）\n- https://ja3er.com/  (ja3 SSL指纹)\n- https://iphey.com/#loc-text  （以IP为主的数字身份）\n- http://dnscookie.com/ （NDS cookie指纹）\n- https://amiunique.org/fp \n- https://firstpartysimulator.net/kcarter?\n\n---\n\n\n## chromedriver指纹\n不论是selenium或者puppeteer或者playwright，基于chromedriver封装的自动化工具库都很容易被网站监测，所以如何应对指纹检测对使用者来说非常重要。\n\n比如特征参数 webdriver，启动参数no-first-run、window-size、log-level、start-maximized、no-sandbox等，用户特征 user_data_dir、language，以及一些html类型Webelement等。\n\n设置 webdriver为flase：\n```python\nbroser.execute_cdp_cmd(\n     \"Page.addScriptToEvaluateOnNewDocument\",\n     {\n         \"source\": \"\"\"\n             Object.defineProperty(window, 'navigator', {\n                 value: new Proxy(navigator, {\n                         has: (target, key) => (key === 'webdriver' ? false : key in target),\n                         get: (target, key) =>\n                                 key === 'webdriver' ?\n                                 false :\n                                 typeof target[key] === 'function' ?\n                                 target[key].bind(target) :\n                                 target[key]\n                         })\n             });\n\n     \"\"\"\n     },\n)\n```\n\n具体方法可以参考 undetected-chromedriver 开源库，源码中给出了丰富的解决方法。\n\n\n---\n\n\n## 隐藏指纹的插件\n\nCanvas Fingerprint Defender  隐藏canvas，不适用于最新chrome\n\nAudioContext Fingerprint Defender-AudioContext  伪造指纹\n\nChameleon by sereneblue  修改UA、分辨率、语言等\n\n一些插件已经不适用于新版google的 manifest_version 要求， 那我们也可以手动去禁用一些指纹，比如Canvas 、WebGL，或者直接禁用JavaScript，但是会影响网站正常运行。\n\n甚至于禁用JavaScript后，一些网站还会根据页面的CSS样式表来获取信息。\n\n\n---\n\n## 修改指纹的浏览器\n\n所以有时候可以使用指纹浏览器来进行调试。\n\n巨象浏览器\nAdsPower浏览器\n阿拉鱼指纹浏览器\nhubstudio指纹浏览器\n洋葱浏览器\n\n\n---\n\n## 反爬指纹的生成\n\n目前常见的反爬指纹有\n\n- 基于某种算法的请求指纹（如：TLS-Ja3、报文指纹）\n- 基于某种算法生成的环境指纹 （如：fingerprint2）\n- 基于服务器预设文件执行结果返回的接口调用信息（如：日志）\n- 基于浏览器对服务器不同参数的动画渲染提取出浏览器的帧数信息\n\n\n\n这些指纹都可生成一个动态值在接口中校验，无论是在验证请求或者是数据解密。\n\n不过指纹用于检验时都是结合起来使用的，比如把fingerprint和结合起来形成新的指纹ID。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/7fbb079bdaeb4d749fcf1fc93e17bc7a.png)\n\n\n\n\n比如https://fingerprintjs.com/demo/的示例。\n\n其算法与浏览器信息生成和设备关联的唯一标识符，用于访问识别，具体方法可阅读官方文档。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/d477838bda794169a17e30c861be981f.png)\n\n\n\n\n---\n\n## canvas指纹\n\n在线查看：[https://browserleaks.com/canvas](https://browserleaks.com/canvas)\n\nCanvas 是一种 HTML5 API，相当于一个画布，用于通过 JavaScript 脚本在网页上绘制图形和动画。\n\n因为Canvas 在不同操作系统不同浏览器上所产生的图片内容基本不同，所以其可用作浏览器指纹识别中的特征，用于标识身份。\n\n但是需要注意 canvas 指纹并不具备唯一性，所以常和其他指纹结合起来计算唯一身份ID。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/c7491496142b4c53a4cd391c2ee9aa24.png)\n![在这里插入图片描述](https://img-blog.csdnimg.cn/6183d52155df4dd18942303c533dd196.png)\n\n那在Js中如何获取Canvas 指纹呢，通常是基于Canvas 绘制特定内容的图片，然后使用 canvas.toDataURL()方法返回该图片内容的base64编码字符串，这一点在我们补环境时也经常遇到。\n\n\n\n\n---\n\n\n## 音频指纹\n浏览器音频指纹AudioContext 测试地址 ：https://audiofingerprint.openwpm.com/ \n\nAudioContext接口表示由链接在一起的音频模块构建的音频处理图，音频上下文控制它包含的节点的创建和音频处理或解码的执行。\n\n在FingerprintJS2有获取音频指纹的代码。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/fb3c4af2001f4fecb21aa3af5242ba49.png)\n\n\n---\n\n## 简述补浏览器环境\n\n所谓的补环境是指在Node环境中去运行浏览器的代码，因为Node环境和浏览器环境是不同的，比如DOM渲染和浏览器内置方法，而经常需要补的内容也是这些。\n\n笔者总结的补环境有两种方式，一是在本地Node中扣代码补环境，二是通过驱动开启一个浏览器环境去执行代码，但是需要记得补驱动的特征。\n\n不过最优的方法还是在本地补，所以这里简单分享一些补的方法和代码。\n\n比如给document补一些方法\n\n```js\nvar document = {\n    createEvent: function createEvent() {},\n    addEventListener: function addEventListener(x) {},\n    createElement: function createElement(x) {\n        if(x===\"\"){} else {}\n    }\n};\n```\n\n比如给 getLX_method 对象增加方法。\n```js\nvar getLX_method = {};\ngetLX_method.__proto__.getExtension = function getExtension(x) {\n    return {}\n}\ngetLX_method.__proto__.getParameter = function getParameter(x) {\n    return \"\"\n}\n```\n\n比如补 canvas 的话，我们只需要看它调用的方法和返回的结果，然后去一次性绘制图片，取出base64值放到toDataURL()中即可。\n\n```js\ndocument = {\n\tcreateElement: function createElement(x) {\n\t\treturn canvas\n\t}\n};\n\ncanvas = {\n\ttoDataURL: function toDataURL() {\n\t\treturn \"data:image/png;base64,i.....ggg==\"\n\t},\n\tgetContext: function getContext(x) {\n        if (x === \"xxx\") {\n            return \n        } else {\n            return CanvasContext \n        }\n\t}\n};\n\nCanvasContext = {\n\tarc: function arc() {},\n\tstroke: function stroke() {},\n\tfillText: function fillText() {},\n\ttoString: function() {\n        return \"[object]\"\n    }\n};\n\ncanvas[Symbol.toStringTag] = \"HTMLCanvasElement\";\n```\n\n重写String的查找方法\n```js\n\tvar _indexOf = String.prototype.indexOf;\n\tString.prototype.indexOf = function (searchValue, fromIndex) {\n\tif (searchValue == 'lx') {\n\t\treturn-1;\n}\n\treturn _indexOf.apply(this, [searchValue, fromIndex]);\n}\n```\n\n重写toString方法：\n```js\nvar newString = Function.prototype.toString;\n\tFunction.prototype.toString = function () {\n\t\tif (this == Window || this == Location || this == Function.prototype.toString) {\n\t\treturn\"function Window() { [native code] }\";\n\t}\n\treturn newString.apply(this);\n};\n```\n\n\n\n再给大家分享一些补环境经验：\n\n1、检测环境记心里，指纹信息重获取。\n\n2、dom操作记一记，Jsdom多练习。\n\n3、不可变对象记得Object.freeze()\n\n4、多用debugger巧用proxy\n\n5、内置方法防重写\n\n6、形成框架方便二次修改\n\n\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t1.js",
    "content": "// 最基础的\nvar glb;\nvar window = global;\nwindow.document = {referrer: \"\"};\nwindow.location = {\n    hash: \"\",\n    host: \"\",\n    hostname: \"\",\n    href: \"\",\n    origin: \"\",\n    pathname: \"/\",\n    port: \"\",\n    protocol: \"https:\",\n    search: \"\"\n};\nwindow.navigator = {\n    appCodeName: \"Mozilla\",\n    appName: \"Netscape\",\n    appVersion: \"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36\",\n    cookieEnabled: true,\n    deviceMemory: 8,\n    doNotTrack: null,\n    hardwareConcurrency: 4,\n    language: \"zh-CN\",\n    languages: [\"zh-CN\", \"zh\"],\n    maxTouchPoints: 0,\n    onLine: true,\n    platform: \"Win32\",\n    product: \"Gecko\",\n    productSub: \"20030107\",\n    userAgent: \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36\",\n    vendor: \"Google Inc.\",\n    vendorSub: \"\",\n};\n\nfunction get_signature(url) {\n    _signature = \"\";\n    return _signature;\n}\n\n// Js代码位置\nurl = '';\nconsole.log(get_signature(url));\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t2.js",
    "content": "// jsdom\nconst jsdom = require(\"jsdom\");\nconst { JSDOM } = jsdom;\nconst dom = new JSDOM(`<!DOCTYPE html><p>Hello Lx</p>`);\nwindow = global;\nvar document = dom.window.document;\nvar params = {\n    location:{\n        hash: \"\",\n        host: \"\",\n        hostname: \"\",\n        href: \"\",\n        protocol: \"\",\n        search: \"\",\n    },\n    navigator:{\n        appCodeName: \"Mozilla\",\n        appName: \"Netscape\",\n        appVersion: \"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36\",\n        cookieEnabled: true,\n        deviceMemory: 8,\n        hardwareConcurrency: 4,\n        language: \"zh-CN\",\n        onLine: true,\n        platform: \"MacIntel\",\n        product: \"Gecko\",\n        productSub: \"20030107\",\n        userAgent: \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36\",\n        vendor: \"Google Inc.\"\n    },\n    screen:{\n        availHeight: 728,\n        availLeft: 0,\n        availTop: 0,\n        availWidth: 1366,\n        colorDepth: 24,\n        height: 768,\n        pixelDepth: 24,\n        width: 1366\n    }\n};\nObject.assign(window,params);\n\nwindow.document = document;\n\n// Js代码位置\n\nfunction get_signature(url) {\n    _signature = \"\";\n    return _signature\n}\n\n   \nconsole.log(get_signature(url));\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t3.js",
    "content": "var exports = undefined\n  , module = undefined\n  , Image = function Image() {}\n  , PluginArray = function PluginArray() {}\n  , indexedDB = {}\n  , DOMException = function DOMException() {}\n  , WebSocket = function WebSocket() {}\n  , Request = function Request() {}\n  , Headers = function Headers() {};\nvar localStorage = {\n    getItem: function getItem(x) {return null},\n    removeItem: function removeItem(x) {}\n};\nvar sessionStorage = {\n    getItem: function getItem(x) {return null},\n    removeItem: function removeItem(x) {}\n};\nvar MimeType = {\n    description: \"Native Client Executable\",\n    suffixes: \"\",\n    type: \"application/x-nacl\"\n};\nMimeType[Symbol.toStringTag] = \"MimeType\";\nvar navigator = {\n    plugins: {\n        0: {\n            0: MimeType,\n            name: \"Native Client\",\n            length: 2,\n            filename: \"internal-nacl-plugin\",\n            description: \"\",\n            length: 1\n        }\n    },\n    webdriver: false,\n    userAgent: \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36\",\n    languages: [\"zh-CN\", \"zh\"],\n    appCodeName: \"Mozilla\",\n    appName: \"Netscape\",\n    appVersion: \"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36\",\n    platform: \"Win32\"\n};\nnavigator.plugins[0][\"application/x-nacl\"] = MimeType;\nnavigator.plugins[0].__proto__.item = function item() {\n    return MimeType\n};\nnavigator.plugins[Symbol.toStringTag] = \"PluginArray\";\nnavigator.plugins[0][Symbol.toStringTag] = \"Plugin\";\nnavigator.plugins[0][0].enabledPlugin = navigator.plugins[2];\nvar CanvasRenderingContext2D_ = {\n    toString: function() {\n        return \"[object CanvasRenderingContext2D]\"\n    }\n};\nCanvasRenderingContext2D_.__proto__.fillText = function fillText() {}\n;\nCanvasRenderingContext2D_.__proto__.arc = function arc() {}\n;\nCanvasRenderingContext2D_.__proto__.stroke = function stroke() {}\n;\nvar getContext_ = {\n    toString: function() {\n        return \"[object WebGLRenderingContext]\"\n    }\n};\nvar aaaaa=0;\nvar canvas = {\n    toDataURL: function toDataURL() {\n        if(aaaaa=0){\n            aaaaa=aaaaa+1\n            return \"[native code]\"\n        }\n        return \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAQCAYAAABQrvyxAAACN0lEQVRIS8WWP0hWYRTGf98S5NBSm5sObgWt6RJR5uLQIGRC1OAWNEspOAWCIIR+4GYFDg1NEoEQ5tIghFNbBIlDLi5Bi/LIOXA8vu/1Q76v7nLvff+c9zzPc55zb4vT11F612vLxjTnz4Vl/3xoCHhaSsgTzQlncL0EcxV4C9xLtLSB58Af4AyAEvu+Pyf7P9S4BdwG5i2pogIl1mMJRUJ6qUCux8vAIvAeeABM24J2idm8ueaBCHYSmDJ2XgLPgO+Axt8AGnPmFF/srQM3PJFQGiUzKc5AIcYZDzQpoMAlH0jaLyGRHeAmsAI8BN4BrwIor28B2gac3S2r+wxAyY8YwL7kjaICnTCe2Rc7m3ay6rQfOAQ+AL+BpQAgAnZlYpIyqC4HKpBRPQfYaGKBcLbjs7fVOOcHaU4HvQZmgfvADHAtAfASiqAygBeAgGr8oNKgiwA82Xj30inNzVlwv+tQHb4MXDdAOigmqy2+zhMsKRCZjn7x8Ucqp2jiWhvNCkRCZNDPwKoNemI/gDWr8Qjgp3UTdZGPgeEagAzUz3bf/DqvFTb1e83tA6PAtwBAho7JRQBaNgZ8NaXOU0BqylvyQb4Ud66mQKce+ATcDZHdoLFt1hQ4KQHb26SAPDVhbblRgfwLEdkvzYn9J8BGxWTdGs7fDI87LGWyAtmosev43BVrkT7XrUQvFKfkgUvA30o0Sb0A6KfKO8+FDu7WphKAceCxfYD27Hsw\" + mu_() + \"AAAAAElFTkSuQmCC\"\n    },\n    getContext: function getContext(x) {\n        if (x === \"2d\") {\n            return CanvasRenderingContext2D_\n        } else {\n            return getContext_\n        }\n    }\n};\ncanvas[Symbol.toStringTag] = \"HTMLCanvasElement\";\ncanvas.getContext[Symbol.toStringTag] = \"WebGLRenderingContext\";\ngetContext_.__proto__.getExtension = function getExtension(x) {\n    return {\n        UNMASKED_RENDERER_WEBGL: 37446,\n        UNMASKED_VENDOR_WEBGL: 37445\n    }\n}\n;\ngetContext_.__proto__.getParameter = function getParameter(x) {\n    return \"Google Inc. (Intel)/ANGLE (Intel, Intel(R) UHD Graphics Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.8681)\"\n}\n;\nvar location = {\n    href: \"https://www.douyin.com/\",\n    toString: function() {\n        return location.href\n    },\n    protocol: \"https:\"\n};\nvar document = {\n    createEvent: function createEvent() {},\n    location: location,\n    cookie: \"\",\n    vlinkColor: \"\",\n    referrer: \"\",\n    fgColor: \"\",\n    dir: \"\",\n    addEventListener: function addEventListener(x) {},\n    createElement: function createElement(x) {\n        return canvas\n    }\n};\ndocument.createElement[Symbol.toStringTag] = \"HTMLImageElement\";\nvar history = {\n    length: 1,\n    scrollRestoration: \"auto\",\n    state: null\n};\nvar upload = {\n    onabort: null,\n    onerror: null,\n    onload: null,\n    onloadend: null,\n    onloadstart: null,\n    onprogress: null,\n    ontimeout: null\n};\nupload[Symbol.toStringTag] = \"XMLHttpRequestUpload\";\nvar XMLHttpRequest = function() {\n    this.onabort = null,\n    this.onerror = null,\n    this.onload = null,\n    this.onloadend = null,\n    this.onloadstart = null,\n    this.onprogress = null,\n    this.onreadystatechange = null,\n    this.ontimeout = null,\n    this.readyState = 0,\n    this.response = \"\",\n    this.responseText = \"\",\n    this.responseType = \"\",\n    this.responseURL = \"\",\n    this.responseXML = null,\n    this.status = 0,\n    this.statusText = \"\",\n    this.timeout = 0,\n    this.upload = upload,\n    this.withCredentials = false\n};\nXMLHttpRequest.prototype.open = function() {\n    function ee() {\n        this.openArgs = arguments\n    }\n    function Vn(e, t) {\n        var n = \"function\" == typeof Symbol && e[Symbol.iterator];\n        if (!n)\n            return e;\n        var r, o, i = n.call(e), a = [];\n        try {\n            for (; (void 0 === t || t-- > 0) && !(r = i.next()).done; )\n                a.push(r.value)\n        } catch (e) {\n            o = {\n                error: e\n            }\n        } finally {\n            try {\n                r && !r.done && (n = i.return) && n.call(i)\n            } finally {\n                if (o)\n                    throw o.error\n            }\n        }\n        return a\n    }\n    ;function a() {\n        for (var t = [], n = 0; n < arguments.length; n++)\n            t[n] = arguments[n];\n        var r = Vn(t, 2)\n          , o = r[0]\n          , i = r[1];\n        return this._url = i || \"\",\n        this._method = o && o.toLowerCase() || \"\",\n        ee.apply(this, t)\n    }\n    ;for (var e = [], t = 0; t < arguments.length; t++)\n        e[t] = arguments[t];\n    return a.apply(this, e)\n}\n;\nXMLHttpRequest.prototype.setRequestHeader = function() {\n    function a() {\n        for (var t = [], n = 0; n < arguments.length; n++)\n            t[n] = arguments[n];\n        return this._requestHeaders = this._requestHeaders || [],\n        this._requestHeaders.push(t)\n    }\n    ;for (var e = [], t = 0; t < arguments.length; t++)\n        e[t] = arguments[t];\n    return a.apply(this, e)\n}\n;\nXMLHttpRequest.prototype.send = function() {\n    function Wn(e, t) {\n        for (var n = 0, r = t.length, o = e.length; n < r; n++,\n        o++)\n            e[o] = t[n];\n        return e\n    }\n    ;function Vn(e, t) {\n        var n = \"function\" == typeof Symbol && e[Symbol.iterator];\n        if (!n)\n            return e;\n        var r, o, i = n.call(e), a = [];\n        try {\n            for (; (void 0 === t || t-- > 0) && !(r = i.next()).done; )\n                a.push(r.value)\n        } catch (e) {\n            o = {\n                error: e\n            }\n        } finally {\n            try {\n                r && !r.done && (n = i.return) && n.call(i)\n            } finally {\n                if (o)\n                    throw o.error\n            }\n        }\n        return a\n    }\n    ;qr = function(e, t, n) {\n        return function() {\n            for (var r = [], o = 0; o < arguments.length; o++)\n                r[o] = arguments[o];\n            if (!e)\n                return hr;\n            var i = e[t]\n              , a = n.apply(void 0, Wn([i], Vn(r)))\n              , s = a;\n            return Yn(s) && (s = function() {\n                for (var e = [], t = 0; t < arguments.length; t++)\n                    e[t] = arguments[t];\n                try {\n                    return a.apply(this, e)\n                } catch (t) {\n                    return Yn(i) && i.apply(this, e)\n                }\n            }\n            ),\n            e[t] = s,\n            function(n) {\n                n && s !== e[t] || (e[t] = i)\n            }\n        }\n    }\n    ;\n    function Yn(e) {\n        return \"function\" == typeof e\n    }\n    ;Jr = function(e) {\n        return qr(e, \"onreadystatechange\", (function(t, n, r, o, i) {\n            return function() {\n                for (var a = [], s = 0; s < arguments.length; s++)\n                    a[s] = arguments[s];\n                return 4 === this.readyState && o && o({\n                    name: Gr,\n                    type: \"get\",\n                    event: Wr(e, n, r, i)\n                }),\n                t && t.apply(this, a)\n            }\n        }\n        ))\n    }\n    ;\n    n = function(t) {\n        r.chechIsReady() ? e.prototype.sendEvent.call(r, t) : r.preQueue.push(t)\n    }\n    ;\n    function ew() {\n        var t = this\n          , n = this.openArgs\n          , r = arguments\n          , o = n[0] || \"GET\"\n          , i = new URL(n[1],window.location.href);\n    }\n    ;function a() {\n        for (var i = [], a = 0; a < arguments.length; a++)\n            i[a] = arguments[a];\n        return Jr(this)({}, null, n, \"https://www.douyin.com/\"),\n        this._start = Date.now(),\n        this._data = null == i ? void 0 : i[0],\n        ew.apply(this, i)\n    }\n    ;for (var e = [], t = 0; t < arguments.length; t++)\n        e[t] = arguments[t];\n    return a.apply(this, e)\n}\n;\nXMLHttpRequest.prototype.overrideMimeType = function overrideMimeType() {}\n;\nXMLHttpRequest.prototype[Symbol.toStringTag] = \"XMLHttpRequest\";\n\nvar window = {\n    queueMicrotask: queueMicrotask,\n    setTimeout: setTimeout,\n    setInterval: setInterval,\n    clearTimeout: clearTimeout,\n    clearInterval: clearInterval,\n    TextEncoder: TextEncoder,\n    URLSearchParams: URLSearchParams,\n    URL: URL,\n    WebAssembly: WebAssembly,\n    //WeakRef: WeakRef,\n    //FinalizationRegistry: FinalizationRegistry,\n    Atomics: Atomics,\n    SharedArrayBuffer: SharedArrayBuffer,\n    isNaN: isNaN,\n    isFinite: isFinite,\n    eval: eval,\n    unescape: unescape,\n    escape: escape,\n    encodeURIComponent: encodeURIComponent,\n    encodeURI: encodeURI,\n    decodeURIComponent: decodeURIComponent,\n    decodeURI: decodeURI,\n    Reflect: Reflect,\n    Proxy: Proxy,\n    WeakSet: WeakSet,\n    WeakMap: WeakMap,\n    Set: Set,\n    BigInt: BigInt,\n    Map: Map,\n    DataView: DataView,\n    BigInt64Array: BigInt64Array,\n    BigUint64Array: BigUint64Array,\n    Uint8ClampedArray: Uint8ClampedArray,\n    Float64Array: Float64Array,\n    Float32Array: Float32Array,\n    Int32Array: Int32Array,\n    Uint32Array: Uint32Array,\n    Int16Array: Int16Array,\n    Uint16Array: Uint16Array,\n    Int8Array: Int8Array,\n    Uint8Array: Uint8Array,\n    ArrayBuffer: ArrayBuffer,\n    Intl: Intl,\n    Math: Math,\n    JSON: JSON,\n    URIError: URIError,\n    TypeError: TypeError,\n    SyntaxError: SyntaxError,\n    ReferenceError: ReferenceError,\n    RangeError: RangeError,\n    EvalError: EvalError,\n    Error: Error,\n    Promise: Promise,\n    Date: Date,\n    Symbol: Symbol,\n    String: String,\n    Boolean: Boolean,\n    undefined: undefined,\n    NaN: NaN,\n    Infinity: Infinity,\n    parseInt: parseInt,\n    parseFloat: parseFloat,\n    Number: Number,\n    Array: Array,\n    Function: Function,\n    Object: Object,\n    navigator: navigator,\n    location: location,\n    document: document,\n    history: history,\n    indexedDB: indexedDB,\n    localStorage: localStorage,\n    sessionStorage: sessionStorage,\n    RegExp: RegExp,\n    XMLHttpRequest: XMLHttpRequest,\n    fetch: function fetch() {return \"[native code]\"},\n    console: console,\n    HTMLElement: function HTMLElement() {},\n    chrome: {\n        \"app\": {\n            \"isInstalled\": false,\n            \"InstallState\": {\n                \"DISABLED\": \"disabled\",\n                \"INSTALLED\": \"installed\",\n                \"NOT_INSTALLED\": \"not_installed\"\n            },\n            \"RunningState\": {\n                \"CANNOT_RUN\": \"cannot_run\",\n                \"READY_TO_RUN\": \"ready_to_run\",\n                \"RUNNING\": \"running\"\n            }\n        },\n        \"runtime\": {\n            connect: function connect() {return \"[native code]\"},\n            \"OnInstalledReason\": {\n                \"CHROME_UPDATE\": \"chrome_update\",\n                \"INSTALL\": \"install\",\n                \"SHARED_MODULE_UPDATE\": \"shared_module_update\",\n                \"UPDATE\": \"update\"\n            },\n            \"OnRestartRequiredReason\": {\n                \"APP_UPDATE\": \"app_update\",\n                \"OS_UPDATE\": \"os_update\",\n                \"PERIODIC\": \"periodic\"\n            },\n            \"PlatformArch\": {\n                \"ARM\": \"arm\",\n                \"ARM64\": \"arm64\",\n                \"MIPS\": \"mips\",\n                \"MIPS64\": \"mips64\",\n                \"X86_32\": \"x86-32\",\n                \"X86_64\": \"x86-64\"\n            },\n            \"PlatformNaclArch\": {\n                \"ARM\": \"arm\",\n                \"MIPS\": \"mips\",\n                \"MIPS64\": \"mips64\",\n                \"X86_32\": \"x86-32\",\n                \"X86_64\": \"x86-64\"\n            },\n            \"PlatformOs\": {\n                \"ANDROID\": \"android\",\n                \"CROS\": \"cros\",\n                \"LINUX\": \"linux\",\n                \"MAC\": \"mac\",\n                \"OPENBSD\": \"openbsd\",\n                \"WIN\": \"win\"\n            },\n            \"RequestUpdateCheckStatus\": {\n                \"NO_UPDATE\": \"no_update\",\n                \"THROTTLED\": \"throttled\",\n                \"UPDATE_AVAILABLE\": \"update_available\"\n            }\n        }\n    }\n};\nwindow[Symbol.toStringTag] = \"Window\";\nnavigator[Symbol.toStringTag] = \"Navigator\";\nlocation[Symbol.toStringTag] = \"Location\";\ndocument[Symbol.toStringTag] = \"HTMLDocument\";\nhistory[Symbol.toStringTag] = \"History\";\nindexedDB[Symbol.toStringTag] = \"IDBFactory\";\nlocalStorage[Symbol.toStringTag] = \"Storage\";\nsessionStorage[Symbol.toStringTag] = \"Storage\";\nObject.prototype.constructor.getOwnPropertyNames = function(x) {\n    if (toString.call(x) == \"[object Navigator]\") {\n        return []\n    } else {\n        return Object.keys(x)\n    }\n}\n\nfunction mu_() {\n    var e = [];\n    var a = \"123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n    for (var b = 0; b < 28; b++) {\n        e[b] = a[Math.floor(Math.random() * a.length)]\n    }\n    ;return e.join('')\n}\n\nObject.freeze(navigator);\nObject.freeze(document);\nObject.freeze(location);\nObject.freeze(history);\nObject.freeze(indexedDB);\nObject.freeze(localStorage);\nObject.freeze(sessionStorage);\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t4.js",
    "content": "// 从浏览器直接扒各种参数环境的脚本,忘记当时转谁的了，请联系我增加署名\n\nconsole.log(make_all()) // 使用时候解开该行注释，然后将生成的代码都放到控制台中直接执行，复制生成的字符出即可。\nfunction get_all(){\n    function generatecode4v(name_, key, v, o, be_values) {\n        if (be_values.indexOf(key) == -1){\n            if (typeof (v) == \"object\") {\n                if (v == null) {\n                    return `${name_}[\"${key}\"] = null;\\r\\n`\n                }\n                if (o == v){\n                    return `${name_}[\"${key}\"] = ${name_};\\r\\n`\n                }\n                try {\n                    return `${name_}[\"${key}\"] = _vPxy(new class ${v.constructor.name}{}, \"${key}\");\\r\\n`\n                } catch (error) {\n                    return `${name_}[\"${key}\"] = \"----------------------------------------------------------------\";\\r\\n`\n                }\n            }\n            if (typeof (v) == \"string\") {\n                if (v.indexOf('\"') == -1){\n                    return `${name_}[\"${key}\"] = \"${v}\";\\r\\n`\n                }else if (v.indexOf(\"'\") == -1){\n                    return `${name_}[\"${key}\"] = '${v}';\\r\\n`\n                }else{\n                    return `${name_}[\"${key}\"] = \\`${v}\\`;\\r\\n`\n                }\n            }\n            if (typeof (v) == \"function\") {\n                return `${name_}[\"${key}\"] = function ${v.name}(){_vLog('--- func(*) --- ${v.name}');debugger;};   safefunction(${name_}[\"${key}\"]);\\r\\n`\n            }\n        }else{\n            return `${name_}[\"${key}\"] = ${JSON.stringify(v)};\\r\\n`\n        }\n        return `${name_}[\"${key}\"] = ${v};\\r\\n`\n    }\n    function generatecode4v1(name_, key, v, o, be_values) {\n        if (be_values.indexOf(key) == -1){\n            if (typeof (v) == \"object\") {\n                if (v == null) {\n                    return `${name_}.__proto__[\"${key}\"] = null;\\r\\n`\n                }\n                try {\n                    return `${name_}.__proto__[\"${key}\"] = _vPxy(new class ${v.constructor.name}{}, \"${key}\");\\r\\n`\n                } catch (error) {\n                    return `${name_}.__proto__[\"${key}\"] = \"----------------------------------------------------------------\";\\r\\n`\n                }\n            }\n            if (typeof (v) == \"string\") {\n                if (v.indexOf('\"') == -1){\n                    return `${name_}.__proto__[\"${key}\"] = \"${v}\";\\r\\n`\n                }else if (v.indexOf(\"'\") == -1){\n                    return `${name_}.__proto__[\"${key}\"] = '${v}';\\r\\n`\n                }else{\n                    return `${name_}.__proto__[\"${key}\"] = \\`${v}\\`;\\r\\n`\n                }\n            }\n            if (typeof (v) == \"function\") {\n                return `${name_}.__proto__[\"${key}\"] = function ${v.name}(){_vLog('--- func(*) --- ${v.name}');debugger;};   safefunction(${name_}[\"${key}\"]);\\r\\n`\n            }\n            if (name_ == 'document' && key == 'all'){\n                return `${name_}.__proto__[\"${key}\"] = undefined;\\r\\n`\n            }\n            if (name_ == 'document' && key == 'body'){\n                return `${name_}.__proto__[\"${key}\"] = _vPxy(new class HTMLBodyElement{}, \"body\");\\r\\n`\n            }\n        }else{\n            return `${name_}.__proto__[\"${key}\"] = ${JSON.stringify(v)};\\r\\n`\n        }\n        return `${name_}.__proto__[\"${key}\"] = ${v};\\r\\n`\n    }\n    function generate4example(example, name_, skips, be_values) {\n        var code = \"\";\n        var protos = {}\n        if (typeof (example) == \"object\" && example.prototype == undefined) {\n            for (let key in example.__proto__) {\n                protos[key] = true;\n            }\n            for (let key in example) {\n                if (protos[key] == undefined) {\n                    if (key && skips.indexOf(key) == -1){\n                        try{\n                           code += generatecode4v(name_, key, example[key], example, be_values);\n                        }catch(e){\n                            console.log('========== error ==========')\n                            console.log(key)\n                            console.log(e)\n                        }\n                    }\n                }\n            }\n        }\n        return alignment_safefunction(alignment(code));\n    }\n    function generate4Prototype(example, name_, skips, be_values) {\n        var code = \"\";\n        if (typeof (example) == \"object\" && example.prototype == undefined) {\n            for (let key in example.__proto__) {\n                if (skips.indexOf(key) == -1){\n                    try{\n                        code += generatecode4v1(name_, key, example[key], example, be_values);\n                    }catch(e){\n                        console.log('========== error ==========')\n                        console.log(key)\n                        console.log(e)\n                    }\n                }\n            }\n        }\n        return alignment_safefunction(alignment(code))\n    }\n    function alignment(str){\n        var max_protolen = 0\n        if (str.trim().length == 0){\n            return str\n        }\n        var mch = str.match(/(\\[\"[^\"]+\"\\]) *=/g)\n        if (!(mch)){\n            return str\n        }\n        mch.map(function(e){\n            if (e.length > max_protolen){\n                max_protolen = e.length\n            }\n        })\n        return str.replace(/(\\[\"[^\"]+\"\\]) *=/g, function(_, e){\n            return e + Array(max_protolen-e.length-1).fill(\" \").join(\"\") + '='\n        })\n    }\n    function alignment_safefunction(str){\n        var max_protolen = 0\n        if (str.trim().length == 0){\n            return str\n        }\n        var mch = str.match(/(=[^=]+); *safefunction/g)\n        if (!(mch)){\n            return str\n        }\n        mch.map(function(e){\n            if (e.length > max_protolen){\n                max_protolen = e.length\n            }\n        })\n        return str.replace(/(=[^=]+;) *safefunction/g, function(_, e){\n            return e + Array(max_protolen-e.length-14).fill(\" \").join(\"\") + 'safefunction'\n        })\n    }\n    function vall(example, name_, skips, be_values){\n        skips = skips || []\n        be_values = be_values || []\n        var protostr = generate4Prototype(example, name_, skips, be_values)\n        var objectstr = generate4example(example, name_, skips, be_values)\n        return protostr + objectstr\n    }\n    vall.generate4example = generate4example\n    vall.generate4Prototype = generate4Prototype\n    // placeholder1\n}\nfunction make_all(){\n    var ret;\n    ret = Cilame + '\\r\\n'\n    ret += get_all + '\\r\\n'\n    ret = ret.replace('// placeholder1', `\n    console.log(\n    Cilame + \"\\\\r\\\\n\" +\n    \"Cilame()\\\\r\\\\n\" +\n    vall(window,                 \"window\",               ${JSON.stringify(Cilame())}.concat(['_vLog', '_vPxy','setTimeout', 'setInterval', 'clearInterval', 'clearTimeout'])) +\n    vall(document,               \"document\",             ['cookie', 'addEventListener', 'dispatchEvent', 'removeEventListener', \"createElement\", \"getElementsByName\"]) +\n    vall(Node.prototype,         \"Node.prototype\",       [\"location\", 'addEventListener', 'dispatchEvent', 'removeEventListener']) +\n    vall(navigator,              \"navigator\",            ['connection', 'getBattery', 'mimeTypes'],    ['languages']) +\n    vall(window.location,        \"window.location\") +\n    vall(window.localStorage,    \"window.localStorage\",   [\"clear\", \"getItem\", \"key\", \"removeItem\", \"setItem\", \"length\"]) +\n    vall(window.sessionStorage,  \"window.sessionStorage\", [\"clear\", \"getItem\", \"key\", \"removeItem\", \"setItem\", \"length\"]) +\n\\`for (let key in navigator.__proto__) {\n    navigator[key] = navigator.__proto__[key];\n    if (typeof (navigator.__proto__[key]) != \"function\") {\n        navigator.__proto__.__defineGetter__(key, function() {\n            debugger ;var e = new Error();\n            e.name = \"TypeError\";\n            e.message = \"Illegal invocation\";\n            e.stack = \"VM988:1 Uncaught TypeError: Illegal invocation \\\\\\\\r\\\\\\\\n at <anonymous>:1:19\";\n            throw e;\n        });\n    }\n}\nwindow                = VmProxyB(window,                \"window\",               true) // 这三个暂时不打印获取的结果\nwindow.document       = VmProxyB(window.document,       \"window.document\",      true) // 这三个暂时不打印获取的结果\nwindow.navigator      = VmProxyB(window.navigator,      \"window.navigator\",     true) // 这三个暂时不打印获取的结果\nwindow.location       = VmProxyB(window.location,       \"window.location\")\nwindow.localStorage   = VmProxyB(window.localStorage,   \"window.localStorage\")\nwindow.sessionStorage = VmProxyB(window.sessionStorage, \"window.sessionStorage\")\nwindow.XMLHttpRequest = VmProxyB(window.XMLHttpRequest, \"window.XMLHttpRequest\")\nwindow.indexedDB      = VmProxyB(window.indexedDB,      \"window.indexedDB\")\n\n// 该处用于一些定制的挂钩处理，绕过 Function 或 eval 函数内一些检测使用的，视情况修改\nfunction temp_hookFunc(H){\n    eval(\\\\\\`\n    _v\\\\\\${H.split('.').pop()} = \\\\\\${H}\n    window.\\\\\\${H} = function \\\\\\${H.split('.').pop()}(){\n        if (start){\n            console.log('-------------------- \\\\\\${H}(*) --------------------')\n            console.log(arguments[0])\n        }\n        if (arguments[0].indexOf('__dirname') != -1 || arguments[0].indexOf('__filename') != -1){\n            return function (){}\n        }\n        return _v\\\\\\${H.split('.').pop()}.apply(this, arguments)\n    }\n    safefunction(window.\\\\\\${H})\n    \\\\\\`)\n}\ntemp_hookFunc('Function')\n// hookFunc('Function')\n\n// 目前就使用这样的方式将 setTimeout/setInterval 钩住使用，这两个函数都有点特殊，需要特别关注\nwindow.setTimeout = safefunction(function setTimeout(func, time){ \n    if ((time||0) < 100){  console.log('  [setTimeout] immediately.', func); func() }\n    else{ console.log('  [setTimeout] not run. cos interval over 100:', time) }\n})\nwindow.setInterval = safefunction(function setInterval(func, time){\n    if ((time||0) < 100){ console.log('  [setInterval] immediately (only run once).', func); func() }\n    else{ console.log('  [setInterval] not run. cos interval over 100:', time) }\n})\nhookFunc(\"clearInterval\")\nhookFunc(\"clearTimeout\")\nhookFunc(\"Number\")\nhookFunc(\"parseFloat\")\nhookFunc(\"parseInt\")\nhookFunc(\"Symbol\")\nhookFunc(\"Error\")\nhookFunc(\"ArrayBuffer\")\nhookFunc(\"Uint8Array\")\nhookFunc(\"Int8Array\")\nhookFunc(\"Uint16Array\")\nhookFunc(\"Int16Array\")\nhookFunc(\"Uint32Array\")\nhookFunc(\"Int32Array\")\nhookFunc(\"Float32Array\")\nhookFunc(\"Float64Array\")\nhookFunc(\"Uint8ClampedArray\")\nhookFunc(\"BigUint64Array\")\nhookFunc(\"BigInt64Array\")\nhookFunc(\"decodeURI\")\nhookFunc(\"decodeURIComponent\")\nhookFunc(\"encodeURI\")\nhookFunc(\"encodeURIComponent\")\nhookFunc(\"escape\")\nhookFunc(\"unescape\")\nhookFunc(\"eval\")\nhookFunc(\"isFinite\")\nhookFunc(\"isNaN\")\nhookFunc(\"SharedArrayBuffer\")\n// 一般这种可以处理 new RegExp(*) 系列的挂钩。\n// 如果是直接 /*/ 挂钩不上，不过这种是可以从代码里面明白的找到，这种无法混淆\n// 正则的挂钩比较特殊，需要在实例化的时候挂钩上实例对象的函数，所以挂钩处理如下\n;(function (){\n    var _vRegExp = RegExp\n    window.RegExp = function RegExp(){\n        var ostart = start\n        if (ostart){\n            console.log('-------------------- RegExp(*) --------------------')\n            console.log(arguments[0])\n        }\n        start = false\n        fakeRegExpObj = _vRegExp.apply(this, arguments)\n        _fakeRegExp_test = fakeRegExpObj.test\n        fakeRegExpObj.test = safefunction(function test() {\n            if (start){\n                console.log('-------------------- RegExp.prototype.test(*) --------------------')\n                console.log(this+'', '==>', arguments[0])\n            }\n            return _fakeRegExp_test.apply(this, arguments)\n        })\n        _fakeRegExp_exec = fakeRegExpObj.exec\n        fakeRegExpObj.exec = safefunction(function exec() {\n            if (start){\n                console.log('-------------------- RegExp.prototype.exec(*) --------------------')\n                console.log(this+'', '==>', arguments[0])\n            }\n            return _fakeRegExp_exec.apply(this, arguments)\n        })\n        start = ostart\n        return fakeRegExpObj\n    }\n    safefunction(window.RegExp)\n})()\n// 挂钩 Object 的各种函数\nhookFuncObject(\"Object.assign\")\nhookFuncObject(\"Object.getOwnPropertyDescriptor\")\nhookFuncObject(\"Object.getOwnPropertyDescriptors\")\nhookFuncObject(\"Object.getOwnPropertyNames\")\nhookFuncObject(\"Object.getOwnPropertySymbols\")\nhookFuncObject(\"Object.is\")\nhookFuncObject(\"Object.preventExtensions\")\nhookFuncObject(\"Object.seal\")\nhookFuncObject(\"Object.create\")\nhookFuncObject(\"Object.defineProperties\")\nhookFuncObject(\"Object.defineProperty\")\nhookFuncObject(\"Object.freeze\")\nhookFuncObject(\"Object.getPrototypeOf\")\nhookFuncObject(\"Object.setPrototypeOf\")\nhookFuncObject(\"Object.isExtensible\")\nhookFuncObject(\"Object.isFrozen\")\nhookFuncObject(\"Object.isSealed\")\nhookFuncObject(\"Object.keys\")\nhookFuncObject(\"Object.entries\")\nhookFuncObject(\"Object.values\")\n\n// 为了保证函数内部的随机函数在一定程度上固定，这里将 random hook 成一个伪随机函数，保证某些函数计算的稳定。\nMath.random = (function(seed) {\n    return (function random() {\n        seed = (seed * 9301 + 49297) % 233280, rnd = seed / 233280.0\n        console.log('  [fake Math.random]', rnd)\n        return rnd\n    })\n})(0)\nhookFunc(\"Date.parse\")\nhookFuncReturn(\"Date.prototype.valueOf\")\nhookFuncReturn(\"Date.prototype.getTime\")\n\nstart = true  // 主要的 VmProxyB 的log开关\nstart1 = true // 一些未被实现的 _vPxy(new class Unknown{}) 的 Proxy 打印日志，让输出更清晰\n\n\n\n\n\n\n\n// 这里插入浏览器给你的代码\n// $placeholder_code\n\nrunloads()\n\n\n\n\n\n\n\n\n// 这里往后插入你自己的代码，用于导出/编辑自己使用的函数\n\\`)`)\n    ret += '\\r\\n'\n    ret += 'get_all()\\r\\n// 将生成的代码全部拷贝到 chrome 控制台执行即可'\n    return ret\n}\n\n\n\n\n\n\n\n// 以下就是就是一个补环境的简单处理，现在还不成熟，后面慢慢补\n\nfunction Cilame(){\n    // 生成一些重要的参数，比如 screen Screen 这种对应的系统对象\n    // 这些系统对象原型结构稍微有点绕，统一成下面模式就行\n    ;(function(){\n        const $toString = Function.toString;\n        const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));\n        const myToString = function() {\n            return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);\n        };\n        function set_native(func, key, value) {\n            Object.defineProperty(func, key, {\n                \"enumerable\": false,\n                \"configurable\": true,\n                \"writable\": true,\n                \"value\": value\n            })\n        };\n        delete Function.prototype['toString'];\n        set_native(Function.prototype, \"toString\", myToString);\n        set_native(Function.prototype.toString, myFunction_toString_symbol, \"function toString() { [native code] }\");\n        ;(typeof global=='undefined'?window:global).safefunction = function(func){\n            set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol,func.name || ''}() { [native code] }`);\n            return func\n        };(typeof global=='undefined'?window:global).safefunction_with_name = function(func,name){\n            set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol,name || ''}() { [native code] }`);\n            return func\n        };\n        function make_constructor(name, Name, name_inject_objs, Name_inject_objs, proto, config){\n            config = config !== undefined?config:{}\n            var allow_illegal = config['allow_illegal']\n            var illegalstr = (!allow_illegal)?'throw new TypeError(\"Illegal constructor\");':''\n            var evalstr = `\n            var ${name}Constructor = function ${Name==\"WindowProperties\"?\"EventTarget\":Name}() { ${illegalstr} }\n            safefunction(${name}Constructor);\n            var ${name}Prototype = (proto!==undefined?proto:{});\n            Object.defineProperties(${name}Prototype, {\n                constructor: { value: ${name}Constructor, writable: true, configurable: true },\n                [Symbol.toStringTag]: { value: \"${Name}\", configurable: true }\n            });\n            ${name}Constructor.prototype = ${name}Prototype;\n            var ${Name} = function ${Name}() {}\n            safefunction(${Name});\n            var ${name} = new ${Name}();\n            ${name}.__proto__ = ${name}Prototype;\n            __cilame__['n'][\"${name}\"] = ${name}\n            __cilame__['N'][\"${Name}\"] = ${Name}\n            if (name_inject_objs.length){ name_inject_objs.map(function(e){ Object.defineProperty(e, \"${name}\", { configurable: true, writable: true, value: ${name} }); }) }\n            if (Name_inject_objs.length){ Name_inject_objs.map(function(e){ Object.defineProperty(e, \"${Name}\", { configurable: true, writable: true, value: ${name}Constructor }); }) }\n            `\n            eval(evalstr)\n        }\n        ;(typeof global=='undefined'?window:global).make_constructor = make_constructor\n        ;(typeof global=='undefined'?window:global).start = false\n        ;(typeof global=='undefined'?window:global).start1 = false\n        ;(typeof global=='undefined'?window:global)._vLog = function _vLog(){ if (start1){ \n            console.log.apply(console.log, [].slice.call(arguments))\n        }}\n        ;(typeof global=='undefined'?window:global).myparselog = function myparselog(V){\n            return typeof V=='string'?\n                V.length > 100?V.slice(0,100) + '... <DONSHOW MORETHAN 100 LENGTH>':V\n            :\n            typeof V=='number'?V:\n            typeof V=='function'?V:\n            typeof V=='undefined'?undefined:\n            typeof V=='boolean'?V:\n            `<DONTSHOW TYPE:${typeof V}>`\n        }\n        ;(typeof global=='undefined'?window:global)._vPxy = function(G, M){\n            var _vLog = (typeof global=='undefined'?window:global)._vLog || console.log\n            function LS(T, M, F){ return `  [UnProxy] ${M}[${T.constructor.name}].(Prxoy)${F} ==>>`} // 未知对象取值处理时的检查操作\n            return new Proxy(G, {\n                apply:                    function(T, A, L){    _vLog(LS(G, M, 'apply') );                    return Reflect.apply(T, A, L) },\n                construct:                function(T, L, N){    _vLog(LS(G, M, 'construct') );                return Reflect.construct(T, L, N) },\n                deleteProperty:           function(T, P){       _vLog(LS(G, M, 'deleteProperty'), P);         return Reflect.deleteProperty(T, P) },\n                get:                      function(T, P, R){    _vLog(LS(G, M, 'get'), P);                    return Reflect.get(T, P, R) },\n                // defineProperty:           function(T, P, A){    _vLog(LS(G, M, 'defineProperty') );           return Reflect.defineProperty(T, P, A) },\n                // getOwnPropertyDescriptor: function(T, P){       _vLog(LS(G, M, 'getOwnPropertyDescriptor') ); return Reflect.getOwnPropertyDescriptor(T, P) },\n                getPrototypeOf:           function(T){          _vLog(LS(G, M, 'getPrototypeOf') );           return Reflect.getPrototypeOf(T) },\n                has:                      function(T, P){       _vLog(LS(G, M, 'has'), P);                    return Reflect.has(T, P) },\n                isExtensible:             function(T){          _vLog(LS(G, M, 'isExtensible') );             return Reflect.isExtensible(T) },\n                ownKeys:                  function(T){          _vLog(LS(G, M, 'ownKeys') );                  return Reflect.ownKeys(T) },\n                preventExtensions:        function(T){          _vLog(LS(G, M, 'preventExtensions') );        return Reflect.preventExtensions(T) },\n                set:                      function(T, P, V, R){ _vLog(LS(G, M, 'set'), P, myparselog(V) );    return Reflect.set(T, P, V, R) },\n                setPrototypeOf:           function(T, P){       _vLog(LS(G, M, 'setPrototypeOf'), P);         return Reflect.setPrototypeOf(T, P) },\n            })\n        }\n        function logA(tag, G_or_S, objectname, propertyname, value){\n            console.table([{tag, G_or_S, objectname, propertyname,value}], [\"tag\",\"G_or_S\",\"objectname\",\"propertyname\",\"value\"]);\n        }\n        function logB(tag, GS, objectname, propertyname, value){\n            var pro = `[VmProxy] ${tag} ${GS} [${objectname}] \"${typeof propertyname=='symbol'?'symbol':propertyname}\"`\n            var emp = function (n){ return n>0?Array(n).fill('=').join('').replace(/=/g, ' '):'' };\n            console.info(pro + emp(70-pro.length), value);\n        }\n        function VmProxy(logger, object_, titlename, dont_log_value){\n            return new Proxy(object_, {\n                get (target, property) { \n                    if (start){\n                        logger(titlename, \"Get >>\", target.constructor.name, property, myparselog(target[property]));\n                    }\n                    return target[property];\n                },\n                set (target, property, value) {\n                    if (start){\n                        logger(titlename, \"Set <<\", target.constructor.name, property, myparselog(value));\n                    }\n                    target[property] = value;\n                }\n            });\n        };\n        var VmProxyA = function (){return VmProxy.apply(this, [logA].concat([].slice.call(arguments)))}\n        var VmProxyB = function (){return VmProxy.apply(this, [logB].concat([].slice.call(arguments)))}\n        ;(typeof global=='undefined'?window:global).VmProxyA = VmProxyA\n        ;(typeof global=='undefined'?window:global).VmProxyB = VmProxyB\n        ;(typeof global=='undefined'?window:global).hookFunc = function hookFunc(H){\n            eval(`\n            _v${H.split('.').pop()} = ${H}\n            window.${H} = function ${H.split('.').pop()}(){\n                if (start){\n                    console.log('-------------------- ${H}(*) --------------------')\n                    console.log(myparselog(arguments[0]))\n                }\n                return _v${H.split('.').pop()}.apply(this, arguments)\n            }\n            safefunction(window.${H})\n            `)\n        }\n        ;(typeof global=='undefined'?window:global).hookFuncObject = function hookFuncObject(H){\n            eval(`\n            _v${H.split('.').pop()} = ${H}\n            window.${H} = function ${H.split('.').pop()}(){\n                if (start){\n                    console.log('-------------------- ${H}(*) --------------------')\n                    console.log(arguments)\n                }\n                return _v${H.split('.').pop()}.apply(this, arguments)\n            }\n            safefunction(window.${H})\n            `)\n        }\n        ;(typeof global=='undefined'?window:global).hookFuncReturn = function hookFuncReturn(H){\n            eval(`\n            _v${H.split('.').pop()} = ${H}\n            window.${H} = function ${H.split('.').pop()}(){\n                var v = _v${H.split('.').pop()}.apply(this, arguments)\n                if (start){\n                    console.log('-------------------- ${H}(*) --------------------')\n                    console.log(myparselog(v))\n                }\n                return v\n            }\n            safefunction(window.${H})\n            `)\n        }\n    })();\n    // 将核心结构初始化，也就是 window navigator document 等初始化处理好\n    var __cilame__ = { 'n':{}, 'N':{}, 'c':{} } // 临时存储空间, n 为 new 对象, N 为原始方法.\n    var GL = _global = (typeof global=='undefined'?window:global)\n    make_constructor(\"eventTarget\", \"EventTarget\", [], [GL], undefined, { allow_illegal: true })\n    EventTarget.prototype.listeners = {};\n    EventTarget.prototype.addEventListener = safefunction(function addEventListener(type, callback) {\n        console.log('  [addEventListener]', type, callback)\n        if(!(type in this.listeners)) { this.listeners[type] = []; }\n        this.listeners[type].push(callback);\n    })\n    EventTarget.prototype.removeEventListener = safefunction(function removeEventListener(type, callback) {\n        console.log('  [removeEventListener]', type, callback)\n        if(!(type in this.listeners)) { return; }\n        var stack = this.listeners[type];\n        for(var i = 0, l = stack.length; i < l; i++) { if(stack[i] === callback){ stack.splice(i, 1); return this.removeEventListener(type, callback); } }\n    })\n    EventTarget.prototype.dispatchEvent = safefunction(function dispatchEvent(event) {\n        console.log('  [dispatchEvent]', event)\n        if(!(event.type in this.listeners)) { return; }\n        var stack = this.listeners[event.type];\n        event.target = this;\n        for(var i = 0, l = stack.length; i < l; i++) { stack[i].call(this, event); }\n    })\n    make_constructor(\"windowProperties\",    \"WindowProperties\", [], [], new EventTarget, { allow_illegal: true })\n    make_constructor(\"window\",              \"Window\", [GL], [GL],       __cilame__['n']['windowProperties']) // WindowProperties 没有注入 window 环境\n    window[\"TEMPORARY\"]  = 0;\n    window[\"PERSISTENT\"] = 1;\n    window = new Proxy(window, {\n        get: function(a,b,c){ return a[b] || global[b] },\n        set: function(a,b,c){ return a[b] = global[b] = c }\n    })\n    // window 生成之后将 global 内部的常用函数直接传到 window 里面\n    var Gkeys = Object.getOwnPropertyNames(global), exclude = ['global', 'process', '_global']\n    for (var i = 0; i < Gkeys.length; i++) {\n        if (exclude.indexOf(Gkeys[i]) == -1){ window[Gkeys[i]] = global[Gkeys[i]] }\n    }\n    var EN = normal_env = [window, GL]\n    make_constructor(\"navigator\",   \"Navigator\",    EN, EN)\n    window.clientInformation = navigator\n    // 处理 document 初始化\n    make_constructor(\"_vNode\",      \"Node\",         [], EN, new EventTarget)\n    make_constructor(\"_vDocument\",  \"Document\",     [], EN, __cilame__[\"n\"]['_vNode'], { allow_illegal: true })\n    make_constructor(\"document\",    \"HTMLDocument\", EN, EN, __cilame__[\"n\"]['_vDocument'])\n    ;(function(){\n        'use strict';\n        var cookie_cache = document.cookie = \"\";\n        Object.defineProperty(document, 'cookie', {\n            get: function() {\n                console.log('==>> Get Cookie', cookie_cache);\n                return cookie_cache;\n            },\n            set: function(val) {\n                console.log('<<== Set Cookie', val);\n                var cookie = val.split(\";\")[0];\n                var ncookie = cookie.split(\"=\");\n                var flag = false;\n                var cache = cookie_cache.split(\"; \");\n                cache = cache.map(function(a) {\n                    if (a.split(\"=\")[0] === ncookie[0]) {\n                        flag = true;\n                        return cookie;\n                    }\n                    return a;\n                })\n                cookie_cache = cache.join(\"; \");\n                if (!flag) {\n                    cookie_cache += cookie + \"; \";\n                }\n                return cookie_cache;\n            }\n        });\n        global.init_cookie = function init_cookie(str){\n            cookie_cache = str\n        }\n    })();\n    // 处理 location 初始化，以及绑定 document\n    make_constructor(\"location\",    \"Location\",     EN, EN)\n    location[\"ancestorOrigins\"] = _vPxy(new (class DOMStringList {}), \"location.ancestorOrigins\");\n    location[\"assign\"]          = function assign(U){  console.log(\"  [location] assign\", U);};  safefunction(location[\"assign\"]);\n    location[\"reload\"]          = function reload(){   console.log(\"  [location] reload\");};     safefunction(location[\"reload\"]);\n    location[\"replace\"]         = function replace(U){ console.log(\"  [location] replace\", U);}; safefunction(location[\"replace\"]);\n    Object.defineProperty(location, 'href', {\n        get: function(){\n            return location.protocol + \"//\" + location.host + (location.port ? \":\" + location.port : \"\") + location.pathname + location.search + location.hash;\n        },\n        set: function(href){\n            var a = href.match(/([^:]+:)\\/\\/([^/:?#]+):?(\\d+)?([^?#]*)?(\\?[^#]*)?(#.*)?/);\n            location.protocol = a[1] ? a[1] : \"\";\n            location.host     = a[2] ? a[2] : \"\";\n            location.port     = a[3] ? a[3] : \"\";\n            location.pathname = a[4] ? a[4] : \"\";\n            location.search   = a[5] ? a[5] : \"\";\n            location.hash     = a[6] ? a[6] : \"\";\n            location.hostname = location.host;\n            location.origin   = location.protocol + \"//\" + location.host + (location.port ? \":\" + location.port : \"\");\n        }\n    });\n    document.location = location\n    // 处理 localStorage 和 sessionStorage 的初始化\n    function Storage(){}\n    Storage.prototype.clear      = function clear(){            console.log('  [Storage] clear');           var self = this; Object.keys(self).forEach(function (key) { self[key] = undefined; delete self[key]; }); }\n    Storage.prototype.getItem    = function getItem(key){       var r = (this.hasOwnProperty(key)?String(this[key]):null); console.log('  [Storage] getItem',key,myparselog(r)); return r}\n    Storage.prototype.setItem    = function setItem(key, val){  console.log('  [Storage] setItem',key,val); this[key] = (val === undefined)?null:String(val) }\n    Storage.prototype.key        = function key(i){             console.log('  [Storage] key',i);           return Object.keys(this)[i||0];} \n    Storage.prototype.removeItem = function removeItem(key){    console.log('  [Storage] removeItem',key);  delete this[key];}  \n    safefunction(Storage)\n    _storage_obj = new Storage\n    // window.localStorage\n    make_constructor(\"localStorage\", \"Storage\", EN, EN, _storage_obj)\n    localStorage.__proto__[\"clear\"]      = safefunction(localStorage.__proto__[\"clear\"]);\n    localStorage.__proto__[\"getItem\"]    = safefunction(localStorage.__proto__[\"getItem\"]);\n    localStorage.__proto__[\"key\"]        = safefunction(localStorage.__proto__[\"key\"]);\n    localStorage.__proto__[\"removeItem\"] = safefunction(localStorage.__proto__[\"removeItem\"]);\n    localStorage.__proto__[\"setItem\"]    = safefunction(localStorage.__proto__[\"setItem\"]);\n    localStorage[\"__#classType\"] = \"localStorage\";\n    Object.defineProperty(localStorage, 'length', { get: function(){ return Object.keys(this).length }, });\n    // window.sessionStorage\n    make_constructor(\"sessionStorage\", \"Storage\", EN, EN, _storage_obj)\n    sessionStorage.__proto__[\"clear\"]      = safefunction(sessionStorage.__proto__[\"clear\"]);\n    sessionStorage.__proto__[\"getItem\"]    = safefunction(sessionStorage.__proto__[\"getItem\"]);\n    sessionStorage.__proto__[\"key\"]        = safefunction(sessionStorage.__proto__[\"key\"]);\n    sessionStorage.__proto__[\"removeItem\"] = safefunction(sessionStorage.__proto__[\"removeItem\"]);\n    sessionStorage.__proto__[\"setItem\"]    = safefunction(sessionStorage.__proto__[\"setItem\"]);\n    Object.defineProperty(sessionStorage, 'length', { get: function(){ return Object.keys(this).length }, });\n    // navigator.connection\n    make_constructor(\"_vconnect\", \"NetworkInformation\", EN, EN)\n    navigator.connection = _vconnect\n    navigator.connection.__proto__[\"onchange\"]            = null;\n    navigator.connection.__proto__[\"effectiveType\"]       = \"4g\";\n    navigator.connection.__proto__[\"rtt\"]                 = 50;\n    navigator.connection.__proto__[\"downlink\"]            = 10;\n    navigator.connection.__proto__[\"saveData\"]            = false;\n    // window.performance\n    make_constructor(\"performance\", \"Performance\", EN, EN)\n    Object.assign(performance, {\n        \"timeOrigin\": 1619098076582.469,\n        \"timing\": {\n            \"connectStart\": 1619098076595,\n            \"navigationStart\": 1619098076582,\n            \"loadEventEnd\": 1619098077273,\n            \"domLoading\": 1619098076680,\n            \"secureConnectionStart\": 0,\n            \"fetchStart\": 1619098076595,\n            \"domContentLoadedEventStart\": 1619098077192,\n            \"responseStart\": 1619098076668,\n            \"responseEnd\": 1619098076878,\n            \"domInteractive\": 1619098077163,\n            \"domainLookupEnd\": 1619098076595,\n            \"redirectStart\": 0,\n            \"requestStart\": 1619098076602,\n            \"unloadEventEnd\": 1619098076678,\n            \"unloadEventStart\": 1619098076678,\n            \"domComplete\": 1619098077272,\n            \"domainLookupStart\": 1619098076595,\n            \"loadEventStart\": 1619098077272,\n            \"domContentLoadedEventEnd\": 1619098077196,\n            \"redirectEnd\": 0,\n            \"connectEnd\": 1619098076595\n        },\n        \"navigation\": {\n            \"type\": 0,\n            \"redirectCount\": 0\n        }\n    })\n    make_constructor(\"_vtiming\", \"PerformanceTiming\", EN, EN)\n    make_constructor(\"_vnavigation\", \"PerformanceNavigation\", EN, EN)\n    performance['timing'] = Object.assign(_vtiming, performance['timing'])\n    performance['navigation'] = Object.assign(_vnavigation, performance['navigation'])\n    // window.chrome\n    window.chrome = {\n        \"app\": {\n            \"isInstalled\": false,\n            \"InstallState\": { \"DISABLED\": \"disabled\", \"INSTALLED\": \"installed\", \"NOT_INSTALLED\": \"not_installed\" },\n            \"RunningState\": { \"CANNOT_RUN\": \"cannot_run\", \"READY_TO_RUN\": \"ready_to_run\", \"RUNNING\": \"running\" },\n            \"getDetails\":     safefunction(function getDetails(){     console.log(\"  [chrome] getDetails\")}),\n            \"getIsInstalled\": safefunction(function getIsInstalled(){ console.log(\"  [chrome] getIsInstalled\")}),\n            \"installState\":   safefunction(function installState(){   console.log(\"  [chrome] installState\")}),\n        },\n        \"runtime\": {\n            \"OnInstalledReason\":        { \"CHROME_UPDATE\": \"chrome_update\", \"INSTALL\": \"install\", \"SHARED_MODULE_UPDATE\": \"shared_module_update\", \"UPDATE\": \"update\" },\n            \"OnRestartRequiredReason\":  { \"APP_UPDATE\": \"app_update\", \"OS_UPDATE\": \"os_update\", \"PERIODIC\": \"periodic\" },\n            \"PlatformArch\":             { \"ARM\": \"arm\", \"ARM64\": \"arm64\", \"MIPS\": \"mips\", \"MIPS64\": \"mips64\", \"X86_32\": \"x86-32\", \"X86_64\": \"x86-64\" },\n            \"PlatformNaclArch\":         { \"ARM\": \"arm\", \"MIPS\": \"mips\", \"MIPS64\": \"mips64\", \"X86_32\": \"x86-32\", \"X86_64\": \"x86-64\" },\n            \"PlatformOs\":               { \"ANDROID\": \"android\", \"CROS\": \"cros\", \"LINUX\": \"linux\", \"MAC\": \"mac\", \"OPENBSD\": \"openbsd\", \"WIN\": \"win\" },\n            \"RequestUpdateCheckStatus\": { \"NO_UPDATE\": \"no_update\", \"THROTTLED\": \"throttled\", \"UPDATE_AVAILABLE\": \"update_available\" },\n            \"connect\":     safefunction(function connect(){     console.log(\"  [chrome] connect\") }),\n            \"sendMessage\": safefunction(function sendMessage(){ console.log(\"  [chrome] sendMessage\") }),\n            \"id\": undefined,\n        }\n    }\n    // window.indexedDB\n    make_constructor(\"_vDOMStringList\", \"DOMStringList\", [], EN, undefined, { allow_illegal: true})\n    make_constructor(\"_vIDBDatabase\", \"IDBDatabase\", [], EN, undefined, { allow_illegal: true})\n    make_constructor(\"_vIDBOpenDBRequest\", \"IDBOpenDBRequest\", [], EN, undefined, { allow_illegal: true})\n    make_constructor(\"indexedDB\", \"IDBFactory\", EN, EN)\n    window.indexedDB.__proto__[\"cmp\"]            = function cmp(){_vLog('--- func(*) --- indexedDB.cmp');debugger;};                       safefunction(window.indexedDB[\"cmp\"]);\n    window.indexedDB.__proto__[\"databases\"]      = function databases(){_vLog('--- func(*) --- indexedDB.databases');debugger;};           safefunction(window.indexedDB[\"databases\"]);\n    window.indexedDB.__proto__[\"deleteDatabase\"] = function deleteDatabase(){_vLog('--- func(*) --- indexedDB.deleteDatabase');debugger;}; safefunction(window.indexedDB[\"deleteDatabase\"]);\n    window.indexedDB.__proto__[\"open\"]           = function open(name){\n        var _temp_IDBOpenDBRequest = _vPxy(new IDBOpenDBRequest, 'IDBOpenDBRequest');\n        _temp_IDBOpenDBRequest.error = null\n        _temp_IDBOpenDBRequest.onblocked = null\n        _temp_IDBOpenDBRequest.onerror = null\n        _temp_IDBOpenDBRequest.onsuccess = null\n        _temp_IDBOpenDBRequest.onupgradeneeded = null\n        _temp_IDBOpenDBRequest.readyState = \"done\"\n        _temp_IDBOpenDBRequest.result = _vPxy(new IDBDatabase, 'IDBDatabase')\n        _temp_IDBOpenDBRequest.result.name = name\n        _temp_IDBOpenDBRequest.result.objectStoreNames = _vPxy(new DOMStringList, 'DOMStringList')\n        _temp_IDBOpenDBRequest.result.objectStoreNames.length = 0\n        _temp_IDBOpenDBRequest.result.onabort = null\n        _temp_IDBOpenDBRequest.result.onclose = null\n        _temp_IDBOpenDBRequest.result.onerror = null\n        _temp_IDBOpenDBRequest.result.onversionchange = null\n        _temp_IDBOpenDBRequest.result.version = 1\n        _temp_IDBOpenDBRequest.source = null\n        _temp_IDBOpenDBRequest.transaction = null\n        return _temp_IDBOpenDBRequest\n    }; safefunction(window.indexedDB[\"open\"]);\n    // window.XMLHttpRequest\n    make_constructor(\"XMLHttpRequest\", \"XMLHttpRequest\", EN, EN, undefined, { allow_illegal: true })\n    XMLHttpRequest.prototype[\"UNSENT\"]                = XMLHttpRequest[\"UNSENT\"]                = 0;\n    XMLHttpRequest.prototype[\"OPENED\"]                = XMLHttpRequest[\"OPENED\"]                = 1;\n    XMLHttpRequest.prototype[\"HEADERS_RECEIVED\"]      = XMLHttpRequest[\"HEADERS_RECEIVED\"]      = 2;\n    XMLHttpRequest.prototype[\"LOADING\"]               = XMLHttpRequest[\"LOADING\"]               = 3;\n    XMLHttpRequest.prototype[\"DONE\"]                  = XMLHttpRequest[\"DONE\"]                  = 4;\n    XMLHttpRequest.prototype[\"abort\"]                 = function abort(){_vLog('--- func(*) --- XMLHttpRequest.abort');debugger;};                                  safefunction(XMLHttpRequest.prototype[\"abort\"]);\n    XMLHttpRequest.prototype[\"getAllResponseHeaders\"] = function getAllResponseHeaders(){_vLog('--- func(*) --- XMLHttpRequest.getAllResponseHeaders');debugger;};  safefunction(XMLHttpRequest.prototype[\"getAllResponseHeaders\"]);\n    XMLHttpRequest.prototype[\"getResponseHeader\"]     = function getResponseHeader(){_vLog('--- func(*) --- XMLHttpRequest.getResponseHeader');debugger;};          safefunction(XMLHttpRequest.prototype[\"getResponseHeader\"]);\n    XMLHttpRequest.prototype[\"open\"]                  = function open(){_vLog('--- func(*) --- XMLHttpRequest.open');debugger;};                                    safefunction(XMLHttpRequest.prototype[\"open\"]);\n    XMLHttpRequest.prototype[\"overrideMimeType\"]      = function overrideMimeType(){_vLog('--- func(*) --- XMLHttpRequest.overrideMimeType');debugger;};            safefunction(XMLHttpRequest.prototype[\"overrideMimeType\"]);\n    XMLHttpRequest.prototype[\"send\"]                  = function send(){_vLog('--- func(*) --- XMLHttpRequest.send');debugger;};                                    safefunction(XMLHttpRequest.prototype[\"send\"]);\n    XMLHttpRequest.prototype[\"setRequestHeader\"]      = function setRequestHeader(){_vLog('--- func(*) --- XMLHttpRequest.setRequestHeader');debugger;};            safefunction(XMLHttpRequest.prototype[\"setRequestHeader\"]);\n    // window.screen\n    make_constructor(\"screen\", \"Screen\", EN, EN)\n    screen.__proto__[\"availWidth\"]  = 1920;\n    screen.__proto__[\"availHeight\"] = 1040;\n    screen.__proto__[\"width\"]       = 1920;\n    screen.__proto__[\"height\"]      = 1080;\n    screen.__proto__[\"colorDepth\"]  = 24;\n    screen.__proto__[\"pixelDepth\"]  = 24;\n    screen.__proto__[\"availLeft\"]   = 0;\n    screen.__proto__[\"availTop\"]    = 0;\n    screen.__proto__[\"orientation\"] = new (class ScreenOrientation {});\n    make_constructor(\"_vorientation\", \"ScreenOrientation\", EN, EN)\n    _vorientation.__proto__[\"angle\"]               = 0;\n    _vorientation.__proto__[\"type\"]                = \"landscape-primary\";\n    _vorientation.__proto__[\"onchange\"]            = null;\n    _vorientation.__proto__[\"lock\"]                = function lock(){debugger;};                safefunction(_vorientation[\"lock\"]);\n    _vorientation.__proto__[\"unlock\"]              = function unlock(){debugger;};              safefunction(_vorientation[\"unlock\"]);\n    screen[\"orientation\"] = _vorientation\n    // Element 元素上面通常存在的 style /CSSStyleDeclaration\n    make_constructor(\"_vCSSStyleDeclaration\", \"CSSStyleDeclaration\", EN, EN)\n    function make_style() {\n        var style = Object.assign(new __cilame__['N']['CSSStyleDeclaration'], {\n            alignContent: \"\", alignItems: \"\", alignSelf: \"\", alignmentBaseline: \"\", all: \"\", animation: \"\", animationDelay: \"\", animationDirection: \"\", animationDuration: \"\", animationFillMode: \"\", animationIterationCount: \"\", animationName: \"\", animationPlayState: \"\", animationTimingFunction: \"\", appearance: \"\", ascentOverride: \"\", aspectRatio: \"\", backdropFilter: \"\",\n            backfaceVisibility: \"\",\n            background: \"\", backgroundAttachment: \"\", backgroundBlendMode: \"\", backgroundClip: \"\", backgroundColor: \"\", backgroundImage: \"\", backgroundOrigin: \"\", backgroundPosition: \"\", backgroundPositionX: \"\", backgroundPositionY: \"\", backgroundRepeat: \"\", backgroundRepeatX: \"\", backgroundRepeatY: \"\", backgroundSize: \"\", baselineShift: \"\", blockSize: \"\", border: \"\", borderBlock: \"\", borderBlockColor: \"\", borderBlockEnd: \"\", borderBlockEndColor: \"\", borderBlockEndStyle: \"\", borderBlockEndWidth: \"\", borderBlockStart: \"\", borderBlockStartColor: \"\", borderBlockStartStyle: \"\", borderBlockStartWidth: \"\", borderBlockStyle: \"\", borderBlockWidth: \"\", borderBottom: \"\", borderBottomColor: \"\", borderBottomLeftRadius: \"\", borderBottomRightRadius: \"\", borderBottomStyle: \"\", borderBottomWidth: \"\", borderCollapse: \"\", borderColor: \"\", borderEndEndRadius: \"\", borderEndStartRadius: \"\", borderImage: \"\", borderImageOutset: \"\", borderImageRepeat: \"\", borderImageSlice: \"\", borderImageSource: \"\", borderImageWidth: \"\", borderInline: \"\", borderInlineColor: \"\", borderInlineEnd: \"\", borderInlineEndColor: \"\", borderInlineEndStyle: \"\", borderInlineEndWidth: \"\", borderInlineStart: \"\", borderInlineStartColor: \"\", borderInlineStartStyle: \"\", borderInlineStartWidth: \"\", borderInlineStyle: \"\", borderInlineWidth: \"\", borderLeft: \"\", borderLeftColor: \"\", borderLeftStyle: \"\", borderLeftWidth: \"\", borderRadius: \"\", borderRight: \"\", borderRightColor: \"\", borderRightStyle: \"\", borderRightWidth: \"\", borderSpacing: \"\", borderStartEndRadius: \"\", borderStartStartRadius: \"\", borderStyle: \"\", borderTop: \"\", borderTopColor: \"\", borderTopLeftRadius: \"\", borderTopRightRadius: \"\", borderTopStyle: \"\", borderTopWidth: \"\", borderWidth: \"\", bottom: \"\", boxShadow: \"\", boxSizing: \"\", breakAfter: \"\", breakBefore: \"\", breakInside: \"\", bufferedRendering: \"\", captionSide: \"\",\n            caretColor: \"\", clear: \"\", clip: \"\", clipPath: \"\", clipRule: \"\", color: \"\", colorInterpolation: \"\", colorInterpolationFilters: \"\", colorRendering: \"\", colorScheme: \"\", columnCount: \"\", columnFill: \"\", columnGap: \"\", columnRule: \"\", columnRuleColor: \"\", columnRuleStyle: \"\", columnRuleWidth: \"\", columnSpan: \"\", columnWidth: \"\", columns: \"\", contain: \"\", containIntrinsicSize: \"\", content: \"\", contentVisibility: \"\", counterIncrement: \"\", counterReset: \"\", counterSet: \"\", cssFloat: \"\", cssText: \"\", cursor: \"\", cx: \"\", cy: \"\", d: \"\",\n            descentOverride: \"\", direction: \"\", display: \"\", dominantBaseline: \"\", emptyCells: \"\", fill: \"\", fillOpacity: \"\", fillRule: \"\", filter: \"\", flex: \"\", flexBasis: \"\", flexDirection: \"\", flexFlow: \"\", flexGrow: \"\", flexShrink: \"\", flexWrap: \"\", float: \"\", floodColor: \"\", floodOpacity: \"\", font: \"\", fontDisplay: \"\", fontFamily: \"\", fontFeatureSettings: \"\", fontKerning: \"\", fontOpticalSizing: \"\", fontSize: \"\", fontStretch: \"\", fontStyle: \"\", fontVariant: \"\", fontVariantCaps: \"\", fontVariantEastAsian: \"\", fontVariantLigatures: \"\", fontVariantNumeric: \"\", fontVariationSettings: \"\", fontWeight: \"\", forcedColorAdjust: \"\", gap: \"\", grid: \"\", gridArea: \"\", gridAutoColumns: \"\", gridAutoFlow: \"\", gridAutoRows: \"\", gridColumn: \"\", gridColumnEnd: \"\", gridColumnGap: \"\", gridColumnStart: \"\", gridGap: \"\", gridRow: \"\", gridRowEnd: \"\", gridRowGap: \"\", gridRowStart: \"\", gridTemplate: \"\", gridTemplateAreas: \"\", gridTemplateColumns: \"\", gridTemplateRows: \"\", height: \"\",\n            hyphens: \"\", imageOrientation: \"\", imageRendering: \"\", inherits: \"\", initialValue: \"\", inlineSize: \"\", inset: \"\", insetBlock: \"\", insetBlockEnd: \"\", insetBlockStart: \"\", insetInline: \"\", insetInlineEnd: \"\", insetInlineStart: \"\", isolation: \"\", justifyContent: \"\", justifyItems: \"\", justifySelf: \"\", left: \"\", length: 0, letterSpacing: \"\", lightingColor: \"\", lineBreak: \"\", lineGapOverride: \"\", lineHeight: \"\", listStyle: \"\", listStyleImage: \"\", listStylePosition: \"\", listStyleType: \"\", margin: \"\", marginBlock: \"\", marginBlockEnd: \"\", marginBlockStart: \"\", marginBottom: \"\", marginInline: \"\", marginInlineEnd: \"\", marginInlineStart: \"\", marginLeft: \"\", marginRight: \"\", marginTop: \"\", marker: \"\", markerEnd: \"\", markerMid: \"\", markerStart: \"\", mask: \"\", maskType: \"\", maxBlockSize: \"\", maxHeight: \"\", maxInlineSize: \"\", maxWidth: \"\", maxZoom: \"\", minBlockSize: \"\", minHeight: \"\", minInlineSize: \"\", minWidth: \"\", minZoom: \"\", mixBlendMode: \"\", objectFit: \"\",\n            objectPosition: \"\", offset: \"\", offsetDistance: \"\", offsetPath: \"\", offsetRotate: \"\", opacity: \"\", order: \"\", orientation: \"\", orphans: \"\", outline: \"\", outlineColor: \"\", outlineOffset: \"\", outlineStyle: \"\", outlineWidth: \"\", overflow: \"\", overflowAnchor: \"\", overflowWrap: \"\", overflowX: \"\", overflowY: \"\", overscrollBehavior: \"\", overscrollBehaviorBlock: \"\", overscrollBehaviorInline: \"\", overscrollBehaviorX: \"\", overscrollBehaviorY: \"\", padding: \"\", paddingBlock: \"\", paddingBlockEnd: \"\", paddingBlockStart: \"\", paddingBottom: \"\", paddingInline: \"\", paddingInlineEnd: \"\", paddingInlineStart: \"\", paddingLeft: \"\", paddingRight: \"\", paddingTop: \"\", page: \"\", pageBreakAfter: \"\", pageBreakBefore: \"\", pageBreakInside: \"\", pageOrientation: \"\", paintOrder: \"\", parentRule: null, perspective: \"\", perspectiveOrigin: \"\", placeContent: \"\", placeItems: \"\", placeSelf: \"\", pointerEvents: \"\", position: \"\", quotes: \"\", r: \"\", resize: \"\", right: \"\", rowGap: \"\", rubyPosition: \"\", rx: \"\", ry: \"\", scrollBehavior: \"\",\n            scrollMargin: \"\", scrollMarginBlock: \"\", scrollMarginBlockEnd: \"\", scrollMarginBlockStart: \"\", scrollMarginBottom: \"\", scrollMarginInline: \"\", scrollMarginInlineEnd: \"\", scrollMarginInlineStart: \"\", scrollMarginLeft: \"\", scrollMarginRight: \"\", scrollMarginTop: \"\", scrollPadding: \"\", scrollPaddingBlock: \"\", scrollPaddingBlockEnd: \"\", scrollPaddingBlockStart: \"\", scrollPaddingBottom: \"\", scrollPaddingInline: \"\", scrollPaddingInlineEnd: \"\", scrollPaddingInlineStart: \"\", scrollPaddingLeft: \"\", scrollPaddingRight: \"\", scrollPaddingTop: \"\", scrollSnapAlign: \"\", scrollSnapStop: \"\", scrollSnapType: \"\", shapeImageThreshold: \"\", shapeMargin: \"\", shapeOutside: \"\", shapeRendering: \"\", size: \"\", speak: \"\", src: \"\", stopColor: \"\", stopOpacity: \"\", stroke: \"\", strokeDasharray: \"\", strokeDashoffset: \"\", strokeLinecap: \"\", strokeLinejoin: \"\", strokeMiterlimit: \"\", strokeOpacity: \"\", strokeWidth: \"\", syntax: \"\", tabSize: \"\", tableLayout: \"\", textAlign: \"\", textAlignLast: \"\", textAnchor: \"\", textCombineUpright: \"\", textDecoration: \"\", textDecorationColor: \"\", textDecorationLine: \"\", textDecorationSkipInk: \"\", textDecorationStyle: \"\", textDecorationThickness: \"\", textIndent: \"\", textOrientation: \"\", textOverflow: \"\", textRendering: \"\", textShadow: \"\", textSizeAdjust: \"\", textTransform: \"\", textUnderlineOffset: \"\", textUnderlinePosition: \"\", top: \"\", touchAction: \"\", transform: \"\", transformBox: \"\", transformOrigin: \"\", transformStyle: \"\", transition: \"\", transitionDelay: \"\", transitionDuration: \"\", transitionProperty: \"\", transitionTimingFunction: \"\", unicodeBidi: \"\", unicodeRange: \"\", userSelect: \"\", userZoom: \"\", vectorEffect: \"\", verticalAlign: \"\", visibility: \"\", whiteSpace: \"\", widows: \"\", width: \"\", willChange: \"\", wordBreak: \"\", wordSpacing: \"\", wordWrap: \"\", writingMode: \"\", \n            x: \"\",\n            y: \"\",\n            zIndex: \"\",\n            zoom: \"\",\n        })\n        style.__proto__ = safefunction(function(){})\n        return style\n    }\n    // document.createElement ， 这个函数很重要，需要特殊挂钩一下\n    var htmlmap = {\n        HTMLElement: [\"abbr\", \"address\", \"article\", \"aside\", \"b\", \"bdi\", \"bdo\", \"cite\", \"code\", \"dd\", \"dfn\", \"dt\", \"em\", \"figcaption\", \"figure\", \"footer\", \"header\", \"hgroup\", \"i\", \"kbd\", \"main\", \"mark\", \"nav\", \"noscript\", \"rp\", \"rt\", \"ruby\", \"s\", \"samp\", \"section\", \"small\", \"strong\", \"sub\", \"summary\", \"sup\", \"u\", \"var\", \"wbr\"],\n        HTMLAnchorElement: [\"a\"], HTMLAreaElement: [\"area\"], HTMLAudioElement: [\"audio\"], HTMLBaseElement: [\"base\"], HTMLBodyElement: [\"body\"], HTMLBRElement: [\"br\"], HTMLButtonElement: [\"button\"], HTMLCanvasElement: [\"canvas\"], HTMLDataElement: [\"data\"], HTMLDataListElement: [\"datalist\"], HTMLDetailsElement: [\"details\"], HTMLDialogElement: [\"dialog\"], HTMLDirectoryElement: [\"dir\"], HTMLDivElement: [\"div\"], HTMLDListElement: [\"dl\"], HTMLEmbedElement: [\"embed\"], HTMLFieldSetElement: [\"fieldset\"], HTMLFontElement: [\"font\"], HTMLFormElement: [\"form\"], HTMLFrameElement: [\"frame\"], HTMLFrameSetElement: [\"frameset\"], HTMLHeadingElement: [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"], HTMLHeadElement: [\"head\"], HTMLHRElement: [\"hr\"], HTMLHtmlElement: [\"html\"], HTMLIFrameElement: [\"iframe\"], HTMLImageElement: [\"img\"], HTMLInputElement: [\"input\"],\n        HTMLLabelElement: [\"label\"], HTMLLegendElement: [\"legend\"], HTMLLIElement: [\"li\"], HTMLLinkElement: [\"link\"], HTMLMapElement: [\"map\"], HTMLMarqueeElement: [\"marquee\"], HTMLMediaElement: [], HTMLMenuElement: [\"menu\"], HTMLMetaElement: [\"meta\"], HTMLMeterElement: [\"meter\"], HTMLModElement: [\"del\", \"ins\"], HTMLObjectElement: [\"object\"], HTMLOListElement: [\"ol\"], HTMLOptGroupElement: [\"optgroup\"], HTMLOptionElement: [\"option\"], HTMLOutputElement: [\"output\"], HTMLParagraphElement: [\"p\"], HTMLParamElement: [\"param\"], HTMLPictureElement: [\"picture\"], HTMLPreElement: [\"listing\", \"pre\", \"xmp\"], HTMLProgressElement: [\"progress\"], HTMLQuoteElement: [\"blockquote\", \"q\"], HTMLScriptElement: [\"script\"], HTMLSelectElement: [\"select\"], HTMLSlotElement: [\"slot\"],\n        HTMLSourceElement: [\"source\"], HTMLSpanElement: [\"span\"], HTMLStyleElement: [\"style\"], HTMLTableCaptionElement: [\"caption\"], HTMLTableCellElement: [\"th\", \"td\"], HTMLTableColElement: [\"col\", \"colgroup\"], HTMLTableElement: [\"table\"], HTMLTimeElement: [\"time\"], HTMLTitleElement: [\"title\"], HTMLTableRowElement: [\"tr\"], HTMLTableSectionElement: [\"thead\", \"tbody\", \"tfoot\"], HTMLTemplateElement: [\"template\"], HTMLTextAreaElement: [\"textarea\"], HTMLTrackElement: [\"track\"], HTMLUListElement: [\"ul\"], HTMLUnknownElement: [], HTMLVideoElement: [\"video\"]\n    }\n    // 临时的 canvas 附加，让 canvas 至少能跑通\n    function attach_canvas(ele){\n        ele.getContext = safefunction(function getContext(){console.log('  [document.createElement.getContext] []'); \n            var v = _vPxy(new class WebGLRenderingContext{\n                createBuffer(){             console.log('    [document.createElement.WebGLRenderingContext.createBuffer]', ...arguments); return _vPxy(new class WebGLBuffer{}, 'WebGLBuffer') }\n                createProgram(){            console.log('    [document.createElement.WebGLRenderingContext.createProgram]', ...arguments); return _vPxy(new class WebGLProgram{}, 'WebGLProgram') }\n                createShader(){             console.log('    [document.createElement.WebGLRenderingContext.createShader]', ...arguments); return _vPxy(new class WebGLShader{}, 'WebGLShader') }\n                fillText(){                 console.log('    [document.createElement.WebGLRenderingContext.fillText]', ...arguments) }\n                fillRect(){                 console.log('    [document.createElement.WebGLRenderingContext.fillRect]', ...arguments) }\n                bindBuffer(){               console.log('    [document.createElement.WebGLRenderingContext.bindBuffer]', ...arguments) }\n                bufferData(){               console.log('    [document.createElement.WebGLRenderingContext.bufferData]', ...arguments) }\n                shaderSource(){             console.log('    [document.createElement.WebGLRenderingContext.shaderSource]', ...arguments) }\n                compileShader(){            console.log('    [document.createElement.WebGLRenderingContext.compileShader]', ...arguments) }\n                attachShader(){             console.log('    [document.createElement.WebGLRenderingContext.attachShader]', ...arguments) }\n                linkProgram(){              console.log('    [document.createElement.WebGLRenderingContext.linkProgram]', ...arguments) }\n                useProgram(){               console.log('    [document.createElement.WebGLRenderingContext.useProgram]', ...arguments) }\n                getAttribLocation(){        console.log('    [document.createElement.WebGLRenderingContext.getAttribLocation]', ...arguments) }\n                getUniformLocation(){       console.log('    [document.createElement.WebGLRenderingContext.getUniformLocation]', ...arguments) }\n                enableVertexAttribArray(){  console.log('    [document.createElement.WebGLRenderingContext.enableVertexAttribArray]', ...arguments) }\n                vertexAttribPointer(){      console.log('    [document.createElement.WebGLRenderingContext.vertexAttribPointer]', ...arguments) }\n                uniform2f(){                console.log('    [document.createElement.WebGLRenderingContext.uniform2f]', ...arguments) }\n                drawArrays(){               console.log('    [document.createElement.WebGLRenderingContext.drawArrays]', ...arguments) }\n                getSupportedExtensions(){   console.log('    [document.createElement.WebGLRenderingContext.getSupportedExtensions]', ...arguments) }\n            }, \"WebGLRenderingContext\")\n            v.ARRAY_BUFFER = 34962\n            v.STATIC_DRAW = 35044\n            v.VERTEX_SHADER = 35633\n            v.FLOAT = 5126\n            v.canvas = _vPxy(new class HTMLCanvasElement{\n                toDataURL(){\n                    console.log('  [document.createElement.WebGLRenderingContext.canvas.HTMLCanvasElement.toDataURL]', ...arguments)\n                    return \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jAAAAAElFTkSuQmCC\"\n                }\n            }, \"document.createElement.WebGLRenderingContext.canvas.HTMLCanvasElement\")\n            return v\n        })\n        ele.toDataURL = safefunction(function toDataURL(){\n            return \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAAyCAYAAAAZUZThAAARr0lEQVR4Xu2bd3hUVfrHv+e2uTPphGqJIiAiICUUQUXaQlxcFFhBigIiRRJCCU1cIXQp0kLobRUQCygYRAVWLHQBl0BYpCgqTSB1ZjJzyzm/5x6YLMHID3mGfeaJ9z5P/sjNve85b/mc9z3vuSHsjQcY7CtkLEBGnyYhMxl7IiA2IKEVBTYgIeYPG5AQc4idQULKIXYGCSl3AHYGCS2H2ICElj9sQELNH3aJFVoesTNIiPnDBiTEHGLvQULKIXaJFVLusPcgIeYOu80bcg6xM0hIucTOICHlDjuDhJg77AwScg6xM0hIucTOICHlDjuDhJg77AwScg6xM0hIucTOICHlDjuDhJg77AwScg6xM0hIucTOICHlDjuDhJg77AwScg6xM0hIueSmGeRTvRl6eqYjjpxDRmQ/VCCXb2vyP5uVMMfXCyNdS7mMAhaGzgXzuKz3IpIRQTy3Jbekl36kd+PvBfNhEgEbwhJRWfyl2GMaZAzx/AOf649jbfhQNJIOF/09n4Vjse95rNafwVmzAr9/t3gRHeStGKauQCRxFz17qzrc6nMBwX/0W6zolJz7iMhGi5I54fKUcueDZkhbELfA7wLCGMEQ72vYqLeGFVRvOqeiqyPjtsw23dcXq/3P4LPI3qhELt1RQKwJbtUfwwueGXhcOoC3w0fACR+ft6XTTF8fzPD1xWjnYh70geuQUQMvumfiAsqijfwNnpK/5H/6TG+GrXpTRBE3VrlGoYl8iN+/1cC/1eduG5BROWMJWB9Bok2vTC579rYcZL/0uxb4XUBO03vRvmAxWsh7kKNHId7MQj/nOrhULwj5Y/+lGwDk84jeKKvnQlSMqzIYoPsVPjnZoQFB+mdTC4SphQNw0ns/npG3oX3EdhCBYp/xCLq5Z3MA5rgmQ9AARgl+laPxrGchDCJyCOpIx2HqIqghcqjO03JYoHXHz6QCJkbOQRXxTBEgMgyslofDSfw31+EWdf3DGeQaIF1ZRsIUX9pduqrsKzd9Z4Ed88GxwO8CslprjxTvGKwJG4afC+/CIa0mXnGsRXX1NATZLDb6N0Y8xnkH4zCtzu8/IhzHeNdcvoL3cU/Fh/pf+P36NAsdhc/xQtRH6Oyei0Bwvet/GvPRDRsiBqKK+HOR7LOsAv5asAzNxb08oC2ojhrVMMw7Bgfpw78Z6/pJ5dEIDHO/ihjNgz7O9zjYndzz+SMfRCThXvMiTE2CKJuYZAzAQq0r3g4bgdbCbhh+GQyEQyWKlL9zQKuJtwo7oJGYie4RH8EjqrxMFEGRRNZgo9YKG4WWiBPPYYpzFlpIe/h8AxnkRpCOmiXr8cQ/3i+2TESPzmkOhukErD7PgiAHQTAy942YHTEjs9eBoEvAtg3pkb0jtJVtYtP25gcnPGwpJQJSCBVdC2bzlTMjvC9yCmMwzp+MluJe9HRsgKL6i1b79XpbJHrGoTzJRl/1XW7Rpb4u8DIn3osYBB0yFvq64Ru9AaZL01EDp3CP6wIHxLqsPch3Rg108czFdNc09FA2FXllk9YK/bwTsTpsOFrLu7BJb4lX3BP4vqK3sp4/t1LrhJM0Dulh49FJ/qyYR62MMTOvLxqQo3BLLrxF2+PdiMFoSDJh+mUQgaFAcqKDZwF/78OwgQjXCnnWkFWdAxK4rEDvmz8FD+i/IMW1DIpDQ2fPPGSa1dHG3Inmyl5QmWCR/jysfdAS1+tor2wvsRS7mR4alG45b5R5xxo3ZnR2V8awkgAXQXCVboYkAGEmoU+JRFAYJUMIWItu5uZ/tqG7PY/rB2bagAQP7BIBOWDWQqeC+ejh2IgJUhrcmguDjddAKMMMZQbKqDkgIoW1Snf0pINCwAdhSYhhBXxVvmjGYpG/K2pKJ9AlfDNm6i/xcmeyYzaiSAF8zIGpWn8cFavy8oQxAV3M2WhqHsJIZRkcqo8D2M8zCSfo/TxwBT8wXkvCBSkWy8PHQKUaDL8Encn4p78jzqMcUsKXIUouvnjOLeyJ/Z66CIcXj7iyMMCxjr9nXRYEZ1EeCQUr0Fj8NxYrY3lZJTk0CNcyx/WmtrLhST0OK+R/oJx8GV38c3CcVsaHchIeFk5CkEzka5FY5O8GkxEMjlwFSIxnmkAGCehahuSWqMdh48HTrY19HV4mqT8JDrqVgQiGIbX9yWwTTqjZKEuoUv09qe3gKOb9eoj59tDKji0vtqXfJL2mL50ZR8/lWvOlwC9l5n37SfDC5M8rqURAxnsHYanWGR+4BiGeZoExYCXpiDTvi1gopqKJegiSQ8d3Zg10LEjHAPUdpIgrYOoyX+JE6WoJZhoiCAEWs+ewUfsL1qgpHCKfJGOgdzzySHhR/T6Nvox/+ZvibXkEKjku4bwUy8urjtLneF1ZgJO++9FHm4w6jmNoJ+xAtOGGAQFeUcXXegNcMmIx3LECDzjO8LIpcO016yA5/3XE02N4QfkIDeRMvu+w5m9BEFgMEsSvkCZN4q9JVvYoYZ9l7aWW+TrjY+UVVMJF9NSnQRJMrJJHQzZN/g4RTazSO+GgryZS1JUo77iEzoX/LSetsrG9fxHaKl+XqMdZvZL3efPTObtIne/S5O6LGcicU+4260WRNGGgfoHhOIeAoLooEDFBSa/lRljXdG3y6Do4IVLQw5Ticpl5B37684Z18DT/DSAXWVk8nb8EkYIbG9QkOHU/BNHEMbEKurjnohvLwFB1Ja/ptxjN8KJ7BlaFjURbc/e14NKKgssKRMOvYJ3RDjPoS9iq9kKMWQC/Khfbg1gb3EypGrq6Z3MAm8nfYgt5AknesVgXPgQNzCM4oNdGRz0NjBC0NvfADwVfig2g41o2gIGNykDEC0chqVfnYGW4zu55yDKrojY7gYYsk8NcXrkMUTb4fE+Z9+LpgqVoJe7GLHEqiMggO/QSLTzAM4G3h7coL6MSLmOAPh4RohvzpYk8Yq3mg5VFrBIq2TMWG6RBqCr+iB76TC7PypZHzGropF+tlkrSQwSlqcaiKQ74HK9LSSkRJL/Hfm93TrxP8W+uOPMw74nnp8SXZYaQMEoa1uJdqW3r1drI5Kbmd5GUiRvtEusOAhI4+9CZhEY0E/fTc9gp1sNZUp6P2ogdxhx5Kh5UTyMDT6KXezrWuoaipbmPB4ekXA28669AF+tmgBgOgQNSn2VhhLwcrxopyEQ1bHAlwqVp2MXqooM/He84h6IF3cdX/xvLIGoKsH6s7GAKAoYVjsH7WgLfn0iGic89zdBAPIJuERvhkPx8ijk0Ch3cCxDLcrFceg1hkqdEQAKb7WwWhc1qXyiGiVeMVISLnquAXNeJswAZ4JmIDEd/VGU/cZDcxFUMkFXOUSXq4b0SXYua7L5N4pPtpsj9B8bRM/3WaWMMChyPnbd/1422jb7WxbIBCR4U10sqlkEsKF72TsF2vQlGOpYh3sgCBcElJRqUCLykWl+YgNHCMnR1bMIx+QF0cKdjtLIUvfAhJEXnkHjg5O3UciQb6a5xmOvvxc9BbgaI1eZN13rgg8IEpIkTMc4cgsbqQQyXVsDQJBwSa6BDYTpGSMuRKKy5iTWulk8f0ta8edBR3orZrsmgPhHrfH/DfrMWnlM+RfPwPUWbcKukXOtvj1XSaDRQDpcIyFdGQ3Rzz+KNgBnidPioygPfFAWsFMdAFrSi96b6BmClrxM2O/uhgnGF79+ukGgOyI/mPWhvLMRg6a0S9SjMDetvKbdfqB03Rh48qALJXrXaP+qIYNKvI+cf+E+51F/DjULJ6mRczPFe6RXtKjvKOgexAfkfABIoN6qLP2CNMwWyZnVx/nvmYZ00z/e9wDtTiepqhCtudPCl4y56CfPESYhS8zkgVt3fpWAuBqprMFJdilvJIBYgWbQqnnOnoQ9bz0uRYZErUN08DTABXkVBR286wk0vFkqpqKhe4mNZh5iJ7lR8S2vh/bBkVBXP4Ij5IG/pxpA8bAobgDJGPqgp4oJYhreu7zPP4+Wwd/GQeso6KsUvtCKez5+DBkYWBjjXorrrVLE9iFWidfe8CT9T8HFYf8QZF1BIHXwPcpRVw0dKIqqJP3BAAif59wgXsNY5DIYmI0kfi1wSUawh4TC1EvVYr7f9QWTmU4YmXbQ26Q/TU67l/rHLK9FLn1iAxLya/RgoNjOQWbnTYibYGeTOgBGQWiyDpPt7YJw3GfOdE/B3fAZGBQgSLdbuXODrjk98T2Kw8hZaOXbx3v94dxKeZf9CfeUofhDvxnytB8ogDx9FDER5LRtb9GYYYIzHq+IStBZ2FrV5bzwb8MGBbp5ZyPbHoB3ZgcSo1ZA1k298rdLNailPcb+C5nQf32x7FZXf+9aojRHqUgxXl8OC2ApmCxKrpduAHuHNA6scszLcNr0pFru74lH8m0MS5bja9bJO0t/M74so6oZTKURd9Si/f+NJemNymHfqfIKCztocnKJxaEX3oJm0D1eUKCzxP89b3NZnLPEsCx7NhX7GRHiJWtSQyBCexCRPYol66Ewamzs9epJFrtXmLU8vrUowd18xgLVrxfZXQDCcgVx+WD711835Ax95U+rZdpHU+aUE+vXG5+i2Y3abN7jAFAESaNnm03BsDu+HGC2ft1pvPOHONKqju3sWurOPkehYjTDVi11mXXxW0Bxn2F34SqyPx+WDmOGchvLsCj90uyxGo7f/DTCdoCXZg97RH6CXe1pR6/P6U2jrgHK8Oxnp4kS0VHfxPYW1MlttZevaqdfnY52j5bBDbIQw0YtR6hJ0kbbA9AvI0FpiNE3hZzLD5JWgmsSzhFV2WecegVP2E97KeFbZjqfDthYdBlq6by94DLvNetjCnsB5oRz/FquHvBH91XUIZ14YPpnL8ysyPwe5VzyH9uYOfKE9iq1CE8TKuXjTNQX1yH+g+2T4iAPd9ZkgYMVO3HcaJetxIvMxR3KF6a0AEis56KdNpNXxTxiH0j3EWXm72EgvhHOLyMzE730JEmGk9ZdS45ze8sQR8SyrcS16/MR9jgsthk55zf4mK0iclPhxR97ghg0ZUFcy6Z7w+QcySxorZ3DDZoSxhwghh6Lm7t9/JbFhTasVSRj1MMqOmwJTBCLWEED9VDA/iZnzXW5ucuN4gNUDNU5TgZyMYXkX84Topy35UTQ3g6Sd5Dvnb/vFy1UUtCMCKc8gXIr2mRlkyYGi1lJgLAZmUmYeEynRIJHKoKSMIJIjkXP27f55aBNntGE8ZYBFM8K23dj2zBtavyozpeYiY9m5krTl3tm7C62xPUn17jIEsRUjRKUUFxRBOGPd18DiBIaKAqBLML9wXWujskFVHZYOjCIKhJkMOCUyogXasNvw2N4+ytilTviFL/29F5TD5cKArreihzX27djWbvMGh5DfAGIFVoRp/I2ASpqqfvx73/W4BzasSBUkmJTkBQI4Z8ij91uHWSCIAiNWl/cCo+SrQNsxZ0jdaGJKrSGQGJHiSrgzf2ueP6LNjYBYv7sHN37EYOajgHgget7eAzeqW2ws66tLoNCEeXhezMEjqamg+ckNm1KCmgK5CkyJkA9q+CQhrLoAciTyug4RS22uFuR66zHGqjDAab1rySeEnIqIdh0iqTuufv1o7dCuAUIYChkVfhUkVosyWN+q5BmitrOa8oX1CfCnLvjPHfY++44omOz6xeD/0yMwzh+2bawng6RmacEJkz+vlCB9HvjnNeDNNI8Zlf04AWtLQUZE0MK0TO2ZPSUtBrb1QtcCNiB3yjeDTjhiXLHvA2gHhr212fc9N/mS6hACb5T9GcidsnrQ5dqABN2kvxWYnRwfByBOgPgQI+z7mLn7v/ofDGsPEQQL2IAEwYg3E/FF8+ZSfG3PU1RARVCWw0Rjm9WwuMPD2uKDZAEbkCAZ0hZTOi1gA1I6/WprFSQL2IAEyZC2mNJpARuQ0ulXW6sgWcAGJEiGtMWUTgvYgJROv9paBckCNiBBMqQtpnRawAakdPrV1ipIFrABCZIhbTGl0wI2IKXTr7ZWQbKADUiQDGmLKZ0WsAEpnX61tQqSBWxAgmRIW0zptIANSOn0q61VkCzwf7FZ7asWd3DbAAAAAElFTkSuQmCC\"\n        })\n    }\n    document.createElement = safefunction(function createElement(e){\n        var ostart = start\n        var ostart1 = start1\n        if (ostart){ console.log('  [document.createElement]', e) }\n        start = false\n        start1 = false\n        var htmlmapkeys = Object.keys(htmlmap)\n        e = e.toLocaleLowerCase()\n        for (var i = 0; i < htmlmapkeys.length; i++) {\n            if (htmlmap[htmlmapkeys[i]].indexOf(e) != -1){\n                var ele = eval(` _vPxy(new class ${htmlmapkeys[i]}{}, \"${htmlmapkeys[i]}\");`)\n                break\n            }\n        }\n        if (!ele){ var ele = eval(` _vPxy(new class HTMLElement{}, \"HTMLElement\");`) }\n        ele.getAttribute           = safefunction(function getAttribute(N){              console.log('  [document.createElement.getAttribute] null',N); return null})\n        ele.getAttributeNode       = safefunction(function getAttributeNode(N){          console.log('  [document.createElement.getAttributeNode] null',N); return null})\n        ele.getAttributeNames      = safefunction(function getAttributeNames(N){         console.log('  [document.createElement.getAttributeNames] []',N); return []})\n        ele.getElementsByClassName = safefunction(function getElementsByClassName(N){    console.log('  [document.createElement.getElementsByClassName] []',N); return []})\n        ele.getElementsByTagName   = safefunction(function getElementsByTagName(N){      console.log('  [document.createElement.getElementsByTagName] []',N); return []})\n        ele.getElementsByTagNameNS = safefunction(function getElementsByTagNameNS(A,B){  console.log('  [document.createElement.getElementsByTagNameNS] []',A,B); return []})\n        if (e == 'canvas'){\n            attach_canvas(ele)\n        }\n        ele.style = make_style()\n        start = ostart\n        start1 = ostart1\n        return ele\n    })\n    // mimeTypes模拟\n    make_constructor(\"_vPlugin\", \"Plugin\", EN, EN, Array)\n    make_constructor(\"_vMimeType\", \"MimeType\", EN, EN)\n    make_constructor(\"_vMimeTypeArray\", \"MimeTypeArray\", EN, EN, Array)\n    _vMimeTypeArray[0] = new __cilame__['N']['MimeType']\n    _vMimeTypeArray[0].description = \"\"\n    _vMimeTypeArray[0].enabledPlugin = new __cilame__['N']['Plugin'] \n    _vMimeTypeArray[0].enabledPlugin[0] = _vMimeTypeArray[0]\n    _vMimeTypeArray[0].enabledPlugin.description = \"\"\n    _vMimeTypeArray[0].enabledPlugin.filename = \"mhjfbmdgcfjbbpaeojofohoefgiehjai\"\n    _vMimeTypeArray[0].enabledPlugin.length = 1\n    _vMimeTypeArray[0].enabledPlugin.name = \"Chrome PDF Viewer\"\n    _vMimeTypeArray[0].suffixes = \"pdf\"\n    _vMimeTypeArray[0].type = \"application/pdf\"\n    _vMimeTypeArray[_vMimeTypeArray[0].type] = _vMimeTypeArray[0]\n    _vMimeTypeArray[1] = new __cilame__['N']['MimeType']\n    _vMimeTypeArray[1].description = \"Portable Document Format\"\n    _vMimeTypeArray[1].enabledPlugin = new __cilame__['N']['Plugin'] \n    _vMimeTypeArray[1].enabledPlugin[0] = _vMimeTypeArray[1]\n    _vMimeTypeArray[1].enabledPlugin.description = \"Portable Document Format\"\n    _vMimeTypeArray[1].enabledPlugin.filename = \"internal-pdf-viewer\"\n    _vMimeTypeArray[1].enabledPlugin.length = 1\n    _vMimeTypeArray[1].enabledPlugin.name = \"Chrome PDF Viewer\"\n    _vMimeTypeArray[1].suffixes = \"pdf\"\n    _vMimeTypeArray[1].type = \"application/x-google-chrome-pdf\"\n    _vMimeTypeArray[_vMimeTypeArray[1].type] = _vMimeTypeArray[1]\n    _vMimeTypeArray[2] = new __cilame__['N']['MimeType']\n    _vMimeTypeArray[2].description = \"Native Client Executable\"\n    _vMimeTypeArray[2].enabledPlugin = new __cilame__['N']['Plugin'] \n    _vMimeTypeArray[2].enabledPlugin[0] = _vMimeTypeArray[2]\n    _vMimeTypeArray[2].enabledPlugin[1] = _vMimeTypeArray[3]\n    _vMimeTypeArray[2].enabledPlugin.description = \"\"\n    _vMimeTypeArray[2].enabledPlugin.filename = \"internal-nacl-plugin\"\n    _vMimeTypeArray[2].enabledPlugin.length = 2\n    _vMimeTypeArray[2].enabledPlugin.name = \"Native Client\"\n    _vMimeTypeArray[2].suffixes = \"pdf\"\n    _vMimeTypeArray[2].type = \"application/x-nacl\"\n    _vMimeTypeArray[_vMimeTypeArray[2].type] = _vMimeTypeArray[2]\n    _vMimeTypeArray[3] = new __cilame__['N']['MimeType']\n    _vMimeTypeArray[3].description = \"Portable Native Client Executable\"\n    _vMimeTypeArray[3].enabledPlugin = new __cilame__['N']['Plugin'] \n    _vMimeTypeArray[3].enabledPlugin[0] = _vMimeTypeArray[2]\n    _vMimeTypeArray[3].enabledPlugin[1] = _vMimeTypeArray[3]\n    _vMimeTypeArray[3].enabledPlugin.description = \"\"\n    _vMimeTypeArray[3].enabledPlugin.filename = \"internal-nacl-plugin\"\n    _vMimeTypeArray[3].enabledPlugin.length = 2\n    _vMimeTypeArray[3].enabledPlugin.name = \"Native Client\"\n    _vMimeTypeArray[3].suffixes = \"pdf\"\n    _vMimeTypeArray[3].type = \"application/x-pnacl\"\n    _vMimeTypeArray[_vMimeTypeArray[3].type] = _vMimeTypeArray[3]\n    Object.defineProperty(_vMimeTypeArray, 'length', { get: function(){ return 4 } })\n    navigator.mimeTypes = _vMimeTypeArray\n    // 电池信息模拟\n    make_constructor(\"_vBatteryManager\", \"BatteryManager\", EN, EN)\n    BatteryManager.prototype['charging']                = true\n    BatteryManager.prototype['chargingTime']            = 0\n    BatteryManager.prototype['dischargingTime']         = Infinity\n    BatteryManager.prototype['level']                   = 1\n    BatteryManager.prototype['onchargingchange']        = null\n    BatteryManager.prototype['onchargingtimechange']    = null\n    BatteryManager.prototype['ondischargingtimechange'] = null\n    BatteryManager.prototype['onlevelchange']           = null\n    navigator.getBattery = safefunction(function getBattery(){\n        var ostart = start\n        start = false\n        fakePromise = new safefunction_with_name(function Promise(){}, 'Promise') // 这里不用真实的 Promise 主要就是考虑到更好的控制执行流程\n        fakePromise.then = safefunction(function then(func){\n            EventTarget.prototype.addEventListener('load', function(){\n                return func(_vPxy(_vBatteryManager, \"BatteryManager\"))\n            })\n        })\n        start = ostart\n        return fakePromise\n    })\n    // runloads： 在你添加的js执行完之后，再执行这个用于将 load 内的函数尽数执行\n    ;(typeof global=='undefined'?window:global).runloads = function runloads(reverse){\n        var loadfuncs = EventTarget.prototype.listeners.load\n        var T = '======================================================================='\n        if (loadfuncs){\n            if (reverse){\n                for (var i = loadfuncs.length - 1; i >= 0; i--) { \n                    console.log(`${T} LoadFunc ${loadfuncs[i].name||'UnknownFunc'} ${T}`)\n                    loadfuncs[i]() }\n            }else{\n                for (var i = 0; i < loadfuncs.length; i++) { \n                    console.log(`${T} LoadFunc ${loadfuncs[i].name||'UnknownFunc'} ${T}`)\n                    loadfuncs[i]() \n                }\n            }\n        }\n    }\n    // 用于生成代码用，在环境中无影响，保留即可\n    var nn = Object.keys(__cilame__['n'])\n    var NN = Object.keys(__cilame__['N'])\n    var AA = ['addEventListener', 'dispatchEvent', 'removeEventListener', 'clientInformation']\n    return nn.concat(NN).concat(AA)\n}\nCilame()\n\n\n\n// console.log(localStorage)\n// console.log(localStorage.length)\n// console.log(localStorage.getItem(\"$_fb\"))\n// console.log(localStorage.removeItem(\"$_fb\"))\n// console.log(localStorage.getItem(\"$_fb\"))\n// console.log(localStorage)\n// console.log(localStorage.setItem(\"$_fb\", \"hahaha\"))\n// console.log(localStorage.getItem(\"$_fb\"))\n// console.log(localStorage)\n\n\n\n\n\n\n\n// sessionStorage.__proto__[\"length\"]     = 2;\n// sessionStorage.__proto__[\"clear\"]      = function clear(){debugger;};      safefunction(sessionStorage.__proto__[\"clear\"]);\n// sessionStorage.__proto__[\"getItem\"]    = function getItem(){debugger;};    safefunction(sessionStorage.__proto__[\"getItem\"]);\n// sessionStorage.__proto__[\"key\"]        = function key(){debugger;};        safefunction(sessionStorage.__proto__[\"key\"]);\n// sessionStorage.__proto__[\"removeItem\"] = function removeItem(){debugger;}; safefunction(sessionStorage.__proto__[\"removeItem\"]);\n// sessionStorage.__proto__[\"setItem\"]    = function setItem(){debugger;};    safefunction(sessionStorage.__proto__[\"setItem\"]);\n// sessionStorage[\"$_cDro\"] = \"1\";\n// sessionStorage[\"$_YWTU\"] = \"FEQUsSBVzv0QWk6YXiwmU1rTQu5fgYnAS0QCjp2noTZ\";\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n// console.log(1,window)\n// console.log(1,window.constructor)\n// console.log(2,window.__proto__)\n// console.log(2,window.__proto__.constructor)\n// console.log(3,window.__proto__.__proto__)\n// console.log(3,window.__proto__.__proto__.constructor)\n// console.log(4,window.__proto__.__proto__.__proto__)\n// console.log(4,window.__proto__.__proto__.__proto__.constructor)\n// console.log()\n// console.log(5,navigator)\n// console.log(5,navigator.constructor)\n// console.log(6,navigator.__proto__)\n// console.log(6,navigator.__proto__.constructor)\n// console.log(7,navigator.__proto__.__proto__)\n// console.log(7,navigator.__proto__.__proto__.constructor)\n// console.log()\n// console.log(7,document)\n// console.log(7,document.constructor)\n// console.log(8,document.__proto__)\n// console.log(8,document.__proto__.constructor)\n// console.log(9,document.__proto__.__proto__)\n// console.log(9,document.__proto__.__proto__.constructor)\n// console.log(10,document.__proto__.__proto__.__proto__)\n// console.log(10,document.__proto__.__proto__.__proto__.constructor)\n// console.log(11,document.__proto__.__proto__.__proto__.__proto__)\n// console.log(11,document.__proto__.__proto__.__proto__.__proto__.constructor)\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t5补环境框架.md",
    "content": "# 补环境框架\n\n补环境框架可以帮助代码在接近原始环境的条件下执行，相当于前面模板的组合加强版。\n\n---\n\n\n## js-sandbox-env-framework\n\n[https://github.com/lasawang/js-sandbox-env-framework](https://github.com/lasawang/js-sandbox-env-framework)\n\n一个完整的 JavaScript 浏览器环境模拟框架，支持 在线编辑、Proxy 递归代理、环境注入、AI 辅助补环境等功能，专为 JS 逆向工程设计。\n\n---\n\n\n## NodeSandbox\n\n一个基于 jsdom 的沙箱环境，可以。\n\n[https://github.com/bnmgh1/NodeSandbox](https://github.com/bnmgh1/NodeSandbox)\n\n---\n\n## qxVm\n\n[https://github.com/ylw00/qxVm](https://github.com/ylw00/qxVm)\n\n基于 `node16`, `vm2`模块, 纯js设计一个补环境框架。\n\n---\n\n## egg\\_vm2\n\n[https://github.com/theheqiang/egg\\_vm2](https://github.com/theheqiang/egg_vm2)\n\n使用 Node.js 中的 vm2 实现一个简单的浏览器环境。\n\n---\n\n## jsVMEnv\n\n[https://github.com/ipylei/jsVmEnv](https://github.com/ipylei/jsVmEnv)\n"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/readme.md",
    "content": "##  补不了就用浏览器\n\n补环境是指用于在**非浏览器环境**下模拟浏览器运行 JavaScript 的工具。但是实在补不出来也不能一直耗着浪费时间，那就不补了，直接用浏览器环境执行代码。\n\n常用方式 playwright+express+核心JS文件，部署一个持久运行的浏览器实例服务，供远程调用执行JS代码。\n\n例如：\n\n```js\n/* eslint-disable */\nimport { createCipheriv } from 'crypto';\nimport { devices, chromium } from 'playwright-chromium';\nconst iPhone11 = devices['iPhone 11 Pro'];\n\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nfunction getRandomInt(a, b) {\n  const min = Math.min(a, b);\n  const max = Math.max(a, b);\n  const diff = max - min + 1;\n  return min + Math.floor(Math.random() * Math.floor(diff));\n}\n\nclass Signer {\n  static instance = null;\n  userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36';\n  args = [\n    '--disable-blink-features',\n    '--disable-blink-features=AutomationControlled',\n    '--disable-infobars',\n    '--window-size=1920,1080',\n    '--start-maximized',\n  ];\n  // Default TikTok loading page\n  default_url = 'https://www.tiktok.com/@aisarkhaledd';\n\n  // Password for xttparams AES encryption\n  password = 'webapp1.0+202106';\n\n  constructor(default_url, userAgent, browser) {\n    if (default_url) {\n      this.default_url = default_url;\n    }\n    if (userAgent) {\n      this.userAgent = userAgent;\n    }\n\n    if (browser) {\n      this.browser = browser;\n      this.isExternalBrowser = true;\n    }\n\n    this.args.push(`--user-agent='${this.userAgent}'`);\n\n    this.options = {\n      headless: true,\n      args: this.args,\n      ignoreDefaultArgs: ['--mute-audio', '--hide-scrollbars'],\n      ignoreHTTPSErrors: true\n    };\n\n    this.isInitialized = false;\n  }\n\n  static async getInstance() {\n    if (!Signer.instance) {\n      Signer.instance = new Signer();\n      await Signer.instance.init();\n    }\n    return Signer.instance;\n  }\n\n  static async close() {\n    if (Signer.instance) {\n      await Signer.instance.close();\n      Signer.instance = null;\n    }\n  }\n\n  async init() {\n    if (this.isInitialized) {\n      return;\n    }\n    \n    // Get the directory name of the current module\n    const __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n    if (!this.browser) {\n      this.browser = await chromium.launch(this.options);\n    }\n\n    let emulateTemplate = {\n      ...iPhone11,\n      locale: 'en-US',\n      deviceScaleFactor: getRandomInt(1, 3),\n      isMobile: Math.random() > 0.5,\n      hasTouch: Math.random() > 0.5,\n      userAgent: this.userAgent,\n    };\n    emulateTemplate.viewport.width = getRandomInt(320, 1920);\n    emulateTemplate.viewport.height = getRandomInt(320, 1920);\n\n    this.context = await this.browser.newContext({\n      bypassCSP: true,\n      ...emulateTemplate,\n    });\n\n    this.page = await this.context.newPage();\n\n    await this.page.route('**/*', (route) => {\n      return route.request().resourceType() === 'script'\n        ? route.abort()\n        : route.continue();\n    });\n\n    await this.page.goto(this.default_url, {\n      waitUntil: 'networkidle',\n    });\n\n    let LOAD_SCRIPTS = ['webmssdk_5.1.3.js',];\n\n    LOAD_SCRIPTS.forEach(async (script) => {\n      await this.page.addScriptTag({\n        path: path.resolve(__dirname, script),\n      });\n      console.log('[+] ' + script + ' loaded');\n    });\n\n     await this.page.evaluate(() => {\n      window.generateXBogus = function generateXBogus(query, undf) {\n        if (typeof window.__tsign.u[970].v !== 'function') {\n          throw 'No X-Bogus function found';\n        }\n\n        return window.__tsign.u[970].v(query, undf);\n      };\n\n      window.generateXGnarly = function generateXGnarly(query, strBody,baseUrl) {\n        if (typeof window.__tsign.u[971].v !== 'function') {\n          throw 'No X-Gnarly function found';\n        }\n        const p4 = {\n          \"totalXHRRequests\": 70,\n          \"totalFetchRequests\": 25,\n          \"interceptedXHRRequests\": 8,\n          \"interceptedFetchRequests\": 6\n        }\n        return window.__tsign.u[971].v(query, strBody,baseUrl,p4);\n      };\n\n      return this;\n    });\n\n    this.isInitialized = true;\n    console.log('[+] Signer initialized successfully');\n  }\n\n  async navigator() {\n    // Get the 'viewport' of the page, as reported by the page.\n    const info = await this.page.evaluate(() => {\n      return {\n        deviceScaleFactor: window.devicePixelRatio,\n        userAgent: window.navigator.userAgent,\n        browser_language: window.navigator.language,\n        browser_platform: window.navigator.platform,\n        browser_name: window.navigator.appCodeName,\n        browser_version: window.navigator.appVersion,\n      };\n    });\n    return info;\n  }\n\n  async Sign({ url, body = '' }) {\n     //console.log('Sign', { e: url, t: body });\n\n    const params = new URL(url).search.slice(1); // removes the \"?\" from the start\n\n    const xGnarly = await this.page.evaluate(`generateXGnarly('${params}', ${body || 'null'},'${url}')`);\n\n    const xBogus = await this.page.evaluate(`generateXBogus('${params}', ${null})`);\n\n    return { signedUrl:`${url}&X-Bogus=${xBogus}&X-Gnarly=${xGnarly}`, xBogus, xGnarly }\n  }\n\n\n  xttparams(query_str) {\n    query_str += '&is_encryption=1';\n\n    // Encrypt query string using aes-128-cbc\n    const cipher = createCipheriv('aes-128-cbc', this.password, this.password);\n    return Buffer.concat([cipher.update(query_str), cipher.final()]).toString(\n      'base64'\n    );\n  }\n\n  async healthCheck() {\n    if (!this.isInitialized || !this.page) {\n      return false;\n    }\n    \n    try {\n      await this.page.evaluate(() => {\n        return typeof window.generateXBogus === 'function' && typeof window.generateXGnarly === 'function';\n      });\n      return true;\n    } catch (error) {\n      console.error('Health check failed:', error);\n      return false;\n    }\n  }\n\n  async close() {\n    if (this.browser && !this.isExternalBrowser) {\n      await this.browser.close();\n      this.browser = null;\n    }\n    if (this.page) {\n      this.page = null;\n    }\n    this.isInitialized = false;\n  }\n}\n\nexport default Signer;\n\n// Export singleton functions for easier use\nexport const getSigner = () => Signer.getInstance();\nexport const closeSigner = () => Signer.close();\n```\n\n用python库来开发也可以，但是在部署在linux中时往往会有依赖问题，不如playwright官方提供的mcr.microsoft.com/playwright:v1.50.0-noble ，可快速部署。\n\n| 框架名称 | 描述 | 是否支持 DOM | 是否支持浏览器 API | 是否支持 WebAssembly | 是否支持动态执行 |\n| --- | --- | --- | --- | --- | --- |\n| [Node.js + JSDOM](https://github.com/jsdom/jsdom) | 在 Node.js 中模拟浏览器环境 | ✅ | ❌（部分支持） | ❌ | ✅ |\n| \\[Node.js + CJS / ESM 模块模拟\\] | 手动补环境（最常用） | ❌ | ❌ | ❌ | ✅ |\n| [Puppeteer](https://pptr.dev/) | 基于 Chrome DevTools 的控制工具 | ✅ | ✅ | ✅ | ✅ |\n| [Playwright](https://playwright.dev/) | 多浏览器自动化工具（支持 Chromium/Firefox/Webkit） | ✅ | ✅ | ✅ | ✅ |\n| [Selenium](https://www.selenium.dev/) | 经典的浏览器自动化框架 | ✅ | ✅ | ✅ | ✅ |"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/test.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nfrom selenium import webdriver\n\nua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'\nPRO_DIR = os.path.dirname(os.path.abspath(__file__))\n\ns1 = \"\"\"\n    <!DOCTYPE html>\n    <html style=\"font-size: 50px;\">\n    <head>\n        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">  \n        <title>signature-hook</title>\n    </head>\n    <body></body>\n\n    <script type=\"text/javascript\">\n    \"\"\"\ns2 = \"\"\"\n    </script>\n    </html>\n    \"\"\"\n\ndef driver_sig(html_file):\n    option = webdriver.ChromeOptions()\n    option.add_argument('headless')\n    option.add_argument('--no-sandbox')\n    option.add_argument('--user-agent={}'.format(ua))\n    driver = webdriver.Chrome(chrome_options=option)\n    driver.get('file:///'+ PRO_DIR + html_file)\n    sig = driver.title\n    driver.quit()\n    return sig\n\nsign_js = '''\nwindow.navigator = {\n    userAgent: ''\n    };\nfunction get_sign() {\n        ... //此处省略N行代码\n        return sign\n    }\nvar signature = get_sign();\ndocument.clear();\ndocument.write(signature);\n'''\n\nif __name__ == '__main__':\n    doc = sign_js.replace(\"userAgent: ''\",\"userAgent: '{}'\".format(ua))\n    html_file = 'get_sign.html'\n    with open(html_file, 'w', encoding='utf-8') as fw:\n        fw.write(s1 + doc + s2)\n    sig = driver_sig(html_file)\n    print(sig)"
  },
  {
    "path": "第三章：Web Js逆向/3.7 浏览器环境补充/readme.md",
    "content": "# 背景\n\n## 一、什么是“补环境”？\n\n在 JavaScript 逆向中，“补环境”指的是**在非浏览器环境中模拟或还原浏览器运行 JavaScript 所需的上下文环境**，以便能够让目标 JavaScript 脚本正常执行。\n\n简单来说，就是**构建一个浏览器的“假环境”**，让被逆向的 JS 代码以为它是在浏览器中运行，从而可以顺利执行并输出我们需要的结果。\n\n所以“补环境”是 WebJS 逆向中的核心技能之一，它是连接爬虫与前端加密逻辑的重要桥梁。\n\n掌握补环境技术，不仅可以提升逆向分析能力，还能帮助开发者更好地理解浏览器机制和 JS 执行原理。\n\n---\n\n## 二、为什么需要“补环境”？\n\nJavaScript 代码通常是在浏览器环境中运行的，依赖于浏览器提供的各种全局对象（如 `window`、`document`、`navigator`）和内置函数（如 `fetch`、`XMLHttpRequest`、`setTimeout`）等。\n\n但当我们使用 Node.js、Python 的 `execjs`、`Pyppeteer`、`Playwright` 或者一些沙盒工具来执行网页中的 JS 代码时，这些环境并不具备浏览器完整的执行上下文，导致 JS 代码无法正常运行，甚至直接报错。\n\n---\n\n## 三、补环境的原理\n\nJavaScript 是一种动态语言，其运行依赖于当前的执行环境。在浏览器中，JS 代码可以访问一系列全局对象和函数，比如：\n\n*   `window`\n    \n*   `document`\n    \n*   `location`\n    \n*   `navigator`\n    \n*   `history`\n    \n*   `localStorage`\n    \n*   `sessionStorage`\n    \n*   `XMLHttpRequest`\n    \n*   `fetch`\n    \n*   `setTimeout` / `setInterval`\n    \n\n在非浏览器环境中，这些对象和函数可能缺失或功能不全。补环境的核心原理就是：\n\n1.  **手动或自动模拟缺失的全局对象和函数**\n    \n2.  **拦截和重写关键函数，使其返回预期结果**\n    \n3.  **绕过环境检测机制（如 navigator.webdriver、proto 等）**\n    \n\n---\n\n## 四、补环境的常见方法\n\n### 1. 手动补环境\n\n适用于小型 JS 代码或对性能要求不高的场景。\n\n**示例：**\n\n```javascript\n// 手动补 window 和 document\nvar window = {};\nvar document = {\n    cookie: \"\",\n    createElement: function() {\n        return {};\n    }\n};\n```\n\n### 2. 使用浏览器模拟工具（如 Puppeteer、Playwright）\n\n这些工具启动一个无头浏览器，自动提供完整的执行环境，适合需要复杂交互的场景。\n\n```javascript\nconst puppeteer = require('puppeteer');\n\n(async () => {\n    const browser = await puppeteer.launch();\n    const page = await browser.newPage();\n    await page.goto('https://example.com');\n    const result = await page.evaluate(() => {\n        return someFunction(); // 在浏览器环境中执行\n    });\n    console.log(result);\n    await browser.close();\n})();\n```\n\n### 3. 使用沙盒工具 + 环境模拟库（如 jsdom、happy-dom）\n\n这些库可以在 Node.js 环境中模拟 DOM 和浏览器 API。\n\n```javascript\nconst { JSDOM } = require('jsdom');\nconst dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);\nglobal.window = dom.window;\nglobal.document = dom.window.document;\n```\n\n### 4. 使用逆向工具（如 Hook、调试器）\n\n在补环境时，可以使用调试器（如 Chrome DevTools、Frida、Hook.js）来动态分析 JS 代码，找出关键函数和环境检测点，进行模拟或绕过。\n\n---\n\n## 五、补环境的难点\n\n1.  **环境检测复杂化**：网站可能使用多重检测手段，如 `Function.toString()`、`Proxy`、`WebAssembly` 等。\n    \n2.  **依赖浏览器特性**：某些 JS 代码依赖浏览器渲染引擎（如 Canvas、WebGL）生成特定值。\n    \n3.  **性能问题**：使用 Puppeteer 等完整浏览器模拟时，资源消耗较大。\n    \n4.  **加密代码混淆**：JS 代码被混淆后难以理解，补环境难度加大。\n    \n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.0 加密方法远程调用/readme.md",
    "content": "加密方法的远程调用主要是使用了RPC协议，RPC（Remote Procedure Call）是远程调用的意思。RPC的应用十分广泛，比如在分布式中的进程间通讯、微服务中的节点通讯。\n\n我们这里使用的rpc其实是实现两个不同进程通信的一种方式，比如在浏览器执行一些方法，将结果返回给本地使用。\n\n在JS逆向这块，不论是selenium、cefpython、puppeteer或者其他工具都可以实现。\n\n大家可以按照书中的案例进行练习。\n\n此文件夹中会更新一些新的案例供大家学习。\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.0 加密方法远程调用/头条系web-RPC.md",
    "content": "以头条系某短视频（dy）web页面搜索为例，通过RPC的逻辑实现数据采集。\n\n目前方案通用于头条系web页面。因为其当前产品大都基于XMLHttpRequest的send方法做一些校验，我们可以自启一个浏览器去完成XMLHttpRequest请求，直接获取返回的responseText。\n\n话虽如此，此方案仅是为了配合书中的教程供大家学习，并不代表是最优选择，主要是给大家提供一种思路和方法。\n\n代码逻辑很简单，只有50行代码，有不懂的问题可私信或留言。\n\n更多精彩内容：[《爬虫逆向进阶实战》](http://t.csdn.cn/mEa64)\n\n\n\n---\n\n## 调试分析\n\n因受版权影响，我会避开关键词。\n\n先找一下其发送逻辑，堆栈第一个点进去。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/cf1f35c4f31d41caa0f475c007b6812f.png)\n\n断点后调试，可看到t即是XMLHttpRequest。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/4e5018337a0449a0a9de97abe79ecc28.png)\n\n查看t对象。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/0036cd99a8e746d7af74c8c5fa5a35ea.png)\n\n\n在浏览器中调试。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/32124b7fa3764128900c9b454c8947d2.png)\n\n\n查看响应。 当前已经返回了responseText和带了签名的responseURL。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/85026da13f6545a19db303a781b23a49.png)\n\n\n---\n\n## Python实现\n注意：url要换成自己浏览器上的。\n```python\n# -*- coding: utf-8 -*-\n# @UpdataTime : 2022/6/1 16:00\n# @Author  : lx\n\nfrom selenium import webdriver\n\nclass Browser():\n    def __init__(self, **kwargs):\n        # TODO： update your executablePath\n        executablePath = r\"chromedriver.exe\"\n        self.executablePath = kwargs.get(\"executablePath\",executablePath )\n        options = webdriver.ChromeOptions()\n        self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)\n        self.browser.get('https://www.douyin.com')\n\n    def search_item(self, keyword):\n        doc = self.browser.execute_script('''\n            function queryData(url) {\n               var p = new Promise(function(resolve,reject) {\n                   var e={\n                           \"url\":\"https://www.douyin.com/aweme/v1/web/search/item/?device_platform=webapp&aid=6383&channel=channel_pc_web&search_channel=aweme_video_web&sort_type=0&publish_time=0&keyword=%s&search_source=normal_search&query_correct_type=1&is_filter_search=0&from_group_id=&offset=0&count=10&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=102.0.5005.63&browser_online=true&engine_name=Blink&engine_version=102.0.5005.63&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7097114192884565534\",\n                           \"method\":\"GET\"\n                         };\n                    var h = new XMLHttpRequest;\n                    h.open(e.method, e.url, true);\n                    h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");  \n                    h.setRequestHeader(\"salute-by\",\"lx\");  \n                    h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n                    h.onreadystatechange =function() {\n                         if(h.readyState === 4 && h.status  ===200) {\n                             resolve(h.responseText);\n                         } else {}\n                    };\n                    h.send(null);\n                    });\n                    return p;\n                }\n            var p1 = queryData('lx');\n            res = Promise.all([p1]).then(function(result){\n                    return result\n            })\n            return res\n        ''' % (keyword))\n        return doc[0]\n\n    def close(self):\n        self.browser.close()\n        self.browser.quit()\n\n\nbrowser = Browser()\n# 注意：如果没打印内容，把url换成自己浏览器上的。还不行就在控制台上执行js看是否有误。\n# 版本 102.0.5005.63（正式版本） （64 位）\nprint(browser.search_item('爬虫逆向进阶实战'))\nprint(browser.search_item('RPC'))\nprint(browser.search_item('案例'))\nprint(browser.search_item('教程'))\nprint(browser.search_item('公众号'))\nprint(browser.search_item('pythonlx'))\nbrowser.close()\n```\n\n---\n\n## 执行结果\n![在这里插入图片描述](https://img-blog.csdnimg.cn/f7602589b1334435a6c0b2a7df2d502c.png)\n\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/client.js",
    "content": "!function(){\n     if (window.flagLX){}\n     else{\n    window.weiboLx = makeRequest;\n    var ws = new WebSocket(\"ws://127.0.0.1:9999\");\n    window.flagLX =true;\n    ws.open = function(evt){};\n    ws.onmessage = function(evt){\n        var lx = evt.data;\n        var result = lx.split(\",\");\n        var res = window.weiboLx(result[0],result[1],7,false);\n        ws.send(JSON.stringify(res));\n    }}\n}();\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/server.py",
    "content": "import asyncio\nimport websockets\nimport time\n\nasync def check_permit(websocket):\n    # 账号列表\n    for send_text in [\n        '11111111111,111',\n        '11111111112,112',\n        '11111111113,113',\n        '11111111114,114'\n    ]:\n        await websocket.send(send_text)\n    return True\n\nasync def recv_msg(websocket):\n    while 1:\n        recv_text = await websocket.recv()\n        print(recv_text)\n\nasync def main_logic(websocket, path):\n    await check_permit(websocket)\n    await recv_msg(websocket)\n\nstart_server = websockets.serve(main_logic, '127.0.0.1', 9999)\nasyncio.get_event_loop().run_until_complete(start_server)\nasyncio.get_event_loop().run_forever()\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/2022-05-25更新.md",
    "content": "## update:  2022-05-25\n\n本文内容是继之前失效文章的补充。 RPC的方法大家应该都从书中掌握了。  (虽然官网更新了，但是没有掌握的还可以看一下视频)\n\n\n所以长话短说，本篇的内容是找新版本弹幕wss协议的RPC的入口点，并进行RPC调用。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/83e6658b6f3c4957ab6705a04c9925d3.png)\n\n\n\n---\n\n## 定位\n\n在JS中，websocket 的  new WebSocket()  是固定的语法，可以用做我们定位的关键词。\n\nwebSocket.send 用于向服务器发送数据\nwebSocket.onopen 用于指定连接成功后的回调函数\nwebSocket.onmessage  用于指定收到服务器数据后的回调函数\nwebSocket.onclose 用于指定连接关闭后的回调函数\nwebsocket.binaryType = 'arraybuffer';   用来表示通用的、固定长度的原始二进制数据缓冲区\n\n\n---\n\nRPC最重要的是找到入口点。一般消息处理函数为onmessage 或者 addEventListener(\"message\")\n\n```js\nws.onmessage = function(event) {\n  var data = event.data;\n};\n \nws.addEventListener(\"message\", function(event) {\n  var data = event.data;\n});\n```\n\n全局检索一下，找到this.client.addEventListener(\"message\"\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a3f452a527644875981a38e7a79197e0.png)\n断点往下走，进入bindClientMessage\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ea1cbd83f5704f84b422f8e3ad07a232.png)\n\no = n.Response.deserializeBinary   \n\n顾名思义，o是响应内容反序列化的二进制，控制台打印下，可以看到关键词WebcastSocialMessage。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/58da43dd97a04e09a3370265841556a0.png)\n\n继续往下看代码，if (\"msg\" === t.getPayloadType() ， (()=>o.toObject()))\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/c40cdbcb8d684fb8a378d0e6ef0af1f2.png)\n现在已经能看到一些明文信息了，但是payload的内容似乎经过base64。\n\natob一下试试，可以看出这是protobuf序列化后的数据。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/76d33472eee941c18e8e31f6cf758f75.png)\n\n所以打好断点继续调试。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/0f7ca8f1d8aa4760ab2a4c8d272156c9.png)\n\n走到runAllEvents中，发现了protobuf反序列化后的数据。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/57f3ede5764f45659b8080f4ae806e1c.png)\n\n\n\n\n---\n\n找到位置后，还是用之前的RPC方法即可。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/f76f8390c3f44f20b6243b9c48670f52.png)\n\n把数据发送到本地。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/42ba93680a6a4b858c44a6c863e83631.png)\n\n\n---\n\n## RPC调用\n\n通过wss协议发数据。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/22b385b8520a4168ae59c29972c45d13.png)\n\n把发数据的代码加上，然后在本地起一个服务端。\n\n\n```python\nimport asyncio\nimport websockets\n\nasync def check_permit(websocket):\n    send_text = 'lx'\n    await websocket.send(send_text)\n    return True\n\n\nasync def recv_msg(websocket):\n    while 1:\n        recv_text = await websocket.recv()\n        print(recv_text)\n\n\nasync def main_logic(websocket, path):\n    await check_permit(websocket)\n    await recv_msg(websocket)\n\n\nstart_server = websockets.serve(main_logic, '127.0.0.1', 9999)\nasyncio.get_event_loop().run_until_complete(start_server)\nasyncio.get_event_loop().run_forever()\n```\n\n\n\n\n---\n\n运行测试，大功告成！\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/70be2ffec3eb46bd81246109443f207f.png)\n\n\n只要大家只要掌握到方法，无论网站怎么改都能从容面对。\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/client.js",
    "content": "// 这是当前新版的\nwindow.dataLx = s.toObject();\n!function(){\n            var res = window.dataLx;\n            if (window.flagLX){\n                    window.wsLX.send(JSON.stringify(res));\n            } \n            else{\n                    var ws = new WebSocket(\"ws://127.0.0.1:9999\");\n                    window.wsLX = ws;\n                    window.flagLX = true;\n                    ws.open = function(evt){};\n                    ws.onmessage = function(evt){\n                        ws.send(JSON.stringify(res));\n                    }\n            }\n}();\n\n\n\n// 这是视频中老版本的\nwindow.dataLx = r;                                                                                                                               \n!function(){\n   var res = window.dataLx;\n   if (window.flagLX){\n          window.wsLX.send(JSON.stringify(res));\n   }\n   else{\n          var ws = new WebSocket(\"ws://127.0.0.1:9999\");\n          window.wsLX = ws;\n          window.flagLX =true;\n          ws.open = function(evt){};\n          ws.onmessage = function(evt){\n              ws.send(JSON.stringify(res));\n }}\n}();\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/readme.md",
    "content": "\n1、更新内容在 2022-05-25更新.md 中\n\n2、更新的视频在 https://www.bilibili.com/video/BV1o34y1L7RX/\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/server.py",
    "content": "import asyncio\nimport websockets\n\nasync def check_permit(websocket):\n    send_text = 'lx'\n    await websocket.send(send_text)\n    return True\n\nasync def recv_msg(websocket):\n    while 1:\n        recv_text = await websocket.recv()\n        print(recv_text)\n\nasync def main_logic(websocket, path):\n    await check_permit(websocket)\n    await recv_msg(websocket)\n\nstart_server = websockets.serve(main_logic, '127.0.0.1', 9999)\nasyncio.get_event_loop().run_until_complete(start_server)\nasyncio.get_event_loop().run_forever()"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index20231108.py",
    "content": "import json\nfrom selenium import webdriver\n\n\nclass Browser():\n    def __init__(self, **kwargs, ):\n        self.debug = kwargs.get(\"debug\", False)\n        self.proxy = kwargs.get(\"proxy\", None)\n        self.api_url = kwargs.get(\"api_url\", None)\n        self.referrer = kwargs.get(\"referer\", \"https://trendinsight.oceanengine.com/\")\n        # TODO： update your executablePath\n        self.executablePath = kwargs.get(\"executablePath\", r\"C:\\Users\\lx\\Desktop\\driver\\chromedriver.exe\")\n\n        args = kwargs.get(\"browser_args\", [])\n        options = kwargs.get(\"browser_options\", {})\n\n        if len(args) == 0:\n            self.args = []\n        else:\n            self.args = args\n\n        options = webdriver.ChromeOptions()\n        options.add_argument(\"--headless\")\n        options.add_argument(\"log-level=2\")\n        self.options = {\n            #\"headless\": True,\n            \"handleSIGINT\": True,\n            \"handleSIGTERM\": True,\n            \"handleSIGHUP\": True,\n        }\n\n        if self.proxy is not None:\n            if \"@\" in self.proxy:\n                server_prefix = self.proxy.split(\"://\")[0]\n                address = self.proxy.split(\"@\")[1]\n                self.options[\"proxy\"] = {\n                    \"server\": server_prefix + \"://\" + address,\n                    \"username\": self.proxy.split(\"://\")[1].split(\":\")[0],\n                    \"password\": self.proxy.split(\"://\")[1].split(\"@\")[0].split(\":\")[1],\n                }\n            else:\n                self.options[\"proxy\"] = {\"server\": self.proxy}\n\n        if self.executablePath is not None:\n            self.options[\"executablePath\"] = self.executablePath\n\n        self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)\n\n        self.browser.get('https://trendinsight.oceanengine.com/arithmetic-index')\n\n        for k, v in cks.items():\n            self.browser.add_cookie({\"name\": k, \"value\": v})\n        self.browser.refresh()\n\n\n\n    def signature(self, keyword, start_date, end_date):\n        sign_url = self.browser.execute_script('''\n                    function queryData(url) {\n                       var p = new Promise(function(resolve,reject) {\n                           var e={\"url\":\"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend\",\n                                    \"method\":\"POST\",\n                                    \"data\" : '{\"keyword_list\": [\"%s\"],\"start_date\": \"%s\",\"end_date\": \"%s\",\"app_name\": \"aweme\"}'};\n                            var h = new XMLHttpRequest;h.open(e.method, e.url, true);\n                            h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");  \n                            h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n                            h.setRequestHeader(\"tea-uid\",\"7054893410171930123\");\n                            h.onreadystatechange =function() {\n                                 if(h.readyState != 4) return;\n                                 if(h.readyState === 4 && h.status  ===200) {\n                                    resolve(h.responseText);\n                                 } else {\n                                  }\n                            };\n                            h.send(e.data);\n                            });\n                            return p;\n                        }\n                    var p1 = queryData('lx');\n                    res = Promise.all([p1]).then(function(result){\n                    return result\n                    })\n                    return res;\n        ''' % (keyword, start_date, end_date))\n        '''\n        let e={\"url\":\"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend\",\n                                \"method\":\"POST\",\n                                \"data\" : '{\"keyword_list\":[\"lx\"],\"start_date\":\"20220430\",\"end_date\":\"20220530\",\"app_name\":\"aweme\"}'};\n        var h = new XMLHttpRequest;h.open(e.method, e.url, true);\n        h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");\n        h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n        h.setRequestHeader(\"tea-uid\",\"7054893410171930123\");\n                h.onreadystatechange=function(){\n                    if (h.status===200){\n                       console.log(h.responseText)\n                       console.log(h.responseURL)\n                    }\n                }\n        h.send(e.data);\n        '''\n        return sign_url[0]\n\n    def decrypt(self,data):\n        text = self.browser.execute_script('''\n        function d(e) {\n            var t = e ;\n            var n = atob(t);\n            var r = new Uint8Array(n.length);\n            for (var i = 0; i < n.length; i++) {\n                r[i] = n.charCodeAt(i);\n            }\n            return r;\n        }\n        var text = \"%s\";\n        var key = \"kbSjOqn9O7APLqUZxdCkTQ==\";\n        var iv = \"JuhL1cOV5JH9ojzt2g2EPg==\";\n        \n        async function decrypt(text,key,iv) {\n            var t = d(key);\n            var i = d(iv);\n            var r = await window.crypto.subtle.importKey(\"raw\", t, \"AES-CBC\", !0, [\"decrypt\"]);\n            var result = await window.crypto.subtle.decrypt({\n                name: \"AES-CBC\",\n                iv: i\n            }, r, d(text));\n            result = (new TextDecoder()).decode(result)\n            return result\n        }\n        function getResult(){\n            var p = decrypt(text,key,iv);\n            return Promise.all([p]).then(data=>{\n                console.log(data)\n                return data[0]\n            })\n        }\n\n        var p1 = getResult();\n        res = Promise.all([p1]).then(function(result){\n            return result\n        })\n       return res\n        '''%data)\n        return text[0]\n\n\n    def responseText(self, keyword, start_date, end_date):\n        doc = self.browser.execute_script('''\n                    function queryData(url) {\n                       var p = new Promise(function(resolve,reject) {\n                           var e={\"url\":\"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend\",\n                                    \"method\":\"POST\",\n                                    \"data\" : '{\"keyword_list\": [\"%s\"],\"start_date\": \"%s\",\"end_date\": \"%s\",\"app_name\": \"aweme\"}'};\n                            var h = new XMLHttpRequest;h.open(e.method, e.url, true);\n                            h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");  \n                            h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n                            h.setRequestHeader(\"tea-uid\",\"7054893410171930123\");\n                            h.onreadystatechange =function() {\n                                 if(h.readyState != 4) return;\n                                 if(h.readyState === 4 && h.status  ===200) {\n                                    resolve(h.responseText);\n                                 } else {\n                                  }\n                            };\n                            h.send(e.data);\n                            });\n                            return p;\n                        }\n                    var p1 = queryData('lx');\n                    res = Promise.all([p1]).then(function(result){\n                    return result\n                    })\n                    return res;\n        ''' % (keyword, start_date, end_date))\n        return doc[0]\n\n    def close(self):\n        self.browser.close()\n        self.browser.quit()\n\n\ndef get_data(keyword, start_date, end_date):\n    text = browser.signature(keyword=keyword, start_date=start_date, end_date=end_date)\n    data = json.loads(text)['data']\n    doc = browser.decrypt(data)\n    return doc\n\n\n\nif __name__ == '__main__':\n    cookies = \"\"  # \"把你登录后的cookie复制到这里\"\n    cks = {}\n    for k in cookies.split(';'):\n        c = k.split('=')\n        cks[c[0].replace(' ','')] = c[1]\n\n    browser = Browser()\n    print(get_data(keyword='lx', start_date=\"20231106\", end_date=\"20231107\"))\n    print(get_data(keyword='鞠婧祎', start_date=\"20231106\", end_date=\"20231107\"))\n    browser.close()\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_0.py",
    "content": "# -*- coding: utf-8 -*-\n# @Time    : 2021/9/27 14:46\n# @Author  : lx\n\nfrom selenium import webdriver\nfrom lxpy import copy_headers_dict\nimport requests\n\nh = copy_headers_dict('''\n    accept: application/json, text/plain, */*\n    accept-encoding: gzip, deflate, br\n    accept-language: zh-CN,zh;q=0.9\n    cache-control: no-cache\n    content-length: 89\n    content-type: application/json;charset=UTF-8\n    cookie: i18next=zh; MONITOR_WEB_ID=75a85826-c1b9-49f2-b7f8-7a1a383b4dd6; x-jupiter-uuid=16327104466868524; Hm_lvt_c36ebf0e0753eda09586ef4fb80ea125=1632709872,1632710446; Hm_lpvt_c36ebf0e0753eda09586ef4fb80ea125=1632710446; tt_scid=4hsZnfHNAtmWGSi4MWUNz-N1DPpijAYZKyzkeKneA2n.ECIhOKPqYLGHBiH8H5zm15f6; s_v_web_id=verify_ku21n812_2kf7njXo_yptW_4Q86_BXNX_Y67hNBvJscUD; _csrf_token=R1pNiIx5y40wvC5reN0CybZa\n    origin: https://trendinsight.oceanengine.com\n    pragma: no-cache\n    referer: https://trendinsight.oceanengine.com/arithmetic-index/analysis?keyword=lx\n    sec-ch-ua: \"Google Chrome\";v=\"93\", \" Not;A Brand\";v=\"99\", \"Chromium\";v=\"93\"\n    sec-ch-ua-mobile: ?0\n    sec-ch-ua-platform: \"Windows\"\n    sec-fetch-dest: empty\n    sec-fetch-mode: cors\n    sec-fetch-site: same-origin\n    tea-uid: 6945252828761294374\n    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36\n    ''')\n\n\nclass Browser():\n    def __init__(self, **kwargs, ):\n        self.debug = kwargs.get(\"debug\", False)\n        self.proxy = kwargs.get(\"proxy\", None)\n        self.api_url = kwargs.get(\"api_url\", None)\n        self.referrer = kwargs.get(\"referer\", \"https://trendinsight.oceanengine.com/\")\n        # TODO： update your executablePath\n        self.executablePath = kwargs.get(\"executablePath\", r\"C:\\Users\\feiyi\\Desktop\\driver\\chromedriver.exe\")\n\n        args = kwargs.get(\"browser_args\", [])\n        options = kwargs.get(\"browser_options\", {})\n\n        if len(args) == 0:\n            self.args = []\n        else:\n            self.args = args\n\n        options = webdriver.ChromeOptions()\n        options.add_argument(\"--headless\")\n        options.add_argument(\"log-level=2\")\n        self.options = {\n            \"headless\": True,\n            \"handleSIGINT\": True,\n            \"handleSIGTERM\": True,\n            \"handleSIGHUP\": True,\n        }\n\n        if self.proxy is not None:\n            if \"@\" in self.proxy:\n                server_prefix = self.proxy.split(\"://\")[0]\n                address = self.proxy.split(\"@\")[1]\n                self.options[\"proxy\"] = {\n                    \"server\": server_prefix + \"://\" + address,\n                    \"username\": self.proxy.split(\"://\")[1].split(\":\")[0],\n                    \"password\": self.proxy.split(\"://\")[1].split(\"@\")[0].split(\":\")[1],\n                }\n            else:\n                self.options[\"proxy\"] = {\"server\": self.proxy}\n\n        if self.executablePath is not None:\n            self.options[\"executablePath\"] = self.executablePath\n\n        self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)\n        self.browser.get('https://trendinsight.oceanengine.com/arithmetic-index')\n\n    def signature(self, keyword, start_date, end_date):\n        sign_url = self.browser.execute_script('''\n                var e={\"url\":\"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend\",\n                        \"method\":\"POST\",\n                        \"data\" : '{\"keyword_list\": [\"%s\"],\"start_date\": \"%s\",\"end_date\": \"%s\",\"app_name\": \"aweme\"}'};\n                var h = new XMLHttpRequest;h.open(e.method, e.url, true);\n                h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");  \n                h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n                h.send(e.data);\n                return h._url\n        ''' % (keyword, start_date, end_date))\n        return sign_url\n\n    def close(self):\n        self.browser.close()\n        self.browser.quit()\n\n\ndef get_data(keyword, start_date, end_date):\n    data = '{\"keyword_list\": [\"%s\"],\"start_date\": \"%s\",\"end_date\": \"%s\",\"app_name\": \"aweme\"}' % (\n    keyword, start_date, end_date)\n    sign_url = browser.signature(keyword=keyword, start_date=start_date, end_date=end_date)\n    print(sign_url)\n    doc = requests.post(sign_url, headers=h, data=data.encode()).json()['data']\n    return doc\n\n\nimport base64\nfrom Crypto.Cipher import AES\n\n# AES-128\ndef decrtptlx(String):\n    iv = \"amlheW91LHFpYW53\".encode(encoding='utf-8')\n    key = 'anN2bXA2NjYsamlh'.encode(encoding='utf-8')\n    cryptor = AES.new(key=key, mode=AES.MODE_CFB, IV=iv, segment_size=128)\n    decode = base64.b64decode(String)\n    plain_text = cryptor.decrypt(decode)\n    print(plain_text)\n    return plain_text\n\n\nbrowser = Browser()\n# test\ndecrtptlx(get_data(keyword='lx', start_date=\"20210826\", end_date=\"20210926\"))\n# test\ndecrtptlx(get_data(keyword = '鞠婧祎',start_date = \"20210826\",end_date = \"20210926\"))\n# 需要修改driver-path\nbrowser.close()\n  \n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_1.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport json\nfrom selenium import webdriver\nfrom lxpy import copy_headers_dict\n\nh = copy_headers_dict('''\n    accept: application/json, text/plain, */*\n    accept-encoding: gzip, deflate, br\n    accept-language: zh-CN,zh;q=0.9\n    cache-control: no-cache\n    content-length: 89\n    content-type: application/json;charset=UTF-8\n    cookie: i18next=zh; MONITOR_WEB_ID=75a85826-c1b9-49f2-b7f8-7a1a383b4dd6; x-jupiter-uuid=16327104466868524; Hm_lvt_c36ebf0e0753eda09586ef4fb80ea125=1632709872,1632710446; Hm_lpvt_c36ebf0e0753eda09586ef4fb80ea125=1632710446; tt_scid=4hsZnfHNAtmWGSi4MWUNz-N1DPpijAYZKyzkeKneA2n.ECIhOKPqYLGHBiH8H5zm15f6; s_v_web_id=verify_ku21n812_2kf7njXo_yptW_4Q86_BXNX_Y67hNBvJscUD; _csrf_token=R1pNiIx5y40wvC5reN0CybZa\n    origin: https://trendinsight.oceanengine.com\n    pragma: no-cache\n    referer: https://trendinsight.oceanengine.com/arithmetic-index/analysis?keyword=lx\n    sec-ch-ua: \"Google Chrome\";v=\"93\", \" Not;A Brand\";v=\"99\", \"Chromium\";v=\"93\"\n    sec-ch-ua-mobile: ?0\n    sec-ch-ua-platform: \"Windows\"\n    sec-fetch-dest: empty\n    sec-fetch-mode: cors\n    sec-fetch-site: same-origin\n    tea-uid: 6945252828761294374\n    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36\n    ''')\n\n\nclass Browser():\n    def __init__(self, **kwargs, ):\n        self.debug = kwargs.get(\"debug\", False)\n        self.proxy = kwargs.get(\"proxy\", None)\n        self.api_url = kwargs.get(\"api_url\", None)\n        self.referrer = kwargs.get(\"referer\", \"https://trendinsight.oceanengine.com/\")\n        # TODO： update your executablePath\n        self.executablePath = kwargs.get(\"executablePath\", r\"chromedriver.exe\")\n\n        args = kwargs.get(\"browser_args\", [])\n        options = kwargs.get(\"browser_options\", {})\n\n        if len(args) == 0:\n            self.args = []\n        else:\n            self.args = args\n\n        options = webdriver.ChromeOptions()\n        options.add_argument(\"--headless\")\n        options.add_argument(\"log-level=2\")\n        self.options = {\n            \"headless\": True,\n            \"handleSIGINT\": True,\n            \"handleSIGTERM\": True,\n            \"handleSIGHUP\": True,\n        }\n\n        if self.proxy is not None:\n            if \"@\" in self.proxy:\n                server_prefix = self.proxy.split(\"://\")[0]\n                address = self.proxy.split(\"@\")[1]\n                self.options[\"proxy\"] = {\n                    \"server\": server_prefix + \"://\" + address,\n                    \"username\": self.proxy.split(\"://\")[1].split(\":\")[0],\n                    \"password\": self.proxy.split(\"://\")[1].split(\"@\")[0].split(\":\")[1],\n                }\n            else:\n                self.options[\"proxy\"] = {\"server\": self.proxy}\n\n        if self.executablePath is not None:\n            self.options[\"executablePath\"] = self.executablePath\n\n        self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)\n        self.browser.get('https://trendinsight.oceanengine.com/arithmetic-index')\n\n    def signature(self, keyword, start_date, end_date):\n        sign_url = self.browser.execute_script('''\n                    function queryData(url) {\n                       var p = new Promise(function(resolve,reject) {\n                           var e={\"url\":\"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend\",\n                                    \"method\":\"POST\",\n                                    \"data\" : '{\"keyword_list\": [\"%s\"],\"start_date\": \"%s\",\"end_date\": \"%s\",\"app_name\": \"aweme\"}'};\n                            var h = new XMLHttpRequest;h.open(e.method, e.url, true);\n                            h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");  \n                            h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n                            h.setRequestHeader(\"tea-uid\",\"7054893410171930123\");\n                            h.onreadystatechange =function() {\n                                 if(h.readyState != 4) return;\n                                 if(h.readyState === 4 && h.status  ===200) {\n                                    resolve(h.responseText);\n                                 } else {\n                                  }\n                            };\n                            h.send(e.data);\n                            });\n                            return p;\n                        }\n                    var p1 = queryData('lx');\n                    res = Promise.all([p1]).then(function(result){\n                    return result\n                    })\n                    return res;\n        ''' % (keyword, start_date, end_date))\n        '''\n        let e={\"url\":\"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend\",\n                                \"method\":\"POST\",\n                                \"data\" : '{\"keyword_list\":[\"lx\"],\"start_date\":\"20220430\",\"end_date\":\"20220530\",\"app_name\":\"aweme\"}'};\n        var h = new XMLHttpRequest;h.open(e.method, e.url, true);\n        h.setRequestHeader(\"accept\",\"application/json, text/plain, */*\");\n        h.setRequestHeader(\"content-type\",\"application/json;charset=UTF-8\");\n        h.setRequestHeader(\"tea-uid\",\"7054893410171930123\");\n                h.onreadystatechange=function(){\n                    if (h.status===200){\n                       console.log(h.responseText)\n                       console.log(h.responseURL)\n                    }\n                }\n        h.send(e.data);\n        '''\n        return sign_url[0]\n\n    def close(self):\n        self.browser.close()\n        self.browser.quit()\n\n\ndef get_data(keyword, start_date, end_date):\n    data = '{\"keyword_list\": [\"%s\"],\"start_date\": \"%s\",\"end_date\": \"%s\",\"app_name\": \"aweme\"}' % (keyword, start_date, end_date)\n    data = browser.signature(keyword=keyword, start_date=start_date, end_date=end_date)\n    doc = json.loads(data)['data']\n    return doc\n\nimport base64\nfrom Crypto.Cipher import AES\n\n# AES-128\ndef decrtptlx(String):\n    iv = \"amlheW91LHFpYW53\".encode(encoding='utf-8')\n    key = 'anN2bXA2NjYsamlh'.encode(encoding='utf-8')\n    cryptor = AES.new(key=key, mode=AES.MODE_CFB, IV=iv, segment_size=128)\n    decode = base64.b64decode(String)\n    plain_text = cryptor.decrypt(decode)\n    print(plain_text)\n    return plain_text\n\n\nbrowser = Browser()\n# test\ndecrtptlx(get_data(keyword='lx', start_date=\"20210826\", end_date=\"20210926\"))\n# test\ndecrtptlx(get_data(keyword = '鞠婧祎',start_date = \"20210826\",end_date = \"20210926\"))\n\nbrowser.close()\n\n"
  },
  {
    "path": "第三章：Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/readme.md",
    "content": "(TODO:之前的版本失效了，大家查看最近提交的文件，旧版可作为参考)\n\n对RPC来讲，需要找可调用的方法入口，像头条系这种在send后重写url的，可以通过查找xmlhttprequest堆栈来定位。\n\n\n![image](https://user-images.githubusercontent.com/45314745/171310204-09a84299-544e-4fd2-bc1f-bc6cd61e2284.png)\n\n\n找到h.onreadystatechange,可知h就是xmlhttprequest对象.在控制台输出可以看到responseURL中生成了带签名的url。\n\n\n![image](https://user-images.githubusercontent.com/45314745/171310487-323cd907-0105-4946-b9b9-f3f88e00c4f1.png)\n\n\n所以我们按照书中方法，进行模拟执行即可。 （可以看视频教程有助理解）\n\n\n代码中需要安装的依赖库： requests、lxpy、selenium、Crypto\n\nCrypto库下载链接：https://pan.baidu.com/s/1xOg9qKWNsMfmWuT20Gf9FA?pwd=9999\n"
  },
  {
    "path": "第九章：安卓逆向案例/9.0 书外新增案例/cntvnews.md",
    "content": "base64:  5aSu6KeG5paw6Ze7YXBw\n\n# 版本9.2.0\n\n标准HMACSHA256加密，算法助手pro即可分析。\n\n## x-emas-gw-sign参数\n\n`emas_gw_utdid`：aVaQIP4xdkADAGQcvpa5LIuC\n\n`emas_gw_ttid`：1618388776598@CCNews\\_Android\\_10.11.0\n\n`fe`：先对params按key排序，&拼接键值对，生成md5哈希值。\n\n`c` ：c = str(round(time.time()))\n\nhmac msg:  `f'{emas_gw_utdid}&&&20000008&{fe}&{c}&emas.feed.iflow.server.getchannelitems&1.0.0&&{emas_gw_ttid}&&&27'`\n\nhmac key：3df8017cb9367f5997ab9e4b19c1e028"
  },
  {
    "path": "第九章：安卓逆向案例/9.0 书外新增案例/readme.md",
    "content": "以文章内容展示，给大家分享在逆向过程中遇到的一些签名和加密参数。\n\n"
  },
  {
    "path": "第九章：安卓逆向案例/9.0 书外新增案例/凤凰新闻app.md",
    "content": "# 凤凰新闻app \n\n# 版本7.38.0\n\n## 接口\n\nnine.ifeng.com/wemediacontentlist\n\n## 脱壳\n\n腾讯加固：com.tencent.StubShell.TxAppEntry\n\n通过反射大师，断网脱壳，导出dex。（用别的也行）\n\n## sn参数\n\n一些字符串拼接后MD5，盐值在so中： \"acF%#\\*{\\_b1mQt@..ifvy\"\n\n![image.png](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/3BMqYybKdPMebqwZ/img/8d363b51-75d7-4474-b7df-e177a17313b1.png)\n\n## sn生成代码\n\n```js\nimport random\nimport time\nimport hashlib\nv = \"7.38.0\"\nproid = \"ifengnews\"\npublishid = \"2899\"\ndeviceid = \"v001iVTYiFTMlBjM2IWM0EGM40QYgfr3r340gf\"\nso = \"acF%#*{_b1mQt@..ifvy\"\nr = int((random.random() * 8999) + 1000)\ntimec = str(int(time.time()))\nst = f\"{timec}{r}\"\nsn_str = f'{v}{proid}{publishid}{deviceid}{st}{so}'\nsn = hashlib.md5(sn_str.encode(encoding='utf-8')).hexdigest()\nprint(st)\nprint(sn)\n```"
  },
  {
    "path": "第九章：安卓逆向案例/9.0 书外新增案例/趣头条sign.md",
    "content": "案例内容：趣头条app的sign值分析和生成。\n案例环境：趣头条（v3.10.43.000.0603.1931）、夜神模拟器（安卓5）、Frida（12.11.18）、Unidbg（0.9.5）\n\n> 声明：文章内容仅供参考学习，如有侵权请联系作者进行删除。\n\n---\n\n@[toc]\n\n---\n\n## 接口分析\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ed821555d800482bbbcc1f551410ff61.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\nurl： \"http://39.107.213.234/search/searchContentNew\"\nparams：\n```json\n{\n    \"dtu\": \"003\",\n    \"tk\": \"ACH5kAjk7kEzhC-JcKT27sgVQw5V2TuYW0Q0NzUxNDk1MDg5NTIyNQ\",\n    \"lon\": \"0.0\",\n    \"token\": \"\",\n    \"guid\": \"ee4d8ab62051306258de31e88ec1.04506739\",\n    \"uuid\": \"ba4be62de1e14e14a80f64e9e1ef42f3\",\n    \"tuid\": \"-ZAI5O5BM4QviXCk9u7IFQ\",\n    \"tabCode\": \"0\",\n    \"oaid\": \"\",\n    \"distinct_id\": \"d81d2cf27a955ec6\",\n    \"version\": \"31043000\",\n    \"keyword\": \"%E8%A2%AB%E7%8E%8B%E6%80%9D%E8%81%AA%E6%89%8B%E6%92%95%E4%BB%A5%E5%B2%AD%E8%8D%AF%E4%B8%9A%E5%86%A4%E4%B8%8D%E5%86%A4%EF%BC%9F\",\n    \"traceId\": \"94c370c5a88283dafd2f235f29a7762a\",\n    \"keywordSource\": \"hotword\",\n    \"page\": \"1\",\n    \"deviceCode\": \"863064707522829\",\n    \"limit\": \"20.0\",\n    \"sign\": \"02ebb2d129c354762e6a4083cb17b05d\",\n    \"time\": \"1649991315231\",\n    \"h5_zip_version\": \"1004\",\n    \"versionName\": \"3.10.43.000.0603.1931\",\n    \"network\": \"wifi\",\n    \"OSVersion\": \"5.1.1\",\n    \"searchSource\": \"0\",\n    \"innoseed\": \"\",\n    \"device_code\": \"863064707522829\",\n    \"lat\": \"0.0\"\n}\n```\n\n经过简单的测试，发现params中的参数都不能缺少。说明服务端对这些都进行了校验，那么直接在源码中检索这些关键词定位即可。\n\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/2c1fc09d5f724b7db49d712a82bab3da.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n经过一顿找，hook了几个位置，确定了在com.jifen.framework.http.napi.util.d中。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/40a5984294e14090a64817fee3d5db0d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\nhook看看参数和参数值\n![在这里插入图片描述](https://img-blog.csdnimg.cn/0e7aa39d9f6b497d90f4b9b6e86769bb.png)\n包名：com.jifen.qukan\n版本：8.1.0\n\n---\n\n## Frida Hook\n```python\nimport frida, sys\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_device().attach('com.jifen.qukan')\n\njs_code = \"\"\"\nJava.perform(function(){\n    console.log(\"1 start hook\");\n    var ba = Java.use('com.jifen.framework.http.napi.util.d');\n    if (ba){\n        console.log(\"2 find class\");\n        ba.c.implementation = function(a1){\n            console.log(\"3 find method\");\n            console.log(a1);\n            var res = ba.a(a1)\n            console.log(res);\n            return res;\n            }\n        }\n    })\n\"\"\"\n\nscript = session.create_script(js_code)\nscript.on('message', on_message)\nscript.load()\nsys.stdin.read()\n\n```\n\n\n打印结果：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a3da5fc6418740f6a5e832f8180eb827.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n参数是list，把params的参数转为 ｛key=value｝后添加在数组中。\n\n在函数中把list转换为了字符串，并且进行了排序。\n\n返回的结果中则生成了sign。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/e6798bedb11b4f90a86fdf00efe10854.png)\n所以最终的计算在NativeUtils.getInnoSoInfo(sb.substring(0, sb.length() - 1));\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/83339090aaba4296844f853418bf4ceb.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n可以看到最终是执行了native String innoSign(String str)  ，接下来继续HOOK  getInnoSoInfo方法。\n```python\njs_code = \"\"\"\nJava.perform(function(){\n    console.log(\"1 start hook\");\n    var ba = Java.use('com.jifen.qukan.utils.NativeUtils');\n    if (ba){\n        console.log(\"2 find class\");\n        ba.getInnoSoInfo.implementation = function(a1){\n            console.log(\"3 find method\");\n            console.log(a1);\n            var res = ba.getInnoSoInfo(a1)\n            console.log(res);\n            return res;\n            }\n        }\n    })\n\"\"\"\n```\n打印结果：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/10328aaf5be840b789ad984250d6ef1b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n计算的参数已经知晓，通过在线网站生成的md5值和返回的结果不同，说明参数在so中进行了处理。\n\n那我们去NativeExample.so中看看innoSign方法。\n\n---\n\n##  So分析\n找到NativeExample.so。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/b7a777865cec464c9d6e07dce56c4426.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n拿IDA反汇编。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/21ee9843e2984fdcb8a64d54e97b25d5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n搜索innoSign。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/e78323283da14ae3891d80a971977a02.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_11,color_FFFFFF,t_70,g_se,x_16)\n\n双击innoSign进入后F5查看伪代码。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/aebe2121dccd4f519cdb096c2901502e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_19,color_FFFFFF,t_70,g_se,x_16)\n\ninnoSign()内容如下：\n```c\nint __fastcall innoSign(const char *a1)\n{\n  const char *v1; // r6\n  char *v2; // r4\n  int v3; // r0\n  size_t v4; // r0\n  char *v5; // r5\n  size_t v6; // r0\n  size_t v7; // r0\n  char *v8; // r4\n  int result; // r0\n  int v10; // [sp+48h] [bp-78h]\n  int v11; // [sp+4Ch] [bp-74h]\n  int v12; // [sp+50h] [bp-70h]\n  int v13; // [sp+54h] [bp-6Ch]\n  int v14; // [sp+58h] [bp-68h]\n  int v15; // [sp+5Ch] [bp-64h]\n  unsigned __int8 v16; // [sp+A0h] [bp-20h]\n  unsigned __int8 v17; // [sp+A1h] [bp-1Fh]\n  unsigned __int8 v18; // [sp+A2h] [bp-1Eh]\n  unsigned __int8 v19; // [sp+A3h] [bp-1Dh]\n  unsigned __int8 v20; // [sp+A4h] [bp-1Ch]\n  unsigned __int8 v21; // [sp+A5h] [bp-1Bh]\n  unsigned __int8 v22; // [sp+A6h] [bp-1Ah]\n  unsigned __int8 v23; // [sp+A7h] [bp-19h]\n  unsigned __int8 v24; // [sp+A8h] [bp-18h]\n  unsigned __int8 v25; // [sp+A9h] [bp-17h]\n  unsigned __int8 v26; // [sp+AAh] [bp-16h]\n  unsigned __int8 v27; // [sp+ABh] [bp-15h]\n  unsigned __int8 v28; // [sp+ACh] [bp-14h]\n  unsigned __int8 v29; // [sp+ADh] [bp-13h]\n  unsigned __int8 v30; // [sp+AEh] [bp-12h]\n  unsigned __int8 v31; // [sp+AFh] [bp-11h]\n  int v32; // [sp+B0h] [bp-10h]\n\n  v1 = a1;\n  v2 = malloc(0x11u);\n  _aeabi_memclr();\n  v3 = 0;\n  do\n  {\n    v2[v3] = byte_3648[v3] ^ byte_3658[v3];\n    ++v3;\n  }\n  while ( v3 != 16 );\n  v4 = strlen(v1);\n  v5 = malloc(v4 + 512);\n  strcpy(v5, v1);\n  v6 = strlen(v5);\n  *&v5[v6] = 2036689702;\n  *&v5[v6 + 4] = 61;\n  strcat(v5, v2);\n  v10 = 0;\n  v11 = 0;\n  v12 = 1732584193;\n  v13 = -271733879;\n  v14 = -1732584194;\n  v15 = 271733878;\n  v7 = strlen(v5);\n  j_MD5Update(&v10, v5, v7);\n  j_MD5Final(&v10, &v16);\n  free(v5);\n  free(v2);\n  v8 = malloc(0x21u);\n  sprintf(\n    v8,\n    \"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\",\n    v16,\n    v17,\n    v18,\n    v19,\n    v20,\n    v21,\n    v22,\n    v23,\n    v24,\n    v25,\n    v26,\n    v27,\n    v28,\n    v29,\n    v30,\n    v31,\n    v19,\n    v18,\n    v17,\n    v16,\n    v10,\n    v11,\n    v12,\n    v13,\n    v14,\n    v15);\n  result = _stack_chk_guard - v32;\n  if ( _stack_chk_guard == v32 )\n    result = v8;\n  return result;\n}\n```\n\n简单看了一下，最后返回了result。result = _stack_chk_guard - v32;if ( _stack_chk_guard == v32 )  result = v8;\n\n_stack_chk_guard 是检查栈帧是否溢出，检查数据是否被修改。\n\n不往下追了，后面还有很多内容。接下来通过unidbg来调so的方法。\n\n---\n\n## Unidbg调用\n\n先搭个架子执行下看看是否需要补环境，路径自己改一改。\n```java\npackage com.jni;\nimport com.github.unidbg.AndroidEmulator;\nimport com.github.unidbg.Module;\nimport com.github.unidbg.linux.android.AndroidEmulatorBuilder;\nimport com.github.unidbg.linux.android.AndroidResolver;\nimport com.github.unidbg.linux.android.dvm.*;\nimport com.github.unidbg.memory.Memory;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.ObjectOutputStream;\n\npublic class qutoutiao extends AbstractJni {\n    private final AndroidEmulator emulator;\n    private final VM vm;\n    private Module module;\n    String rootPath = \"C:\\\\Users\\\\Desktop\\\\AppTest\\\\\";\n    File apkFile = new File(rootPath+\"趣头条.apk\");\n    File soFile = new File(rootPath+\"libNativeExample.so\");\n\n    // OtoB: Object to Bytes;\n    private static byte[] OtoB(Object obj){\n        try {\n            ByteArrayOutputStream ByteStream = new ByteArrayOutputStream();\n            ObjectOutputStream ObjectStream = new ObjectOutputStream(ByteStream);\n            ObjectStream.writeObject(obj);\n            ObjectStream.flush();\n            byte[] newArray = ByteStream.toByteArray();\n            ObjectStream.close();\n            ByteStream.close();\n            return newArray;\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    public qutoutiao() {\n        emulator = AndroidEmulatorBuilder.for32Bit().build();\n        final Memory memory = emulator.getMemory();\n        memory.setLibraryResolver(new AndroidResolver(23));\n        vm = emulator.createDalvikVM(apkFile);\n        vm.setVerbose(false);\n        vm.setJni(this);\n        DalvikModule dm = vm.loadLibrary(soFile, true);\n        module = dm.getModule();\n        dm.callJNI_OnLoad(emulator);\n        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    emulator.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }));\n    }\n\n    public String get_sign(){\n        DvmClass BitmapkitUtils = vm.resolveClass(\"com/jifen/qukan/utils/NativeUtils\");\n        String params = \"OSVersion=5.1.1&deviceCode=863064707522829&device_code=863064707522829&distinct_id=d81d2cf27a955ec6&dtu=003&guid=ee4d8ab62051306258de31e88ec1.04506739&h5_zip_version=1004&innoseed=&keyword=Lx&keywordSource=search&lat=35.00024265777022&limit=20.0&lon=107.56824527000379&network=wifi&oaid=&page=1&searchSource=0&tabCode=0&time=1650004096206&tk=ACH5kAjk7kEzhC-JcKT27sgVQw5V2TuYW0Q0NzUxNDk1MDg5NTIyNQ&token=&traceId=94c370c5a88283dafd2f235f29a7762a&tuid=-ZAI5O5BM4QviXCk9u7IFQ&uuid=ba4be62de1e14e14a80f64e9e1ef42f3&version=31043000&versionName=3.10.43.000.0603.1931\";\n        StringObject signs = BitmapkitUtils.callStaticJniMethodObject(emulator,\"innoSign()\",params);\n        String sign = signs.getValue();\n        return sign;\n    }\n\n    public static void main(String[] args) {\n        com.jni.qutoutiao qtt = new com.jni.qutoutiao();\n        System.out.println(qtt.get_sign());\n    }\n\n}\n```\n\n\n用frida hook的参数和Unidbg执行结果进行对比。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/d3c7590be9a945f9a3ecbf6a6eebff97.png)\n发现两者一致。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/8b479a31134c4356a03c1254a57e9eb1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n继续抓包对比下。将数据包params的sign删除后按key排序生成新字符串，放到unidbg中执行。生成的sign和返回的一致。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/f37b290ebac146b0acd51aa816c72e15.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n那么本节案例到此结束了，大家动手操作一遍！\n\n\n---\n\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/97d13bbf1690474f81f78bae168fc542.png)\n"
  },
  {
    "path": "第九章：安卓逆向案例/9.0 书外新增案例/飞瓜sign.md",
    "content": "本文案例是飞瓜APP的Sign参数分析和生成。\n\n> 声明：文章内容仅供参考学习，如有侵权请联系作者进行删除。\n\n\n\n---\n\n## 接口分析\n\n观察后发现，同一时间请求的不同接口，Sign是相同的。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/bffc2f59cfbe48df86290354ac705d64.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_15,color_FFFFFF,t_70,g_se,x_16)\nAPI：\"http://appapi.feigua.cn/api/v1/live/liveRealtimeRoomDataV3?page=1&pattern=2&pageSize=5\"\n\nheaders:\n```\n{\n\tPlatform\tAndroid\n\tImei\t161174e6-6db5-42e9-8569-63f815042db1\n\tVersion\t148-1.4.8\n\tLoginType\t\n\tLoginId\t\n\tts\t1647493831\n\tSign\t198C5C37675D494DAEDCE494389300C6\n\tHost\tappapi.feigua.cn\n\tAccept-Encoding\tgzip\n\tUser-Agent\tokhttp/3.12.0\n\tConnection\tkeep-alive\n}\n```\n\n---\n\n## 参数定位\n\n定位比较简单\n![在这里插入图片描述](https://img-blog.csdnimg.cn/6850476423314c68960f0da7390d8bd5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n点进去看看\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/26127cba5e9341e6a2033aead464d485.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\nbuilder2.addHeader(\"Sign\", HttpConstant.m22288a(hashMap, d, sb3.toString()));\n\n先看看参数\n\nsb3 =  System.currentTimeMillis() / 1000;\n\nString d = SharedPreferencesUtils.m22806b(MyApplication.m22275b()).m22809d(SessionId);\n\n再看一下 HttpConstant.m22288a\n![在这里插入图片描述](https://img-blog.csdnimg.cn/d97f51f59e614caa84975abe72006bf1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n就是把stringBuffer 各种拼接、排序处理后， md5一下。 \n![在这里插入图片描述](https://img-blog.csdnimg.cn/3674c0cf44b9473dac5356ba7c99dc36.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_18,color_FFFFFF,t_70,g_se,x_16)\n\njava代码很简单，静态分析结束，为了保险起见，hook md5看看参数吧。\n\n---\n\n## Hook调试\n![在这里插入图片描述](https://img-blog.csdnimg.cn/4b9877f7f99542cf864de903c3893058.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\nFrida代码：\n```python\n# -*- coding: utf-8 -*-\n# @Author  : lx\n# @IDE ：PyCharm\nimport frida, sys\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_device().attach('com.feigua.androiddy')\n\njs_code = '''\n    Java.perform(\n        function(){\n                console.log(\"1. start hook\");\n                var ba = Java.use(\"com.feigua.androiddy.d.i\");\n                if (ba != undefined) {\n                    console.log(\"2. find class\");\n                    ba.a.implementation = function(a1){\n                        console.log(\"3. hook method\");\n                        console.log(a1);\n                        var res = ba.a(a1);\n                        console.log(res);\n                        return res\n                        }\n                }\n        }\n    )\n'''\nscript = session.create_script(js_code)\nscript.on('message', on_message)\nscript.load()\nsys.stdin.read()\n\n\n```\n\n接着先看是不是正常的MD5，经对比一样的。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/8eaf4183380e4479a05e3886e28881db.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_17,color_FFFFFF,t_70,g_se,x_16)\n\n\n\n分析完了，拿python还原一下。\n\n---\n\n## python还原\nImei 可以不带 ，代码如下：\n\n```python\n# -*- coding: utf-8 -*-\n# @Time    : 2022/3/17 13:28\n# @Author  : lx\n# @IDE ：PyCharm\n\nimport requests\nimport time\nimport hashlib\nheaders = {\n    \"Platform\":\"Android\",\n    # \"Imei\":\"161174e6-6db5-42e9-8569-63f815042db1\",\n    \"Version\":\"148-1.4.8\",\n    \"LoginType\":\"\",\n    \"LoginId\":\"\",\n    \"Host\":\"appapi.feigua.cn\",\n    \"Accept-Encoding\":\"gzip\",\n    \"User-Agent\":\"okhttp/3.12.0\",\n    \"Connection\":\"keep-alive\",\n}\n\ndef get_md5(string):\n    m = hashlib.md5()\n    m.update(string.encode())\n    return m.hexdigest()\n\nts = str(round(time.time()))\n\n# 最好直接根据key从小到大 排序\nitem = {\n    \"page\":\"1\",\n    \"pagesize\":\"5\",\n    \"pattern\":\"2\",\n    \"platform\":\"Android\",\n    \"ts\":ts\n }\n\nparams=sorted(item.items(),key=lambda x:x[0])\nsb = \"CCd35181!!6445btrrtBBertert===\"\nfor p in params:\n    sb += \"&\"\n    sb += f'{p[0]}={p[1]}'\nprint(sb)\nsign = get_md5(sb).upper()\nprint(sign)\nheaders.update({\"ts\":ts})\nheaders.update({\"Sign\":sign})\nres = requests.get(\"http://appapi.feigua.cn/api/v1/live/liveRealtimeRoomDataV3?page=1&pattern=2&pageSize=5\",headers=headers)\nprint(res.text)\n\n```\n\n好了，到这里就结束了。\n\n"
  },
  {
    "path": "第九章：安卓逆向案例/9.1 某新闻加密参数分析和还原/frida1.py",
    "content": "import frida, sys\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_device().attach('cn.dahebao')\n\njscode_hook = \"\"\"\n    Java.perform(\n        function(){\n                console.log(\"1. start hook\");\n                var ba = Java.use(\"com.dingduan.lib_network.interceptor.CommonParamInterceptor\").$new();\n                if (ba != undefined) {\n                    console.log(\"2. find class\");\n                    ba.md5.implementation = function (a1) {\n                        console.log(\"3. find function\");\n                        console.log(a1);\n                        var res = ba.md5(a1);\n                        console.log(\"计算Sign:\" + res);\n                        return res;\n                }\n            }\n        }\n)\n\"\"\"\n\nscript = session.create_script(jscode_hook)\nscript.on('message', on_message)\nscript.load()\nsys.stdin.read()"
  },
  {
    "path": "第九章：安卓逆向案例/9.2 某瓣签名Frida还原/frida1.py",
    "content": "import frida, sys\n\ndef on_message(message, data):\n    if message['type'] == 'send':\n        print(\"[*] {0}\".format(message['payload']))\n    else:\n        print(message)\n\njscode_hook = \"\"\"\nJava.perform(\n    function(){\n            console.log(\"1. start hook\");\n            var ba = Java.use(\"com.douban.frodo.utils.crypto.HMACHash1\");\n            if (ba != undefined) {\n                console.log(\"2. find class\");\n                ba.a.overload('java.lang.String', 'java.lang.String').implementation = function (a1,a2) {\n                    console.log(\"3. find function\");\n                    console.log(a1);\n                    console.log(a2);\n                    var res = ba.a(a1,a2);\n                    console.log(\"计算result:\" + res);\n                    return res;\n                }\n            }\n    }\n)\n\"\"\"\n\nprocess = frida.get_usb_device().attach('com.douban.frodo')\nscript = process.create_script(jscode_hook)\nscript.on('message', on_message)\nprint('[*] Hook Start Running')\nscript.load()\nsys.stdin.read()"
  },
  {
    "path": "第九章：安卓逆向案例/9.2 某瓣签名Frida还原/run.py",
    "content": "import requests,time\nfrom urllib.parse import quote,urlparse\nimport hashlib,base64,hmac\n\nheaders = {\"User-Agent\": \"api-client/1 com.douban.frodo/7.18.0(230) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android  rom/miui6  network/wifi  udid/bba04d59bdf9c91ef59ff80573c4480c1a661a70  platform/mobile nd/1\"}\n\ndef bd_request():\n    url = \"\"\n    ts = str(round(time.time()))\n    params ={\n        'count':'30',\n        'tag':'追剧',\n        'os_rom':'miui6',\n        'apikey':'0dad551ec0f84ed02907ff5c42e8ec70',\n        'channel':'Baidu_Market',\n        'udid':'bba04d59bdf9c91ef59ff80573c4480c1a661a70',\n        'timezone':'Asia/Shanghai',\n        \"_sig\": get_sig(url=url, ts=ts),\n        \"_ts\": ts,\n    }\n    data = requests.get(url, params=params, headers=headers).text\n    return data\n\ndef get_sig(url,ts):\n    urlpath = urlparse(url).path\n    sign = '&'.join(['GET', quote(urlpath,safe=''), ts])\n    sig = hmac.new(\"bf7dddc7c9cfe6f7\".encode(), sign.encode(), hashlib.sha1).digest()\n    _sig = base64.b64encode(sig).decode()\n    return _sig\n\nprint(bd_request())"
  },
  {
    "path": "第九章：安卓逆向案例/9.4 某图参数Frida+Flask RPC/run.py",
    "content": "import frida\nfrom flask import Flask, jsonify, request\n\napp = Flask(__name__)\n\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\n\ndef start_hook():\n    session = frida.get_usb_device().attach('com.mt.mtxx.mtxx')\n    js_code = '''\n    rpc.exports = {\n        \"a\": function (kw) {\n            var ret = {};\n            Java.perform(function(){\n                    var SigEntity = Java.use(\"com.meitu.secret.SigEntity\");\n                    var BaseApplication = Java.use('com.meitu.library.application.BaseApplication');\n                        var str1 = \"search/feeds.json\";\n                        var str3 = \"6184556633574670337\";\n                        var content = BaseApplication.getApplication();\n                    var result = SigEntity.generatorSig(str1, kw, str3, content);\n                    ret[\"result\"]=result.sig.value;\n                    console.log(\"[*] Sig:\",result.sig.value);\n                    }\n                )\n            return ret;\n            }\n        }\n    '''\n    script = session.create_script(js_code)\n    script.on('message', on_message)\n    script.load()\n    return script\n\n\n@app.route(\"/hook\")\ndef search():\n    kw = request.args.get(\"kw\")\n# 因参数过长，此处代码中的params不完整\n    params = ['1639127762948', 'CMCC', 'GMT+8',kw, ...]\n    result = start_hook().exports.a(params)\n    return jsonify({'result':result})\n\n\nif __name__ == '__main__':\n    app.run()"
  },
  {
    "path": "第九章：安卓逆向案例/9.5 某东加密参数Unidbg生成/readme.md",
    "content": "**案例 9.3也在其中**\n\n**lxServer**: 是书中对某东APP的sign参数分析和通过Unidbg模拟调用.\n\n**unidbg-jd-sign-11**：新增的，是对11版本的调用。\n\n\n- 运行前准备好java环境以及maven\n- 按照readme中的说明修改路径和测试\n"
  },
  {
    "path": "第九章：安卓逆向案例/9.6 某资讯加固脱壳和参数分析/hook.py",
    "content": "import frida, sys\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_device().attach('com.hipu.yidian')\n\njscode_hook = \"\"\"\n    Java.perform(\n        function(){\n                console.log(\"1. start hook\");\n                var ba = Java.use(\"com.yidian.news.util.sign.SignUtil\");\n                if (ba != undefined) {\n                    console.log(\"2. find class\");\n                    ba.signInternal.implementation = function (a1,a2) {\n                        console.log(\"3. find function\");\n                        console.log(a1);\n                        console.log(a2);\n                        var res = ba.signInternal(a1,a2);\n                        console.log(\"计算Sign:\" + res);\n                        return res;\n                }\n            }\n        }\n)\n\"\"\"\n\nscript = session.create_script(jscode_hook)\nscript.on('message', on_message)\nscript.load()\nsys.stdin.read()"
  },
  {
    "path": "第九章：安卓逆向案例/9.6 某资讯加固脱壳和参数分析/rpc.py",
    "content": "import frida\n\n\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\n\ndef start_hook():\n    session = frida.get_usb_device().attach('com.hipu.yidian')\n    print(\"[*] start hook\")\n\n    js_code = '''\n    rpc.exports = {\n        \"a\": function (params) {\n                var ret = {};\n                Java.perform(function(){\n                    console.log(\"1. start hook\");\n                    var ba = Java.use(\"com.yidian.news.util.sign.SignUtil\");\n\n                    var current_application = Java.use('android.app.ActivityThread').currentApplication();\n                    var a1 = current_application.getApplicationContext();\n\n                    if (ba != undefined) {\n                        console.log(\"2. find class\");\n                        var a2 = params;\n                        var res = ba.signInternal(a1,a2);\n                        console.log(\"计算Sign:\" + res);\n                        console.log(res)\n                        ret[\"result\"]=res;\n                        console.log(ret)\n                        }\n                    }\n               )\n            return ret;\n            }\n        }\n    '''\n    script = session.create_script(js_code)\n    script.on('message', on_message)\n    script.load()\n    return script\n\n\nimport time\n\nstimec = str(int(time.time() * 1000))\nparams = f'yidian6.0.4.41kbylz0sj_{stimec}_207030300'\nresult = start_hook().exports.a(params)\nprint(result)"
  },
  {
    "path": "第八章：抓包技巧汇总/heytap软件商店抓包.md",
    "content": "本文内容是 heytap软件商店抓包案例。\n\n---\n\n用常规的http/https工具，比如charles、fiddler去抓包时，无法正常对heytapmobi进行抓包。\n\n会提示客户端SSL握手失败，Received fatal alert: certificate_unknown\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/5f2fa7e1e3104de5b9d5e88adfa9e107.png)\n\n\n本以为是双向认证的原因，但是并没找到有效的客户端证书，所以开始通过其他工具进行抓包。\n\n拿httpCanary试过，并没有拦截到。\n\n经过一番测试发现使用NetKeeper可解决问题。\n\n---\n\n**NetKeeper抓包精灵** 不需要ROOT，通过抓包的结果还能抓取音频以及视频。\n\n\n设置一下过滤条件，方便查看数据包。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/4c6080a4ddc3429b9010ac78b0a3006d.png?)\n\n触发评论请求后，成功看到数据包。\n\nhttps://api-cn.store.heytapmobi.com:443/common/v1/comment/list?appId=3700438&size=10&start=40&token=-1&type=bad\n\n**Type类型：** hot、good、middle、bad\n![在这里插入图片描述](https://img-blog.csdnimg.cn/3ea8c6729c874963aa36a60b8f171744.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n可以发现有加密参数sign。\n\n抓到包后，后面的操作就不再多说了，大家自行研究。\n\n---\n\n\n我在源码中也直接搜索过comment相关api，通过hook一些类也能拿到数据接口。\n\n\n"
  },
  {
    "path": "第八章：抓包技巧汇总/readme.md",
    "content": "对应第八章《八：抓包技巧汇总》\n\n大家先把书中概念性的东西了解一下\n\n书中出现的内容就不重复贴了，这里加一些案例和知识点，持续更新\n"
  },
  {
    "path": "第八章：抓包技巧汇总/夜神安卓7导入charles证书.md",
    "content": "夜神安卓7系统的charles证书导入。由于用户安装的外部证书不被信任，所以需要把SSL证书安装到安卓系统证书目录里。\n\n---\n\n## 一：下载证书\n开启本地代理，在浏览器输入 chls.pro/ssl 下载证书到本地。\n\n把证书原名charles-proxy-ssl-proxying-certificate.pem 先修改为 charles.pem\n\n---\n\n## 二：打印证书\n\n通过openssl输出证书内容，自行安装openssl\n\n下载地址：[https://slproweb.com/products/Win32OpenSSL.html](https://slproweb.com/products/Win32OpenSSL.html)\n\n安装后通过 openssl command 打开command。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/d4abf24ca70044fb9e277ae9da79b83b.png)\n\n输入 `openssl x509 -inform PEM -subject_hash_old -in charles.pem`\n\n执行后打印的结果中，第一行的90e59ded复制一下。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/f5f9c2e095fc49519ded35f9e4201ffd.png)\n\n此处把证书名修改为 90e59ded.0   。 注意格式，你修改为 xxx.0\n\n\n---\n\n## 三：导入设备\n\n不管啥方法，把证书传进设备的 /sdcard/ 文件下。\n\n可以通过adb push，命令： `adb push xxx.0 /sdcard/`\n\n然后进入adb shell中，adb shell 连接手机，不是root的通过命令 su 切换下，然后cd到 /sdcard/中。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/c3163457f4904b40a1c7e68bc62f6a0f.png)\n\n没问题的话将证书移动到 /system/etc/security/cacerts/ 路径下。\n命令： `mv xxx.0 /system/etc/security/cacerts/`\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/9e127a9157be41ae861fad05223fd2c7.png)\n\n有可能会执行失败，说只读之类的Read-only file system \n可以先执行命令：`mount -o rw,remount /system`\n或者执行命令：`mount -o rw,remount /`\n然后再mv移动。\n\n\n---\n\n\n## 四：证书授权\n\n给证书权限的执行命令：`chmod 777 /system/etc/security/cacerts/xxx.0`\n\n重启手机：`reboot`\n\n证书导入完成，配置下wifi代理就可以正常抓包了。\n\n"
  },
  {
    "path": "第八章：抓包技巧汇总/快手app抓包.md",
    "content": "# 快手app抓包\n\n快手app版本8+往后使用的quic协议。QUIC 基于 UDP 传输、多数代理工具不支持，且快手用 Aegon 库强制 QUIC、同时叠加证书校验与代理绕过机制，导致常规代理抓包失效。\n\n最常用的解决方法是将app的quic协议降级成http/https协议。\n\n## 背景\n\n快手的 QUIC 逻辑全部封装在自研的 `Aegon` 网络库中。\n\n1.  把快手 APK 拖入 Jadx-Gui，等待反编译完成；\n    \n2.  在 Jadx 的搜索框（快捷键 Ctrl+Shift+F）输入关键词 `Aegon`，会看到大量以 `com.kuaishou.aegon` 为包名的类；\n    \n3.  优先查看 `Aegon` 主类（即 `com.kuaishou.aegon.Aegon`），这是网络库的入口类。\n    \n4.  在 Aegon 类中找 QUIC 相关方法。打开 包含 `quic` 关键词的方法 / 字段；，包含 `config`（配置）、`update`（更新）的方法（因为 QUIC 的开启 / 关闭是通过配置更新实现的）。\n    \n\n很快能看到 `nativeUpdateConfig` 这个方法 —— 名字里的 `native` 说明是 Native 层方法，`UpdateConfig` 说明是更新网络配置，这正是修改 QUIC 开关的核心入口；\n\n查看该方法的参数：通常是一个 String 类型的 JSON 字符串，点进方法引用（右键→Find Usages），能看到调用处传入的 JSON 里包含 `enable_quic` 字段（值为 true/false），坐实这是控制 QUIC 的关键方法。\n\n用 Frida Hook 该方法，然后结合Postern抓包。\n\nHook 禁用 QUIC 后，为什么还需要结合 Postern 抓包？\n\n核心原因是：Hook 只解决了 QUIC 协议降级的问题，但手机 App 的流量默认不会主动转发到电脑的抓包工具（如 Charles/mitmproxy），Postern 的核心作用是做「系统级流量转发」，让降级后的 HTTP/HTTPS 流量能被抓包工具捕获。\n\n## hook代码\n\nfrida 16.0.19  \nfrida-tools 12.1.2  \n夜神 安卓7(32位)  \n快手APP 9.2  \nPostern 3.1.2\n\n```javascript\nimport frida, sys\njscode = \"\"\"\nJava.perform(\n    function () {\n        var Aegon = Java.use('com.kuaishou.aegon.Aegon');\n        Aegon.nativeUpdateConfig.implementation = function (a,b) {\n                    a = '{\"enable_quic\":false,\"preconnect_num_streams\":2,\"quic_idle_timeout_sec\":180,\"quic_use_bbr\":true,\"altsvc_broken_time_max\":600,\"altsvc_broken_time_base\":60,\"proxy_host_blacklist\":[]}';\n                    return this.nativeUpdateConfig(a,b);\n        }\n    }\n);\n\"\"\"\ndef on_message(message, data):\n    if message['type'] == 'send':\n        print(\"[*] {0}\".format(message['payload']))\n    else:\n        print(message)\nprocess = frida.get_remote_device()\n\n#pid = process.spawn(['com.kuaishou.nebula']) #  极速\npid = process.spawn(['com.smile.gifmaker']) #   app\nsession = process.attach(pid)\nscript = session.create_script(jscode) \nscript.on('message',on_message) \nscript.load()\nprocess.resume(pid)\n\n```\n\n## Postern\n\n配置代理，代理类型用**socks**  \n![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/QvjnA3jV9K6EyOXo/img/ae73d0a7-75b5-4402-961c-a58e1a30e363.png)\n\n配置规则  \n![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/QvjnA3jV9K6EyOXo/img/5b136a98-b884-49cb-a19b-0de5bee431ea.png)\n\n---\n\n## 示例\n\n![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/QvjnA3jV9K6EyOXo/img/4094fc45-2d9d-4bc5-ad54-da3419d253ac.png)"
  },
  {
    "path": "第八章：抓包技巧汇总/抖音app抓包.md",
    "content": "# 抖音app抓包\n\n核心逻辑：Hook 抖音网络库 libsscronet.so，修改 QUIC 配置使其降级为 HTTPS。\n\n```javascript\nJava.perform(function() {\n    const CronetEngine = Java.use(\"org.chromium.net.CronetEngine\");\n    // Hook配置构建器，禁用QUIC\n    CronetEngine.Builder.prototype.enableQuic.implementation = function(enable) {\n        console.log(\"禁用QUIC: enableQuic(false)\");\n        return this.enableQuic(false);\n    };\n    // 备选：Hook native层更新配置\n    const Aegon = Java.use(\"com.bytedance.aegon.Aegon\");\n    if (Aegon) {\n        Aegon.nativeUpdateConfig.implementation = function(configStr) {\n            const newConfig = configStr.replace(/\"enable_quic\":true/, '\"enable_quic\":false');\n            console.log(\"修改QUIC配置:\", newConfig);\n            return this.nativeUpdateConfig(newConfig);\n        };\n    }\n});\n```"
  },
  {
    "path": "第八章：抓包技巧汇总/某物app抓包.md",
    "content": "\n## 环境准备\n模拟器夜神安卓7版本。配合charles的抓包步骤：[http://t.csdn.cn/lpNaV](http://t.csdn.cn/lpNaV)\n\n模拟器需要是64位的，在商店下载推荐版本时会提示更新。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/3339e3d37e9147399616e08c19e3d8fe.png)\n\n安装后，创建64位的模拟器，从商店下载app\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/30fbb6bb2dfd474b9661eb8e7fcf0d0f.png)\n\n打开后再按要求更新一下，即可成功进入APP。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/29547b9260d646e6880c39b2740712a1.png)\n更新后的版本：4.95.1.10\n\n\n---\n\n\n## No_PROXY抓包\n\n发现搜索后没抓到有用的数据包，但是有其他包，可能这个APP采用了 NO_PROXY 的方式拒绝代理。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/bb59ee050f02483f94d3e16c185a14ef.png)\n\n那我们可以采用VPN转发的方式进行测试，如果还不行就需要分析源码进行Hook 或者更换其他类型的抓包工具。\n\n我用 drony 转发并没有成功，所以来分析源码。\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/6e772c61b28545258f11f51649c2f734.png)\ncom.shizhuang.duapp.common.net.DuHttpConfig.a\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/603a420ca40743efaf13674237315a99.png)\n\n在本地进行hook：\n```python\nimport frida, sys\n\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\n# dewu  4.95.1.10\nsession = frida.get_remote_device().attach('com.shizhuang.duapp')\n\n# okhttp3拦截器\njs_code2 = \"\"\"\nJava.perform(function(){\n    console.log(\"1 start hook\");\n    var ba = Java.use('okhttp3.internal.http.RealInterceptorChain');\n    if (ba){\n        console.log(\"2 find class\");\n        ba.proceed.overload('okhttp3.Request').implementation = function(a1){\n            console.log(\"3 find method\");\n            console.log(a1);\n            return ba.proceed(a1)\n        }\n    }\n})\n\"\"\"\n\njs_code1 = \"\"\"\nJava.perform(function(){\n    console.log(\"1 start hook\");\n    var ba = Java.use('com.shizhuang.duapp.common.helper.net.interceptor.HttpRequestInterceptor').$new();\n    if (ba){\n        console.log(\"2 find class\");\n        ba.intercept.implementation = function(a1){\n            console.log(\"3 find method\");\n            console.log(a1);\n            return ba.intercept(a1)\n        }\n    }\n})\n\"\"\"\n\n\n\nscript = session.create_script(js_code1)\nscript.on('message', on_message)\nscript.load()\nsys.stdin.read()\n```\n\n找到 com.shizhuang.duapp.modules.mall_search.api.ProductService.searchProductNew()\n![在这里插入图片描述](https://img-blog.csdnimg.cn/106d31369bae4d949e23e3adb85cc39b.png)\n\n"
  },
  {
    "path": "第八章：抓包技巧汇总/点评app抓包案例.md",
    "content": "本文是大众点评APP的分析记录。\n\n> 声明：文章内容仅供参考学习，如有侵权请联系作者进行删除。\n\n案例环境：夜神安卓5，APP版本10.45.7。 \n工具：Frida、Charles。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/bbb2c875aef54cf1b5bee513e1b03b14.png)\n\n点评看不到http/https数据包，它走了自己的CIP协议，网上的抓包方案有降级或者VPN转发。 \n\n本文通过hook的方式来抓http/https数据包。\n\n\n用super-Jadx时内存溢出，我删除了一些无用文件，将dex分批反编译，这块就不再说了。\n\n---\n\n\n@[toc]\n\n---\n\n##  Hook 抓包\nHook代码：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/4540d1a4f36144f99ded43b373154a3b.png)\n执行hook脚本后，成功抓到包。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/c673c61550f247678b231ea64e569af7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n---\n\n## Hook http/https请求信息\nHook代码：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/941b3e9fdc4a4706aab31cea068679a4.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n查看执行结果：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/042226b04d8d4e799893a19354f181c8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n\n\n---\n\n## Hook 明文响应内容\nHook代码：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/f2058ba38d7e4f49a403a84c500fb5e1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n查看执行结果：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/89e0486d8b704a10a7d10a9887af5d4f.png)\n格式化后和设备页面信息对比，发现内容一致。\n![在这里插入图片描述](https://img-blog.csdnimg.cn/caa6bc5bd73241c1b6114ab3032576e3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ICD5Y-k5a2m5a62bHg=,size_20,color_FFFFFF,t_70,g_se,x_16)\n\n---\n\n## Hook 代码整理\n```python\nimport frida, sys\ndef on_message(message, data):\n    print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_device().attach('com.dianping.v1')\n\njs_code = \"\"\"\nJava.perform(function(){\n    \n    Java.openClassFile(\"/data/local/tmp/r0gson.dex\").load();\n    const gson = Java.use('com.r0ysue.gson.Gson');\n    \n    var c1 = Java.use(\"com.dianping.nvnetwork.tunnel2.a\");\n        c1.isSocketConnected.implementation = function () {\n        return false;\n    }\n    \n    \n    var bb = Java.use(\"com.dianping.dataservice.mapi.b\");\n    bb.b.overload('java.lang.String', 'com.dianping.dataservice.mapi.c').implementation = function(a1, a2){\n        //console.log(\"**************************** http start\");\n        console.log(a1);\n        // console.log('a2:', a2);\n        var res = this.b(a1, a2);\n        // console.log(res);\n        //console.log(\"**************************** http end\");\n        return res;\n    }\n    \n    var d = Java.use(\"com.dianping.dataservice.mapi.impl.d\")\n    d.a.overload('java.lang.String', 'java.lang.String').implementation = function(a1, a2){\n        //console.log(\"**************************** https start\");\n        var res = this.a(a1, a2);\n        console.log(res);\n        //console.log(\"**************************** https end\");\n        return res;\n    };\n    \n    \n    var c3 = Java.use(\"com.dianping.picassocontroller.jse.c\");\n\tc3.a.overload('com.dianping.picassocontroller.vc.e', 'java.lang.String', '[Ljava.lang.Object;').implementation = function (a,b,c) {\n\t\tconsole.log('a: ', a);\n\t\tconsole.log('b: ', b);\n\t\tconsole.log('c: ', c);\n\t\tvar v = this.a(a,b,c)\n\t\tconsole.log(v.string())\n\t    return v;\n\t}\n\t\n    //// hook decryptData\n    var ByteString = Java.use(\"com.android.okhttp.okio.ByteString\");\n    var SocketSecureManager = Java.use(\"com.dianping.nvnetwork.tunnel.Encrypt.SocketSecureManager\");\n    SocketSecureManager.decryptData.implementation = function(bstr, str){\n       console.log('bstr: ', bstr);\n       console.log('bstr-tojson:',gson.$new().toJson(bstr));\n       console.log('bstr-hex: ', ByteString.of(bstr).hex());\n       console.log('str: ', str);\n       var ret = this.decryptData(bstr, str);\n       // console.log(Java.use(\"android.util.Log\").getStackTraceString(Java.use(\"java.lang.Throwable\").$new()));\n       console.log('decryptData Results: ', ByteString.of(ret).hex());\n       return ret;\n    }\n    \n    \n    // var AESUtils = Java.use(\"com.meituan.android.common.unionid.oneid.util.AESUtils\");\n    // AESUtils.decrypt.implementation = function(str){\n    //     console.log('decrypt is called');\n    //     str = \"RNtYlL8BsMe4EOqz-X0a1WAw3FwHsr1fdXSOBRnPEF_MiYYvJ1GSqvIIA1NwwTUxuoNWGGueSBRl50pmkidrgdQmVUUScNhW4FpBl1ZFPSyJAz4Zo0PpDNStJnb5JCf8fEe8oDXOCAsptjpuGpRJGClsKeIqe9ph6gAyvYfOk2XafwXbHf4VlsjATDVI7r4f-2s6QQ5Mfc6jvRMyqNdLJNtLwg5XDEmL4Leu7fCnHJbJ46O8hy8MFuN38avBqh6N-2s6QQ5Mfc6jvRMyqNdLJLVj6r8HF-qtkeIznxOc2qXKVyQ4dzMLEBQjCADd9vGF\"\n    //     var ret = this.decrypt(str);\n    //     console.log('decrypt ret value is ' + ret);\n    //     return ret;\n    // };\n  \n})\n\"\"\"\n\nscript = session.create_script(js_code)\nscript.on('message', on_message)\nscript.load()\nsys.stdin.read()\n\n```\n\n\n\n\n"
  },
  {
    "path": "第六章：安卓逆向/Frida/Frida基本方法.md",
    "content": "\n\n\n\n## 基本命令\n|命令  | 简介 |\n|--|--|\n|adb devices  |列出设备  |\n|adb connect 127.0.0.1:62001\t|连接设备(注意端口)|\n|adb shell\t|进入shell|\n|adb kill-server\t|关闭服务|\n|adb start-server\t|启动服务|\n|adb reboot\t|重启设备|\n|adb forward tcp:27042 tcp:27042\t|端口转发|\n|adb shell dumpsys activity top\t|查看apk包名|\n|frida-ls-devices\t|列出所有连接到电脑上的设备|\n|frida-ps -U\t|列出正在运行的进程|\n|frida-ps -Uai\t|列出安装的程序|\n|frida-ps -Ua\t|列出运行中的程序|\n|frida-ps -D \"设备id\"\t|连接frida到个指定的设备|\n|frida-trace -U -f Name -i \"函数名\"|\t跟踪某个函数|\n|frida-trace -U -f Name -m \"方法名\"\t|跟踪某个方法|\n|frida -U -l *.js \"进程ID\"\t|加载Js脚本|\n|frida-discover -n Name\t|发现程序内部函数|\n|frida-discover -p pid\t|发现程序内部函数|\n|frida-kill -U | \"进程ID\"\t|结束进程|\n\n\n## Hook 一般函数\n\n```javascript\nvar MyClass = Java.use('xx.xx.MainActivity');\nMyClass.myMethod.implementation = function (arg) {\n    var ret = this.myMethod(arg);\n    console.log('Done:' + arg);\n    return ret;\n}\n```\n\n\n## Hook 重载函数\n```javascript\nmyClass.myMethod.overload(\"java.lang.String\").implementation = function(param1){\nconsole.log(param1);\n}\n\nmyClass.myMethod.overload(\"[B\",\"[B\").implementation = function(param1,param2) {\nconst p1 = Java.use(\"java.lang.String\").$new(param1);\nconst p2 = Java.use(\"java.lang.String\").$new(param2);\n}\n\nmyClass.myMethod.overload(\"android.context.Context\", \"boolean\").implementation = function(param1, param2){\n   //do something \n}\n```\n\n\n## Hook 构造函数\n\n```javascript\nconst StringBuilder = Java.use('java.lang.StringBuilder');\nStringBuilder.$init.overload('java.lang.String').implementation = function (arg) {\n    var partial = \"\";\n    var result = this.$init(arg);\n    if (arg !== null) {\n         partial = arg.toString().slice(0,10);\n    }\n    console.log('new StringBuilder(\"' + partial + '\");');\n    return result;\n};\n\n\nStringBuilder.$init.overload('[B', 'int').implementation = function (arg1,arg2,) {\n  //do something \n}\n```\n\n\n## Hook 成员方法\n```javascript\nJava.perform(\n    function(){\n            var ba = Java.use(\"com.xx.xx.xx\").$new();\n            if (ba != undefined) {\n                ba.mdthod.implementation = function (a1) {\n                //do something \n            }\n        }\n    }\n)\n```\n\n## Hook 内部类\n\n```javascript\nvar inInnerClass = Java.use('ese.xposedtest.MainActivity$inInnerClass');\n// 类路径$内部类名\ninInnerClass.methodInclass.implementation = function(arguments){\n    var arg0 = arguments[0];\n    var arg1 = arguments[1];\n    send(\"params1: \"+ arg0 +\" params2: \" + arg1);\n    return this.formInclass(1,\"Frida\");\n}\n```\n\n\n## Hook native函数\n```javascript\nfunction hookNativeFun(callback, funName, moduleName) {\n    var time = 1000;\n    var address = Module.findExportByName(moduleName, funName);\n    if (address == null) {\n        setTimeout(hookNativeFun, time, callback, funName, moduleName);\n} \nelse {\n        console.log(funName + \"hook result\")\n        var nativePointer = new NativePointer(address);\n        Interceptor.attach(nativePointer, callback);\n    }\n}\n```\n\n\n## 从内存中主动调用Java方法\n```javascript\nJava.perform(\n    function(){\n        Java.choose(\"com.xx.xx.xx\", {\n        onMatch: function (x) {\n            ba.signInternal.implementation = function(a1,a2) {\n            result= x.method(a1,a2);\n            },\n        onComplete: function () {\n            }\n        })\n    }\n)\n```\n\n\n## 获取所有已加载的类名\n\n```javascript\nJava.perform(function(){\n    Java.enumerateLoadedClasses({\n        onMatch: function(className) {\n            send(className);},\n        onComplete:function(){\n            send(\"done\");\n        }\n    });\n});\n```\n\n\n## 获取方法名\n\n```javascript\nfunction getMethodName() {\n    var ret;\n    Java.perform(function() {\n        var Thread = Java.use(\"java.lang.Thread\")\n        ret = Thread.currentThread().getStackTrace()[2].getMethodName();\n    });\n    return ret;\n}\n```\n\n\n## 打印堆栈信息\n\n```javascript\nfunction showStacks() {\n    Java.perform(function() {\n        console.log(Java.use(\"android.util.Log\").getStackTraceString(Java.use(\"java.lang.Exception\").$new()));\n    });\n}\n```\n\n## 打印类所有方法名\n\n```javascript\nfunction enumMethods(targetClass) {\n    var ret;\n    Java.perform(function() {\n            var hook = Java.use(targetClass);\n            var ret = hook.class.getDeclaredMethods();\n            ret.forEach(function(s) {\n                console.log(s);\n            })\n    })\n    return ret;\n}\n```\n\n\n## 构造 context\n\n```js\nvar current_application = Java.use('android.app.ActivityThread').currentApplication();\nvar context = current_application.getApplicationContext();\n\n```\n\n\n## Hook NO_Proxy\n```js\nJava.perform(function(){\n    console.log(\"1 start hook\");\n    try {\n        var URL = Java.use('java.net.URL')\n        URL.openConnection.overload('java.net.Proxy').implementation = function (arg1){\n            return this.openConnection()\n        }\n    } catch (e) {\n        console.log('' + e)\n    }\n    try {\n        var Builder = Java.use('okhttp3.OkHttpClient$Builder')\n        var mybuilder = Builder.$new()\n        Builder.proxy.overload('java.net.Proxy').implementation = function (arg1) {\n            return mybuilder\n        }\n    }   catch (e) {\n        console.log('' + e)\n    }\n```\n\n\n\n\n## Hook HashMap-put\n\n```javascript\nvar hashMap = Java.use(\"java.util.HashMap\");\nhashMap.put.implementation = function (a, b) {\n    // 不行可换 a.equals(\"username\")\n    if (a==\"username\") {\n     console.log(\"hashMap.put: \", a, b);\n        printStacks();\n }\n return this.put(a, b);\n}\n```\n\n## Hook ArrayList-add\n\n```javascript\nvar arrayList = Java.use(\"java.util.ArrayList\");\narrayList.add.overload('java.lang.Object').implementation = function (a) {\n    if (a == \"username\") {\n        console.log(\"arrayList.add: \", a);\n        showStacks();  // 打印堆栈信息\n    }\n    //console.log(\"arrayList.add: \", a);\n    return this.add(a);\n}\narrayList.add.overload('int', 'java.lang.Object').implementation = function (a, b) {\n    console.log(\"arrayList.add: \", a, b);\n    return this.add(a, b);\n}\n```\n\n## Hook TextUtils-isEmpty\n\n```javascript\n// 判断输入框是否为空\nvar textUtils = Java.use(\"android.text.TextUtils\");\ntextUtils.isEmpty.implementation = function (a) {\n    if (a == \"TURJNk1EQTZNREE2TURBNk1EQTZNREE9\") {\n        console.log(\"textUtils.isEmpty: \", a);\n        printStacks();\n\n    }\n    //console.log(\"textUtils.isEmpty: \", a);\n    return this.isEmpty(a);\n}\n```\n\n## hook Base64-encodeToString\n\n```javascript\nvar base64 = Java.use(\"android.util.Base64\");\nbase64.encodeToString.overload('[B', 'int').implementation = function (a, b) {\n    console.log(\"base64.encodeToString: \", JSON.stringify(a));\n    var result = this.encodeToString(a, b);\n    console.log(\"base64.encodeToString result: \", result)\n    printStacks();\n    return result;\n}\n```\n\n\n\n## okhttp3 rpc\n```javascript\nrpc.exports = {\n    request_url: function (url) {\n        return new Promise(function(resolve, reject) {\n            Java.perform(function () {\n                var OkHttpClient=Java.use(\"okhttp3.OkHttpClient\");\n                var Builder=Java.use(\"okhttp3.Request$Builder\");\n                var client = OkHttpClient.$new()\n                var request = Builder.$new().get().url(url).build()\n                var response = client.newCall(request).execute()\n                resolve(response.body().string())\n            });\n        });\n    }\n};\n\n\n```\n\n## okhttp3 GET\n```javascript\nfunction okhttp3_get(url, headers_str){\n    let body = null;\n    Java.perform(() => {\n        const BuilderClazz = Java.use('okhttp3.Request$Builder');\n        const OkHttpClientClazz = Java.use('okhttp3.OkHttpClient');\n        try{\n            let builder = BuilderClazz.$new();\n            builder = builder.url(url);\n            if(headers_str != null && headers_str != ''){\n                let headers = JSON.parse(headers_str);\n                for(let key in headers){\n                    builder = builder.addHeader(key, headers[key]);\n                }\n            }\n            let request = builder.build();\n            if(!okhttp3_client){\n                okhttp3_client = OkHttpClientClazz.$new();\n            }\n            let call = okhttp3_client.newCall(request);\n            let response = call.execute();\n            body = response.body().string();\n        }catch(e){\n            console.error(e);\n        }\n    });\n    return body;\n}\n\n```\n\n## okhttp3 POST\n\n```javascript\nfunction okhttp3_post(url, headers_str, media_type, body){\n    let ret = null;\n    Java.perform(() => {\n        const BuilderClazz = Java.use('okhttp3.Request$Builder');\n        const OkHttpClientClazz = Java.use('okhttp3.OkHttpClient');\n        const MediaTypeClazz = Java.use('okhttp3.MediaType');\n        const RequestBodyClazz = Java.use('okhttp3.RequestBody');\n        try{\n            let builder = BuilderClazz.$new();\n            builder = builder.url(url);\n            if(headers_str != null && headers_str != ''){\n                let headers = JSON.parse(headers_str);\n                for(let key in headers){\n                    builder = builder.addHeader(key, headers[key]);\n                }\n            }\n            let m_type = MediaTypeClazz.parse(media_type);\n            let request_body = RequestBodyClazz.create(m_type, body);\n            builder = builder.post(request_body);\n            let request = builder.build();\n            if(!okhttp3_client){\n                okhttp3_client = OkHttpClientClazz.$new();\n            }\n            let call = okhttp3_client.newCall(request);\n            let response = call.execute();\n            ret = response.body().string();\n        }catch(e){\n            console.error(e);\n        }\n    });\n    return ret;\n}\n\n```\n\n"
  },
  {
    "path": "第六章：安卓逆向/Frida/Frida自吐算法.js",
    "content": "\n// 代码引用自 Mobile security 王铁头\n\nvar N_ENCRYPT_MODE = 1\nvar N_DECRYPT_MODE = 2\n\nfunction showStacks() {\n    var Exception = Java.use(\"java.lang.Exception\");\n    var ins = Exception.$new(\"Exception\");\n    var straces = ins.getStackTrace();\n\n    if (undefined == straces || null == straces) {\n        return;\n    }\n\n    console.log(\"============================= Stack strat=======================\");\n    console.log(\"\");\n\n    for (var i = 0; i < straces.length; i++) {\n        var str = \"   \" + straces[i].toString();\n        console.log(str);\n    }\n\n    console.log(\"\");\n    console.log(\"============================= Stack end=======================\\r\\n\");\n    Exception.$dispose();\n}\n\n//工具相关函数 \nvar base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',\n    base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, (-1), (-1), (-1), (-1), (-1), (-1), 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, (-1), (-1), (-1), (-1), (-1));\n\nfunction stringToBase64(e) {\n    var r, a, c, h, o, t;\n    for (c = e.length, a = 0, r = ''; a < c;) {\n        if (h = 255 & e.charCodeAt(a++), a == c) {\n            r += base64EncodeChars.charAt(h >> 2),\n                r += base64EncodeChars.charAt((3 & h) << 4),\n                r += '==';\n            break\n        }\n        if (o = e.charCodeAt(a++), a == c) {\n            r += base64EncodeChars.charAt(h >> 2),\n                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),\n                r += base64EncodeChars.charAt((15 & o) << 2),\n                r += '=';\n            break\n        }\n        t = e.charCodeAt(a++),\n            r += base64EncodeChars.charAt(h >> 2),\n            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),\n            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),\n            r += base64EncodeChars.charAt(63 & t)\n    }\n    return r\n}\nfunction base64ToString(e) {\n    var r, a, c, h, o, t, d;\n    for (t = e.length, o = 0, d = ''; o < t;) {\n        do\n            r = base64DecodeChars[255 & e.charCodeAt(o++)];\n        while (o < t && r == -1);\n        if (r == -1)\n            break;\n        do\n            a = base64DecodeChars[255 & e.charCodeAt(o++)];\n        while (o < t && a == -1);\n        if (a == -1)\n            break;\n        d += String.fromCharCode(r << 2 | (48 & a) >> 4);\n        do {\n            if (c = 255 & e.charCodeAt(o++), 61 == c)\n                return d;\n            c = base64DecodeChars[c]\n        } while (o < t && c == -1);\n        if (c == -1)\n            break;\n        d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2);\n        do {\n            if (h = 255 & e.charCodeAt(o++), 61 == h)\n                return d;\n            h = base64DecodeChars[h]\n        } while (o < t && h == -1);\n        if (h == -1)\n            break;\n        d += String.fromCharCode((3 & c) << 6 | h)\n    }\n    return d\n}\nfunction hexToBase64(str) {\n    return base64Encode(String.fromCharCode.apply(null, str.replace(/\\r|\\n/g, \"\").replace(/([\\da-fA-F]{2}) ?/g, \"0x$1 \").replace(/ +$/, \"\").split(\" \")));\n}\nfunction base64ToHex(str) {\n    for (var i = 0, bin = base64Decode(str.replace(/[ \\r\\n]+$/, \"\")), hex = []; i < bin.length; ++i) {\n        var tmp = bin.charCodeAt(i).toString(16);\n        if (tmp.length === 1)\n            tmp = \"0\" + tmp;\n        hex[hex.length] = tmp;\n    }\n    return hex.join(\"\");\n}\nfunction hexToBytes(str) {\n    var pos = 0;\n    var len = str.length;\n    if (len % 2 != 0) {\n        return null;\n    }\n    len /= 2;\n    var hexA = new Array();\n    for (var i = 0; i < len; i++) {\n        var s = str.substr(pos, 2);\n        var v = parseInt(s, 16);\n        hexA.push(v);\n        pos += 2;\n    }\n    return hexA;\n}\nfunction bytesToHex(arr) {\n    var str = '';\n    var k, j;\n    for (var i = 0; i < arr.length; i++) {\n        k = arr[i];\n        j = k;\n        if (k < 0) {\n            j = k + 256;\n        }\n        if (j < 16) {\n            str += \"0\";\n        }\n        str += j.toString(16);\n    }\n    return str;\n}\nfunction stringToHex(str) {\n    var val = \"\";\n    for (var i = 0; i < str.length; i++) {\n        if (val == \"\")\n            val = str.charCodeAt(i).toString(16);\n        else\n            val += str.charCodeAt(i).toString(16);\n    }\n    return val\n}\nfunction stringToBytes(str) {\n    var ch, st, re = [];\n    for (var i = 0; i < str.length; i++) {\n        ch = str.charCodeAt(i);\n        st = [];\n        do {\n            st.push(ch & 0xFF);\n            ch = ch >> 8;\n        }\n        while (ch);\n        re = re.concat(st.reverse());\n    }\n    return re;\n}\n//将byte[]转成String的方法\nfunction bytesToString(arr) {\n    var str = '';\n    arr = new Uint8Array(arr);\n    for (var i in arr) {\n        str += String.fromCharCode(arr[i]);\n    }\n    return str;\n}\nfunction bytesToBase64(e) {\n    var r, a, c, h, o, t;\n    for (c = e.length, a = 0, r = ''; a < c;) {\n        if (h = 255 & e[a++], a == c) {\n            r += base64EncodeChars.charAt(h >> 2),\n                r += base64EncodeChars.charAt((3 & h) << 4),\n                r += '==';\n            break\n        }\n        if (o = e[a++], a == c) {\n            r += base64EncodeChars.charAt(h >> 2),\n                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),\n                r += base64EncodeChars.charAt((15 & o) << 2),\n                r += '=';\n            break\n        }\n        t = e[a++],\n            r += base64EncodeChars.charAt(h >> 2),\n            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),\n            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),\n            r += base64EncodeChars.charAt(63 & t)\n    }\n    return r\n}\nfunction base64ToBytes(e) {\n    var r, a, c, h, o, t, d;\n    for (t = e.length, o = 0, d = []; o < t;) {\n        do\n            r = base64DecodeChars[255 & e.charCodeAt(o++)];\n        while (o < t && r == -1);\n        if (r == -1)\n            break;\n        do\n            a = base64DecodeChars[255 & e.charCodeAt(o++)];\n        while (o < t && a == -1);\n        if (a == -1)\n            break;\n        d.push(r << 2 | (48 & a) >> 4);\n        do {\n            if (c = 255 & e.charCodeAt(o++), 61 == c)\n                return d;\n            c = base64DecodeChars[c]\n        } while (o < t && c == -1);\n        if (c == -1)\n            break;\n        d.push((15 & a) << 4 | (60 & c) >> 2);\n        do {\n            if (h = 255 & e.charCodeAt(o++), 61 == h)\n                return d;\n            h = base64DecodeChars[h]\n        } while (o < t && h == -1);\n        if (h == -1)\n            break;\n        d.push((3 & c) << 6 | h)\n    }\n    return d\n}\n//stringToBase64 stringToHex stringToBytes\n//base64ToString base64ToHex base64ToBytes\n//               hexToBase64  hexToBytes    \n// bytesToBase64 bytesToHex bytesToString\n\n\nJava.perform(function () {\n    var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');\n    secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {\n        showStacks();\n        var result = this.$init(a, b);\n        console.log(\"======================================\");\n        console.log(\"算法名：\" + b + \"|str密钥:\" + bytesToString(a));\n        console.log(\"算法名：\" + b + \"|Hex密钥:\" + bytesToHex(a));\n        return result;\n    }\n\n    var DESKeySpec = Java.use('javax.crypto.spec.DESKeySpec');\n    DESKeySpec.$init.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.$init(a);\n        console.log(\"======================================\");\n        var bytes_key_des = this.getKey();\n        console.log(\"des密钥  |str \" + bytesToString(bytes_key_des));\n        console.log(\"des密钥  |hex \" + bytesToHex(bytes_key_des));\n        return result;\n    }\n\n    DESKeySpec.$init.overload('[B', 'int').implementation = function (a, b) {\n        showStacks();\n        var result = this.$init(a, b);\n        console.log(\"======================================\");\n        var bytes_key_des = this.getKey();\n        console.log(\"des密钥  |str \" + bytesToString(bytes_key_des));\n        console.log(\"des密钥  |hex \" + bytesToHex(bytes_key_des));\n        return result;\n    }\n\n    var mac = Java.use('javax.crypto.Mac');\n    mac.getInstance.overload('java.lang.String').implementation = function (a) {\n        showStacks();\n        var result = this.getInstance(a);\n        console.log(\"======================================\");\n        console.log(\"算法名：\" + a);\n        return result;\n    }\n    mac.update.overload('[B').implementation = function (a) {\n        //showStacks();\n        this.update(a);\n        console.log(\"======================================\");\n        console.log(\"update:\" + bytesToString(a))\n    }\n    mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {\n        //showStacks();\n        this.update(a, b, c)\n        console.log(\"======================================\");\n        console.log(\"update:\" + bytesToString(a) + \"|\" + b + \"|\" + c);\n    }\n    mac.doFinal.overload().implementation = function () {\n        //showStacks();\n        var result = this.doFinal();\n        console.log(\"======================================\");\n        console.log(\"doFinal结果: |str  :\"     + bytesToString(result));\n        console.log(\"doFinal结果: |hex  :\"     + bytesToHex(result));\n        console.log(\"doFinal结果: |base64  :\"  + bytesToBase64(result));\n        return result;\n    }\n    mac.doFinal.overload('[B').implementation = function (a) {\n        //showStacks();\n        var result = this.doFinal(a);\n        console.log(\"======================================\");\n        console.log(\"doFinal参数: |str  :\"     + bytesToString(a));\n        console.log(\"doFinal参数: |hex  :\"     + bytesToHex(a));\n        console.log(\"doFinal结果: |str  :\"     + bytesToString(result));\n        console.log(\"doFinal结果: |hex  :\"     + bytesToHex(result));\n        console.log(\"doFinal结果: |base64  :\"  + bytesToBase64(result));\n        return result;\n    }\n\n    var md = Java.use('java.security.MessageDigest');\n    md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {\n        //showStacks();\n        console.log(\"======================================\");\n        console.log(\"算法名：\" + a);\n        return this.getInstance(a, b);\n    }\n    md.getInstance.overload('java.lang.String').implementation = function (a) {\n        //showStacks();\n        console.log(\"======================================\");\n        console.log(\"算法名：\" + a);\n        return this.getInstance(a);\n    }\n    md.update.overload('[B').implementation = function (a) {\n        //showStacks();\n        console.log(\"======================================\");\n        console.log(\"update:\" + bytesToString(a))\n        return this.update(a);\n    }\n    md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {\n        //showStacks();\n        console.log(\"======================================\");\n        console.log(\"update:\" + bytesToString(a) + \"|\" + b + \"|\" + c);\n        return this.update(a, b, c);\n    }\n    md.digest.overload().implementation = function () {\n        //showStacks();\n        console.log(\"======================================\");\n        var result = this.digest();\n        console.log(\"digest结果 |hex:\" + bytesToHex(result));\n        console.log(\"digest结果 |base64:\" + bytesToBase64(result));\n        return result;\n    }\n    md.digest.overload('[B').implementation = function (a) {\n        //showStacks();\n        console.log(\"======================================\");\n        console.log(\"digest参数 |str:\" + bytesToString(a));\n        console.log(\"digest参数 |hex:\" + bytesToHex(a));\n        var result = this.digest(a);\n        console.log(\"digest结果: |hex\" + bytesToHex(result));\n        console.log(\"digest结果: |base64\" + bytesToBase64(result));\n        return result;\n    }\n\n    var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');\n    ivParameterSpec.$init.overload('[B').implementation = function (a) {\n        //showStacks();\n        var result = this.$init(a);\n        console.log(\"======================================\");\n        console.log(\"iv向量: |str:\" + bytesToString(a));\n        console.log(\"iv向量: |hex:\" + bytesToHex(a));\n        return result;\n    }\n\n    var cipher = Java.use('javax.crypto.Cipher');\n    cipher.getInstance.overload('java.lang.String').implementation = function (a) {\n        //showStacks();\n        var result = this.getInstance(a);\n        console.log(\"======================================\");\n        console.log(\"模式填充:\" + a);\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.Key').implementation = function (a, b) {\n        //showStacks();\n        var result = this.init(a, b);\n        console.log(\"======================================\");\n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n\n        var bytes_key = b.getEncoded();\n        console.log(\"init key:\" + \"|str密钥:\" + bytesToString(bytes_key));\n        console.log(\"init key:\" + \"|Hex密钥:\" + bytesToHex(bytes_key));\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function (a, b) {\n        //showStacks();\n        var result = this.init(a, b);\n        console.log(\"======================================\");\n        \n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (a, b, c) {\n        //showStacks();\n        var result = this.init(a, b, c);\n        console.log(\"======================================\");\n        \n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n     \n        var bytes_key = b.getEncoded();\n        console.log(\"init key:\" + \"|str密钥:\" + bytesToString(bytes_key));\n        console.log(\"init key:\" + \"|Hex密钥:\" + bytesToHex(bytes_key));\n\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function (a, b, c) {\n        //showStacks();\n        var result = this.init(a, b, c);\n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function (a, b, c) {\n        //showStacks();\n        var result = this.init(a, b, c);\n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n\n         var bytes_key = b.getEncoded();\n        console.log(\"init key:\" + \"|str密钥:\" + bytesToString(bytes_key));\n        console.log(\"init key:\" + \"|Hex密钥:\" + bytesToHex(bytes_key));\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function (a, b, c) {\n        //showStacks();\n        var result = this.init(a, b, c);\n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n\n        var bytes_key = b.getEncoded();\n        console.log(\"init key:\" + \"|str密钥:\" + bytesToString(bytes_key));\n        console.log(\"init key:\" + \"|Hex密钥:\" + bytesToHex(bytes_key));\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function (a, b, c, d) {\n        //showStacks();\n        var result = this.init(a, b, c, d);\n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n\n        var bytes_key = b.getEncoded();\n        console.log(\"init key:\" + \"|str密钥:\" + bytesToString(bytes_key));\n        console.log(\"init key:\" + \"|Hex密钥:\" + bytesToHex(bytes_key));\n        return result;\n    }\n    cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function (a, b, c, d) {\n        //showStacks();\n        var result = this.init(a, b, c, d);\n        if (N_ENCRYPT_MODE == a) \n        {\n            console.log(\"init  | 加密模式\");    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            console.log(\"init  | 解密模式\");    \n        }\n\n         var bytes_key = b.getEncoded();\n        console.log(\"init key:\" + \"|str密钥:\" + bytesToString(bytes_key));\n        console.log(\"init key:\" + \"|Hex密钥:\" + bytesToHex(bytes_key));\n        return result;\n    }\n\n    cipher.update.overload('[B').implementation = function (a) {\n        //showStacks();\n        var result = this.update(a);\n        console.log(\"======================================\");\n        console.log(\"update:\" + bytesToString(a));\n        return result;\n    }\n    cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {\n        //showStacks();\n        var result = this.update(a, b, c);\n        console.log(\"======================================\");\n        console.log(\"update:\" + bytesToString(a) + \"|\" + b + \"|\" + c);\n        return result;\n    }\n    cipher.doFinal.overload().implementation = function () {\n        //showStacks();\n        var result = this.doFinal();\n        console.log(\"======================================\");\n        console.log(\"doFinal结果: |str  :\"     + bytesToString(result));\n        console.log(\"doFinal结果: |hex  :\"     + bytesToHex(result));\n        console.log(\"doFinal结果: |base64  :\"  + bytesToBase64(result));\n        return result;\n    }\n    cipher.doFinal.overload('[B').implementation = function (a) {\n        //showStacks();\n        var result = this.doFinal(a);\n        console.log(\"======================================\");\n        console.log(\"doFinal参数: |str  :\"     + bytesToString(a));\n        console.log(\"doFinal参数: |hex  :\"     + bytesToHex(a));\n        console.log(\"doFinal结果: |str  :\"     + bytesToString(result));\n        console.log(\"doFinal结果: |hex  :\"     + bytesToHex(result));\n        console.log(\"doFinal结果: |base64  :\"  + bytesToBase64(result));\n        return result;\n    }\n\n    var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');\n    x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {\n        //showStacks();\n        var result = this.$init(a);\n        console.log(\"======================================\");\n        console.log(\"RSA密钥:\" + bytesToBase64(a));\n        return result;\n    }\n\n    var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');\n    rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {\n        //showStacks();\n        var result = this.$init(a, b);\n        console.log(\"======================================\");\n        //console.log(\"RSA密钥:\" + bytesToBase64(a));\n        console.log(\"RSA密钥N:\" + a.toString(16));\n        console.log(\"RSA密钥E:\" + b.toString(16));\n        return result;\n    }\n\n    var KeyPairGenerator = Java.use('java.security.KeyPairGenerator');\n    KeyPairGenerator.generateKeyPair.implementation = function () \n    {\n        //showStacks();\n        var result = this.generateKeyPair();\n        console.log(\"======================================\");\n        \n        var str_private = result.getPrivate().getEncoded();\n        var str_public = result.getPublic().getEncoded();\n        console.log(\"公钥  |hex\" + bytesToHex(str_public));\n        console.log(\"私钥  |hex\" + bytesToHex(str_private));\n\n        return result;\n    }\n\n    KeyPairGenerator.genKeyPair.implementation = function () \n    {\n        //showStacks();\n        var result = this.genKeyPair();\n        console.log(\"======================================\");\n\n        var str_private = result.getPrivate().getEncoded();\n        var str_public = result.getPublic().getEncoded();\n        console.log(\"公钥  |hex\" + bytesToHex(str_public));\n        console.log(\"私钥  |hex\" + bytesToHex(str_private));\n\n        return result;\n    }\n});\n"
  },
  {
    "path": "第六章：安卓逆向/Frida/Frida自吐算法.py",
    "content": "# -*- coding: UTF-8 -*-\n# 代码引用自 guyezhou51\n\nimport frida\nimport sys\n\n\ndef on_message(message, data):\n    if message['type'] == 'send':\n        ss = \"[*]{0}\".format(message['payload'])\n        file_handle = open('log.txt', mode='a+')\n        file_handle.write('%s \\r\\n' % (ss))\n        file_handle.close()\n    else:\n        print(message)\n\n\ndef get_js():\n    htmlstr = '''\nvar N_ENCRYPT_MODE = 1;\nvar N_DECRYPT_MODE = 2;\n\nfunction showStacks() {\n    var Exception = Java.use(\"java.lang.Exception\");\n    var ins = Exception.$new(\"Exception\");\n    var straces = ins.getStackTrace();\n\n    if (undefined == straces || null == straces) {\n        return;\n    }\n\n    mylog(\"===================== Stack strat=======================\",\"\",\"\",0);    \n\n    for (var i = 0; i < straces.length; i++) {\n        var str = \"   \" + straces[i].toString();\n        mylog(str,\"\",\"\",0);\n    }\n\n\n    mylog(\"====================== Stack end=======================\",\"\",\"\",0);\n    Exception.$dispose();\n};\n\n//工具相关函数 \nvar base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',\n    base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, (-1), (-1), (-1), (-1), (-1), (-1), 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, (-1), (-1), (-1), (-1), (-1));\n\nfunction bytesToHex(arr) {\n    var str = '';\n    arr = new Uint8Array(arr);\n    var k, j;\n    for (var i = 0; i < arr.length; i++) {\n        k = arr[i];\n        j = k;\n        if (k < 0) {\n            j = k + 256;\n        }\n        if (j < 16) {\n            str += \"0\";\n        }\n        str += j.toString(16);\n    }\n    return str;\n};\n//将byte[]转成String的方法\nfunction bytesToString(arr) {\n    var str = '';\n    arr = new Uint8Array(arr);\n    for (var i in arr) {\n        str += String.fromCharCode(arr[i]);\n    }\n    return str;\n};\nfunction bytesToBase64(e) {\n    e = new Uint8Array(e);\n    var r, a, c, h, o, t;\n    for (c = e.length, a = 0, r = ''; a < c;) {\n        if (h = 255 & e[a++], a == c) {\n            r += base64EncodeChars.charAt(h >> 2),\n                r += base64EncodeChars.charAt((3 & h) << 4),\n                r += '==';\n            break;\n        }\n        if (o = e[a++], a == c) {\n            r += base64EncodeChars.charAt(h >> 2),\n                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),\n                r += base64EncodeChars.charAt((15 & o) << 2),\n                r += '=';\n            break;\n        }\n        t = e[a++],\n            r += base64EncodeChars.charAt(h >> 2),\n            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),\n            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),\n            r += base64EncodeChars.charAt(63 & t);\n    }\n    return r;\n};\n\n//stringToBase64 stringToHex stringToBytes\n//base64ToString base64ToHex base64ToBytes\n//               hexToBase64  hexToBytes    \n// bytesToBase64 bytesToHex bytesToString\nfunction mylog(s,code,s2,ii){\n    if(ii==1){ \n\n        //输出hex类型\n        var str =  bytesToHex(code)+s2;\n        console.log(s+\" |HEX :\"+str);\n        send(s+\" |HEX :\"+str);\n        //输出base64\n        str = bytesToBase64(code)+s2;\n        console.log( s+\" |BASE64 :\"+str);\n        send(s+\" |BASE64 :\"+str);\n\n        //输出string类型\n        str =  bytesToString(code)+s2;\n        console.log(s+\" |str :\"+str);\n        send(s+\" |str :\"+str);\n    }else{\n        console.log(\"print: \"+s);\n        send(\"print: \"+s);\n    }\n\n};\n\nJava.perform(function () {\n    var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');\n    var AE算法名称 = null;\n    secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {\n        showStacks();\n        var result = this.$init(a, b);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"算法名：\" + b + \"| 密钥\" , a,\"\",1);   \n        AE算法名称=b;    \n        return result;\n    };\n\n    secretKeySpec.$init.overload('[B', 'int','int','java.lang.String').implementation = function (a,i1,i2, b) {\n        showStacks();\n        var result = this.$init(a,i1,i2,b);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"算法名：\" + b + \"| 密钥\" , a,\"    |开始取的位置\"+i1+\"取长度:\"+i2,1);   \n        AE算法名称=b;    \n        return result;\n    };\n\n    var DESKeySpec = Java.use('javax.crypto.spec.DESKeySpec');\n    DESKeySpec.$init.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.$init(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        var bytes_key_des = this.getKey();\n        mylog(\"des密钥 \" ,bytes_key_des,\"\",1);        \n        return result;\n    };\n\n    DESKeySpec.$init.overload('[B', 'int').implementation = function (a, b) {\n        showStacks();\n        var result = this.$init(a, b);\n        mylog(\"======================================\",\"\",\"\",0);\n        var bytes_key_des = this.getKey();\n        mylog(\"des密钥 \" , bytes_key_des,\"\",1);      \n        return result;\n    };\n    //3des\n    var DESedeKeySpec = Java.use('javax.crypto.spec.DESedeKeySpec');\n    DESedeKeySpec.$init.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.$init(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        var bytes_key_des = this.getKey();\n        mylog(\"des密钥 \" ,bytes_key_des,\"\",1);        \n        return result;\n    };\n\n    DESedeKeySpec.$init.overload('[B', 'int').implementation = function (a, b) {\n        showStacks();\n        var result = this.$init(a, b);\n        mylog(\"======================================\",\"\",\"\",0);\n        var bytes_key_des = this.getKey();\n        mylog(\"des密钥 \" , bytes_key_des,\"\",1);      \n        return result;\n    };\n\n\n    var mac = Java.use('javax.crypto.Mac');\n    var MAC算法名称=null;\n    mac.getInstance.overload('java.lang.String').implementation = function (a) {\n        showStacks();\n        var result = this.getInstance(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"Mac算法名：\" + a,\"\",\"\",0);\n        MAC算法名称 =a;\n        return result;\n    };\n    mac.update.overload('[B').implementation = function (a) {\n        showStacks();\n        this.update(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(MAC算法名称+\"update:\" ,a,\"\",1);\n\n    };\n    mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {\n        showStacks();\n        this.update(a, b, c);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(MAC算法名称+\"update:\" , a , \"|\" + b + \"|\" + c,1);      \n    };\n    mac.update.overload('java.nio.ByteBuffer').implementation = function (a) {\n        showStacks();\n        this.update(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(MAC算法名称+\"update:\" ,a.array() , \"\",1);      \n    };\n    mac.doFinal.overload().implementation = function () {\n        showStacks();\n        var result = this.doFinal();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(MAC算法名称+\"doFinal结果:\", result,\"\",1);\n        return result;\n    };\n    mac.doFinal.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.doFinal(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(MAC算法名称+\"doFinal参数:\",a,\"\",1);\n        return result;\n    };\n    mac.doFinal.overload('[B','int').implementation = function (a,b) {\n        showStacks();\n        var result = this.doFinal(a,b);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(MAC算法名称+\"doFinal参数:\",a,\"  |  \"+b,1);\n        return result;\n    };\n\n    var md = Java.use('java.security.MessageDigest');\n    var HX算法名称=null;\n    md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"算法名：\" + a,\"\",\"\",0);\n        HX算法名称 = a;\n        return this.getInstance(a, b);\n    };\n    md.getInstance.overload('java.lang.String', 'java.security.Provider').implementation = function (a, b) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"算法名：\" + a,\"\",\"\",0);\n        HX算法名称 = a;\n        return this.getInstance(a, b);\n    };\n    md.getInstance.overload('java.lang.String').implementation = function (a) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"算法名：\" + a,\"\",\"\",0);\n        HX算法名称 = a;\n        return this.getInstance(a);\n    };\n    md.update.overload('[B').implementation = function (a) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(HX算法名称+\"_update:\" , a,\"\",1);     \n        return this.update(a);\n    };\n    md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(HX算法名称+\"_update:\" , a , \"|\" + b + \"|\" + c,1);       \n        return this.update(a, b, c);\n    };\n    md.update.overload('java.nio.ByteBuffer').implementation = function (a) {\n        showStacks();\n        this.update(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(HX算法名称+\"update:\" ,a.array() , \"\",1);      \n    };\n    md.digest.overload().implementation = function () {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        var result = this.digest();\n        mylog(HX算法名称+\"_digest结果:\" , result,\"\",1);        \n        return result;\n    };\n    md.digest.overload('[B').implementation = function (a) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(HX算法名称+\"_digest参数:\" , a,\"\",1);\n        var result = this.digest(a);\n        mylog(HX算法名称+\"_digest结果:\" , result,\"\",1);        \n        return result;\n    } ; \n    md.digest.overload('[B','int','int').implementation = function (a,b,c) {\n        showStacks();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(HX算法名称+\"_digest参数:\" , a,\"   |\"+b+\"|\"+c,1);\n        var result = this.digest(a,b,c);\n        mylog(HX算法名称+\"_digest结果:\" , result,\"\",1);        \n        return result;\n    };\n\n    var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');\n    ivParameterSpec.$init.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.$init(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"iv向量: \" ,a,\"\",1);\n        return result;\n    };\n    var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');\n    ivParameterSpec.$init.overload('[B','int','int').implementation = function (a,b,c) {\n        showStacks();\n        var result = this.$init(a,b,c);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"iv向量: \" ,a,\"   |\"+b+\"|\"+c,1);\n        return result;\n    };\n\n    var cipher = Java.use('javax.crypto.Cipher');\n    cipher.getInstance.overload('java.lang.String').implementation = function (a) {\n        showStacks();\n        var result = this.getInstance(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_模式填充:\" + a,\"\",\"\",0);\n        return result;\n    };\n    cipher.init.overload('int', 'java.security.Key').implementation = function (a, b) {\n        showStacks();\n        var result = this.init(a, b);\n        mylog(\"======================================\",\"\",\"\",0);\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n\n        var bytes_key = b.getEncoded();\n        mylog(AE算法名称+\"_init key:\" + \"|密钥\" , bytes_key,\"\",1);       \n        return result;\n    };\n    cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function (a, b) {\n        showStacks();\n        var result = this.init(a, b);\n        mylog(\"======================================\",\"\",\"\",0);\n\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n\n        return result;\n    };\n    cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (a, b, c) {\n        showStacks();\n        var result = this.init(a, b, c);\n        mylog(\"======================================\",\"\",\"\",0);\n\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n\n        var bytes_key = b.getEncoded();\n        mylog(AE算法名称+\"_init key:\" + \"|密钥\" ,bytes_key,\"\",1); \n        return result;\n    };\n    cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function (a, b, c) {\n        showStacks();\n        var result = this.init(a, b, c);\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n        return result;\n    };\n    cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function (a, b, c) {\n        showStacks();\n        var result = this.init(a, b, c);\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n\n         var bytes_key = b.getEncoded();\n        mylog(AE算法名称+\"_init key:\" + \"密钥:\" , bytes_key,\"\",1);       \n        return result;\n    };\n    cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function (a, b, c) {\n        showStacks();\n        var result = this.init(a, b, c);\n        if (N_ENCRYPT_MODE == a) \n        {\n           mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n\n        var bytes_key = b.getEncoded();\n        mylog(AE算法名称+\"_init key:\" + \"密钥:\" , bytes_key,\"\",1);\n\n        return result;\n    };\n    cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function (a, b, c, d) {\n        showStacks();\n        var result = this.init(a, b, c, d);\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        }\n\n        var bytes_key = b.getEncoded();\n        mylog(AE算法名称+\"_init key:\" + \"密钥:\" , bytes_key,\"\",1);        \n        return result;\n    };\n    cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function (a, b, c, d) {\n        showStacks();\n        var result = this.update(a, b, c, d);\n        if (N_ENCRYPT_MODE == a) \n        {\n            mylog(AE算法名称+\"_init  | 加密模式\",\"\",\"\",0);    \n        }\n        else if(N_DECRYPT_MODE == a)\n        {\n            mylog(AE算法名称+\"_init  | 解密模式\",\"\",\"\",0);    \n        };\n\n         var bytes_key = b.getEncoded();\n        mylog(AE算法名称+\"_init key:\" + \"|密钥:\" ,bytes_key,\"\",1);       \n        return result;\n    };\n\n    cipher.update.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.update(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_update:\" , a,\"\",1);  \n        return result;\n    };\n    cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {\n        showStacks();\n        var result = this.update(a, b, c);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_update: \" , a , \"|\" + b + \"|\" + c,1);\n        return result;\n    };\n    cipher.update.overload('[B', 'int', 'int','[B').implementation = function (a, b, c,d) {\n        showStacks();\n        var result = this.update(a, b, c, d);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_update: \" , a , \"|\" + b + \"|\" + c,1);\n        mylog(AE算法名称+\"_update:结果: \" , d , \"|\" + b + \"|\" + c,1);\n        return result;\n    };\n    cipher.update.overload('[B', 'int', 'int','[B','int').implementation = function (a, b, c,d,e) {\n        showStacks();\n        var result = this.update(a, b, c, d,e);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_update: \" , a , \"|\" + b + \"|\" + c + \"|\" + e,1);\n        mylog(AE算法名称+\"_update:结果: \" , d , \"|\" + b + \"|\" + c+ \"|\" + e,1);\n        return result;\n    }  ;  \n    cipher.update.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function (a, b) {\n        showStacks();\n        var result = this.update(a,b);        \n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"(ByteBuffer)_update: \" , a.array() ,\"\",1);\n        mylog(AE算法名称+\"(ByteBuffer)_update:结果: \" , b.array(), \"\" ,1);\n        return result;\n    };\n    cipher.doFinal.overload().implementation = function () {\n        showStacks();\n        var result = this.doFinal();\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_doFinal结果: \",result,\"\",1);\n        return result;\n    };\n    cipher.doFinal.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.doFinal(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(AE算法名称+\"_doFinal参数: \" ,a,\"\",1);\n        mylog(AE算法名称+\"_doFinal结果: \",result,\"\",1);\n\n        return result;\n    };\n    cipher.doFinal.overload('[B','int').implementation = function (a,b) {\n        showStacks();\n        var result = this.doFinal(a,b);\n        mylog(\"======================================\",\"\",\"\",0);        \n        mylog(AE算法名称+\"_doFinal结果: \", a,\"   |\"+b,1);\n\n        return result;\n    };\n\n    cipher.doFinal.overload('[B','int','int').implementation = function (a,b,c) {\n        showStacks();\n        var result = this.doFinal(a,b,c);\n        mylog(\"======================================\",\"\",\"\",0);        \n        mylog(AE算法名称+\"_doFinal参数: \" ,a,\"   |\"+b+\"|\"+c,1);\n        mylog(AE算法名称+\"_doFinal结果: \",result,\"\",1);\n        return result;\n    };\n\n    cipher.doFinal.overload('[B','int','int','[B','int').implementation = function (a,b,c,d,e) {\n        showStacks();\n        var result = this.doFinal(a,b,c,d,e);\n        mylog(\"======================================\",\"\",\"\",0);        \n        mylog(AE算法名称+\"_doFinal参数: \" ,a,\"   |\"+b+\"|\"+c,1);\n        mylog(AE算法名称+\"_doFinal结果: \",d,\"  |\"+e,1);\n        return result;\n    };\n    cipher.doFinal.overload('[B','int','int','[B').implementation = function (a,b,c,d) {\n        showStacks();\n        var result = this.doFinal(a,b,c,d);\n        mylog(\"======================================\",\"\",\"\",0);        \n        mylog(AE算法名称+\"_doFinal参数: \" ,a,\"   |\"+b+\"|\"+c,1);\n        mylog(AE算法名称+\"_doFinal结果: \",d,\"\",1);\n        return result;\n    };\n\n    var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');\n    x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {\n        showStacks();\n        var result = this.$init(a);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"RSA密钥:\" + bytesToBase64(a),\"\",\"\",0);\n        return result;\n    };\n\n    var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');\n    rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {\n        showStacks();\n        var result = this.$init(a, b);\n        mylog(\"======================================\",\"\",\"\",0);\n        //console.log(\"RSA密钥:\" + bytesToBase64(a));\n        mylog(\"RSA密钥N:\" + a.toString(16),\"\",\"\",0);\n        mylog(\"RSA密钥E:\" + b.toString(16),\"\",\"\",0);\n        return result;\n    };\n\n    var KeyPairGenerator = Java.use('java.security.KeyPairGenerator');\n    KeyPairGenerator.generateKeyPair.implementation = function () \n    {\n        showStacks();\n        var result = this.generateKeyPair();\n        mylog(\"======================================\",\"\",\"\",0);\n\n        var str_private = result.getPrivate().getEncoded();\n        var str_public = result.getPublic().getEncoded();\n        mylog(\"公钥 |hex:\" + bytesToHex(str_public),\"\",\"\",0);\n        mylog(\"私钥 |hex:\" + bytesToHex(str_private),\"\",\"\",0);\n\n        return result;\n    };\n\n    KeyPairGenerator.genKeyPair.implementation = function () \n    {\n        showStacks();\n        var result = this.genKeyPair();\n        mylog(\"======================================\",\"\",\"\",0);\n\n        var str_private = result.getPrivate().getEncoded();\n        var str_public = result.getPublic().getEncoded();\n        mylog(\"公钥 |hex:\" + bytesToHex(str_public),\"\",\"\",0);\n        mylog(\"私钥 |hex:\" + bytesToHex(str_private),\"\",\"\",0);\n        return result;\n    };\n\n        //返回输出流\n        var OutStream = Java.use('java.io.OutputStream');\n        OutStream['write'].overload('[B').implementation = function(data) {   \n            showStacks();\n            var ret = this.write(data);\n            mylog(\"======================================\",\"\",\"\",0);\n            mylog(\"TCP接收 输出流:\",data,\"\" ,1);\n            return ret;\n        };\n        //返回输出流\n        OutStream['write'].overload('[B','int','int').implementation = function(data,a,b) {   \n            showStacks();\n            var ret = this.write(data,a,b);\n            mylog(\"======================================\",\"\",\"\",0);\n            mylog(\"TCP接收 输出流:\",data,\"  |\"+a+\"|\"+b  ,1);\n            return ret;\n        };\n         //返回输入流\n    var Stream = Java.use('java.io.InputStream');\n    Java.use(\"java.net.Socket\").getInputStream.overload().implementation=function(){\n        showStacks();\n        mylog(\"tcp 输入流======================================\",\"\",\"\",0);\n        var rets = this.getInputStream()     \n        return rets;\n    };\n\n\n    Stream['read'].overload('[B').implementation = function(data) {   \n        mylog(\"tcp 输入流======================================\",\"\",\"\",0);\n            showStacks();\n            var ret = this.read(data);\n            mylog(\"======================================\",\"\",\"\",0);\n            mylog(\"tcp 输入流:\",data,\"\" ,1);\n            return ret;\n        };\n            //返回输入流\n    Stream['read'].overload('[B','int','int').implementation = function(data,a,b) {  \n        mylog(\"tcp 输入流======================================\",\"\",\"\",0); \n        showStacks();\n        var ret = this.read(data,a,b);\n        mylog(\"======================================\",\"\",\"\",0);\n        mylog(\"tcp 输入流:\",data,\"  |\"+a+\"|\"+b ,1);\n        return ret;\n    };\n});\n\n\n\n    '''\n    return htmlstr\n\n\ndef mians(pakname):\n    print(pakname)\n    jscod = get_js()\n    process = frida.get_remote_device().attach(pakname)\n    script = process.create_script(jscod)\n    script.on(\"message\", on_message)\n    script.load()\n    sys.stdin.read()\n\n\n\n\n\n\n"
  },
  {
    "path": "第六章：安卓逆向/Frida/Frida过Root检测.js",
    "content": "\n// $ frida -l antiroot.js -U -f com.example.app --no-pause\n// CHANGELOG by Pichaya Morimoto (p.morimoto@sth.sh): \n//  - I added extra whitelisted items to deal with the latest versions \n// \t\t\t\t\t\tof RootBeer/Cordova iRoot as of August 6, 2019\n//  - The original one just fucked up (kill itself) if Magisk is installed lol\n// Credit & Originally written by: https://codeshare.frida.re/@dzonerzy/fridantiroot/\n// If this isn't working in the future, check console logs, rootbeer src, or libtool-checker.so\nJava.perform(function() {\n\n    var RootPackages = [\"com.noshufou.android.su\", \"com.noshufou.android.su.elite\", \"eu.chainfire.supersu\",\n        \"com.koushikdutta.superuser\", \"com.thirdparty.superuser\", \"com.yellowes.su\", \"com.koushikdutta.rommanager\",\n        \"com.koushikdutta.rommanager.license\", \"com.dimonvideo.luckypatcher\", \"com.chelpus.lackypatch\",\n        \"com.ramdroid.appquarantine\", \"com.ramdroid.appquarantinepro\", \"com.devadvance.rootcloak\", \"com.devadvance.rootcloakplus\",\n        \"de.robv.android.xposed.installer\", \"com.saurik.substrate\", \"com.zachspong.temprootremovejb\", \"com.amphoras.hidemyroot\",\n        \"com.amphoras.hidemyrootadfree\", \"com.formyhm.hiderootPremium\", \"com.formyhm.hideroot\", \"me.phh.superuser\",\n        \"eu.chainfire.supersu.pro\", \"com.kingouser.com\", \"com.android.vending.billing.InAppBillingService.COIN\",\"com.topjohnwu.magisk\"\n    ];\n\n    var RootBinaries = [\"su\", \"busybox\", \"supersu\", \"Superuser.apk\", \"KingoUser.apk\", \"SuperSu.apk\",\"magisk\"];\n\n    var RootProperties = {\n        \"ro.build.selinux\": \"1\",\n        \"ro.debuggable\": \"0\",\n        \"service.adb.root\": \"0\",\n        \"ro.secure\": \"1\"\n    };\n\n    var RootPropertiesKeys = [];\n\n    for (var k in RootProperties) RootPropertiesKeys.push(k);\n\n    var PackageManager = Java.use(\"android.app.ApplicationPackageManager\");\n\n    var Runtime = Java.use('java.lang.Runtime');\n\n    var NativeFile = Java.use('java.io.File');\n\n    var String = Java.use('java.lang.String');\n\n    var SystemProperties = Java.use('android.os.SystemProperties');\n\n    var BufferedReader = Java.use('java.io.BufferedReader');\n\n    var ProcessBuilder = Java.use('java.lang.ProcessBuilder');\n\n    var StringBuffer = Java.use('java.lang.StringBuffer');\n\n    var loaded_classes = Java.enumerateLoadedClassesSync();\n\n    send(\"Loaded \" + loaded_classes.length + \" classes!\");\n\n    var useKeyInfo = false;\n\n    var useProcessManager = false;\n\n    send(\"loaded: \" + loaded_classes.indexOf('java.lang.ProcessManager'));\n\n    if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) {\n        try {\n            //useProcessManager = true;\n            //var ProcessManager = Java.use('java.lang.ProcessManager');\n        } catch (err) {\n            send(\"ProcessManager Hook failed: \" + err);\n        }\n    } else {\n        send(\"ProcessManager hook not loaded\");\n    }\n\n    var KeyInfo = null;\n\n    if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) {\n        try {\n            //useKeyInfo = true;\n            //var KeyInfo = Java.use('android.security.keystore.KeyInfo');\n        } catch (err) {\n            send(\"KeyInfo Hook failed: \" + err);\n        }\n    } else {\n        send(\"KeyInfo hook not loaded\");\n    }\n\n    PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pname, flags) {\n        var shouldFakePackage = (RootPackages.indexOf(pname) > -1);\n        if (shouldFakePackage) {\n            send(\"Bypass root check for package: \" + pname);\n            pname = \"set.package.name.to.a.fake.one.so.we.can.bypass.it\";\n        }\n        return this.getPackageInfo.call(this, pname, flags);\n    };\n\n    NativeFile.exists.implementation = function() {\n        var name = NativeFile.getName.call(this);\n        var shouldFakeReturn = (RootBinaries.indexOf(name) > -1);\n        if (shouldFakeReturn) {\n            send(\"Bypass return value for binary: \" + name);\n            return false;\n        } else {\n            return this.exists.call(this);\n        }\n    };\n\n    var exec = Runtime.exec.overload('[Ljava.lang.String;');\n    var exec1 = Runtime.exec.overload('java.lang.String');\n    var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;');\n    var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;');\n    var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File');\n    var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File');\n\n    exec5.implementation = function(cmd, env, dir) {\n        if (cmd.indexOf(\"getprop\") != -1 || cmd == \"mount\" || cmd.indexOf(\"build.prop\") != -1 || cmd == \"id\" || cmd == \"sh\") {\n            var fakeCmd = \"grep\";\n            send(\"Bypass \" + cmd + \" command\");\n            return exec1.call(this, fakeCmd);\n        }\n        if (cmd == \"su\") {\n            var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n            send(\"Bypass \" + cmd + \" command\");\n            return exec1.call(this, fakeCmd);\n        }\n        if (cmd == \"which\") {\n            var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n            send(\"Bypass which command\");\n            return exec1.call(this, fakeCmd);\n        }\n        return exec5.call(this, cmd, env, dir);\n    };\n\n    exec4.implementation = function(cmdarr, env, file) {\n        for (var i = 0; i < cmdarr.length; i = i + 1) {\n            var tmp_cmd = cmdarr[i];\n            if (tmp_cmd.indexOf(\"getprop\") != -1 || tmp_cmd == \"mount\" || tmp_cmd.indexOf(\"build.prop\") != -1 || tmp_cmd == \"id\" || tmp_cmd == \"sh\") {\n                var fakeCmd = \"grep\";\n                send(\"Bypass \" + cmdarr + \" command\");\n                return exec1.call(this, fakeCmd);\n            }\n\n            if (tmp_cmd == \"su\") {\n                var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n                send(\"Bypass \" + cmdarr + \" command\");\n                return exec1.call(this, fakeCmd);\n            }\n        }\n        return exec4.call(this, cmdarr, env, file);\n    };\n\n    exec3.implementation = function(cmdarr, envp) {\n        for (var i = 0; i < cmdarr.length; i = i + 1) {\n            var tmp_cmd = cmdarr[i];\n            if (tmp_cmd.indexOf(\"getprop\") != -1 || tmp_cmd == \"mount\" || tmp_cmd.indexOf(\"build.prop\") != -1 || tmp_cmd == \"id\" || tmp_cmd == \"sh\") {\n                var fakeCmd = \"grep\";\n                send(\"Bypass \" + cmdarr + \" command\");\n                return exec1.call(this, fakeCmd);\n            }\n\n            if (tmp_cmd == \"su\") {\n                var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n                send(\"Bypass \" + cmdarr + \" command\");\n                return exec1.call(this, fakeCmd);\n            }\n        }\n        return exec3.call(this, cmdarr, envp);\n    };\n\n    exec2.implementation = function(cmd, env) {\n        if (cmd.indexOf(\"getprop\") != -1 || cmd == \"mount\" || cmd.indexOf(\"build.prop\") != -1 || cmd == \"id\" || cmd == \"sh\") {\n            var fakeCmd = \"grep\";\n            send(\"Bypass \" + cmd + \" command\");\n            return exec1.call(this, fakeCmd);\n        }\n        if (cmd == \"su\") {\n            var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n            send(\"Bypass \" + cmd + \" command\");\n            return exec1.call(this, fakeCmd);\n        }\n        return exec2.call(this, cmd, env);\n    };\n\n    exec.implementation = function(cmd) {\n        for (var i = 0; i < cmd.length; i = i + 1) {\n            var tmp_cmd = cmd[i];\n            if (tmp_cmd.indexOf(\"getprop\") != -1 || tmp_cmd == \"mount\" || tmp_cmd.indexOf(\"build.prop\") != -1 || tmp_cmd == \"id\" || tmp_cmd == \"sh\") {\n                var fakeCmd = \"grep\";\n                send(\"Bypass \" + cmd + \" command\");\n                return exec1.call(this, fakeCmd);\n            }\n\n            if (tmp_cmd == \"su\") {\n                var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n                send(\"Bypass \" + cmd + \" command\");\n                return exec1.call(this, fakeCmd);\n            }\n        }\n\n        return exec.call(this, cmd);\n    };\n\n    exec1.implementation = function(cmd) {\n        if (cmd.indexOf(\"getprop\") != -1 || cmd == \"mount\" || cmd.indexOf(\"build.prop\") != -1 || cmd == \"id\" || cmd == \"sh\") {\n            var fakeCmd = \"grep\";\n            send(\"Bypass \" + cmd + \" command\");\n            return exec1.call(this, fakeCmd);\n        }\n        if (cmd == \"su\") {\n            var fakeCmd = \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\";\n            send(\"Bypass \" + cmd + \" command\");\n            return exec1.call(this, fakeCmd);\n        }\n        return exec1.call(this, cmd);\n    };\n\n    String.contains.implementation = function(name) {\n        if (name == \"test-keys\") {\n            send(\"Bypass test-keys check\");\n            return false;\n        }\n        return this.contains.call(this, name);\n    };\n\n    var get = SystemProperties.get.overload('java.lang.String');\n\n    get.implementation = function(name) {\n        if (RootPropertiesKeys.indexOf(name) != -1) {\n            send(\"Bypass \" + name);\n            return RootProperties[name];\n        }\n        return this.get.call(this, name);\n    };\n\n    Interceptor.attach(Module.findExportByName(\"libc.so\", \"fopen\"), {\n        onEnter: function(args) {\n            var path1 = Memory.readCString(args[0]);\n            var path = path1.split(\"/\");\n            var executable = path[path.length - 1];\n            var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)\n            if (shouldFakeReturn) {\n                Memory.writeUtf8String(args[0], \"/ggezxxx\");\n                send(\"Bypass native fopen >> \"+path1);\n            }\n        },\n        onLeave: function(retval) {\n\n        }\n    });\n\n    Interceptor.attach(Module.findExportByName(\"libc.so\", \"fopen\"), {\n        onEnter: function(args) {\n            var path1 = Memory.readCString(args[0]);\n            var path = path1.split(\"/\");\n            var executable = path[path.length - 1];\n            var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)\n            if (shouldFakeReturn) {\n                Memory.writeUtf8String(args[0], \"/ggezxxx\");\n                send(\"Bypass native fopen >> \"+path1);\n            }\n        },\n        onLeave: function(retval) {\n\n        }\n    });\n\n    Interceptor.attach(Module.findExportByName(\"libc.so\", \"system\"), {\n        onEnter: function(args) {\n            var cmd = Memory.readCString(args[0]);\n            send(\"SYSTEM CMD: \" + cmd);\n            if (cmd.indexOf(\"getprop\") != -1 || cmd == \"mount\" || cmd.indexOf(\"build.prop\") != -1 || cmd == \"id\") {\n                send(\"Bypass native system: \" + cmd);\n                Memory.writeUtf8String(args[0], \"grep\");\n            }\n            if (cmd == \"su\") {\n                send(\"Bypass native system: \" + cmd);\n                Memory.writeUtf8String(args[0], \"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\");\n            }\n        },\n        onLeave: function(retval) {\n\n        }\n    });\n\n    /*\n\n    TO IMPLEMENT:\n\n    Exec Family\n\n    int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);\n    int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);\n    int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);\n    int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);\n    int execv(const char *path, char *const argv[]);\n    int execve(const char *path, char *const argv[], char *const envp[]);\n    int execvp(const char *file, char *const argv[]);\n    int execvpe(const char *file, char *const argv[], char *const envp[]);\n\n    */\n\n\n    BufferedReader.readLine.overload().implementation = function() {\n        var text = this.readLine.call(this);\n        if (text === null) {\n            // just pass , i know it's ugly as hell but test != null won't work :(\n        } else {\n            var shouldFakeRead = (text.indexOf(\"ro.build.tags=test-keys\") > -1);\n            if (shouldFakeRead) {\n                send(\"Bypass build.prop file read\");\n                text = text.replace(\"ro.build.tags=test-keys\", \"ro.build.tags=release-keys\");\n            }\n        }\n        return text;\n    };\n\n    var executeCommand = ProcessBuilder.command.overload('java.util.List');\n\n    ProcessBuilder.start.implementation = function() {\n        var cmd = this.command.call(this);\n        var shouldModifyCommand = false;\n        for (var i = 0; i < cmd.size(); i = i + 1) {\n            var tmp_cmd = cmd.get(i).toString();\n            if (tmp_cmd.indexOf(\"getprop\") != -1 || tmp_cmd.indexOf(\"mount\") != -1 || tmp_cmd.indexOf(\"build.prop\") != -1 || tmp_cmd.indexOf(\"id\") != -1) {\n                shouldModifyCommand = true;\n            }\n        }\n        if (shouldModifyCommand) {\n            send(\"Bypass ProcessBuilder \" + cmd);\n            this.command.call(this, [\"grep\"]);\n            return this.start.call(this);\n        }\n        if (cmd.indexOf(\"su\") != -1) {\n            send(\"Bypass ProcessBuilder \" + cmd);\n            this.command.call(this, [\"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\"]);\n            return this.start.call(this);\n        }\n\n        return this.start.call(this);\n    };\n\n    if (useProcessManager) {\n        var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean');\n        var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean');\n\n        ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) {\n            var fake_cmd = cmd;\n            for (var i = 0; i < cmd.length; i = i + 1) {\n                var tmp_cmd = cmd[i];\n                if (tmp_cmd.indexOf(\"getprop\") != -1 || tmp_cmd == \"mount\" || tmp_cmd.indexOf(\"build.prop\") != -1 || tmp_cmd == \"id\") {\n                    var fake_cmd = [\"grep\"];\n                    send(\"Bypass \" + cmdarr + \" command\");\n                }\n\n                if (tmp_cmd == \"su\") {\n                    var fake_cmd = [\"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\"];\n                    send(\"Bypass \" + cmdarr + \" command\");\n                }\n            }\n            return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);\n        };\n\n        ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) {\n            var fake_cmd = cmd;\n            for (var i = 0; i < cmd.length; i = i + 1) {\n                var tmp_cmd = cmd[i];\n                if (tmp_cmd.indexOf(\"getprop\") != -1 || tmp_cmd == \"mount\" || tmp_cmd.indexOf(\"build.prop\") != -1 || tmp_cmd == \"id\") {\n                    var fake_cmd = [\"grep\"];\n                    send(\"Bypass \" + cmdarr + \" command\");\n                }\n\n                if (tmp_cmd == \"su\") {\n                    var fake_cmd = [\"justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled\"];\n                    send(\"Bypass \" + cmdarr + \" command\");\n                }\n            }\n            return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect);\n        };\n    }\n\n    if (useKeyInfo) {\n        KeyInfo.isInsideSecureHardware.implementation = function() {\n            send(\"Bypass isInsideSecureHardware\");\n            return true;\n        }\n    }\n\n});\n"
  },
  {
    "path": "第六章：安卓逆向/Unidbg/xgorgon.java",
    "content": "package com.douyin;\nimport com.github.unidbg.*;\nimport com.github.unidbg.linux.android.AndroidARMEmulator;\nimport com.github.unidbg.linux.android.AndroidEmulatorBuilder;\nimport com.github.unidbg.linux.android.AndroidResolver;\nimport com.github.unidbg.linux.android.dvm.*;\nimport com.github.unidbg.memory.Memory;\nimport com.github.unidbg.memory.MemoryBlock;\nimport com.github.unidbg.linux.android.dvm.array.ByteArray;\nimport java.io.File;\nimport java.io.IOException;\n\npublic class xgorgon extends AbstractJni {\n\n    private static LibraryResolver createLibraryResolver() {\n        return new AndroidResolver(23);\n    }\n\n    private static AndroidEmulator createARMEmulator() {\n        AndroidEmulator emulator = AndroidEmulatorBuilder.for32Bit().build();\n        return emulator;\n    }\n\n    private final AndroidEmulator emulator;\n    private final VM vm;\n    private final DvmClass Native;\n\n    private xgorgon() {\n        emulator = createARMEmulator();\n        final Memory memory = emulator.getMemory(); memory.setLibraryResolver(createLibraryResolver());\n\n        vm = emulator.createDalvikVM(new File(\"com.sun.jna\"));\n        vm.setJni(this);\n        vm.setVerbose(true); // 自行修改文件路径\n        DalvikModule dm = vm.loadLibrary(new File(\"C:\\\\Users\\\\feiyi\\\\Desktop\\\\unidbg-master\\\\unidbg-android\\\\src\\\\test\\\\java\\\\com\\\\douyin\\\\libcms.so\"), false);\n        dm.callJNI_OnLoad(emulator);\n\n        Native = vm.resolveClass(\"com/ss/sys/ces/a\");\n    }\n    private void destroy() throws IOException {\n        emulator.close();\n        System.out.println(\"destroy\"); }\n    public static void main(String[] args) throws Exception {\n        xgorgon test = new xgorgon();\n        test.test();\n        test.destroy();\n    }\n\n    public static String xuzi1(byte[] bArr) {\n        if (bArr == null) {\n            return null;\n        }\n        char[] charArray = \"0123456789abcdef\".toCharArray();\n        char[] cArr = new char[(bArr.length * 2)];\n        for (int i = 0; i < bArr.length; i++) {\n            int b2 = bArr[i] & 255;\n            int i2 = i * 2;\n            cArr[i2] = charArray[b2 >>> 4];\n            cArr[i2 + 1] = charArray[b2 & 15];\n        }\n        return new String(cArr); }\n\n    private void test() {\n        String methodSign = \"leviathan(II[B)[B\";\n        byte[] data = \"这里是url经过处理后的data\".getBytes();\n        int time = (int) (System.currentTimeMillis() / 1000);\n\n        Native.callStaticJniMethod(emulator, methodSign, -1,time,new ByteArray(vm,data));\n\n        Object ret = Native.callStaticJniMethodObject(emulator, methodSign, -1,time,new ByteArray(vm,data));\n\n        System.out.println(\"callObject执行结果:\"+((DvmObject) ret).getValue());\n        byte[] tt = (byte[]) ((DvmObject) ret).getValue();\n        System.out.println(new String(tt));\n        String s = xuzi1(tt); System.out.println(s);\n    }\n}"
  },
  {
    "path": "第六章：安卓逆向/常见检测及绕过/Frida检测的处理思路.md",
    "content": "执行顺序：\n\n    方法一：找开源方案（10分钟找不到就方法二）\n\n    方法二：换增强版的frida-server（失败到方法三）\n\n    方法三：对应用降级。 （失败到方法四）\n\n    方法四：hook dlopen找so，删除对应so。 （失败到方法五）\n\n    方法五：正常流程分析，找检测点。"
  },
  {
    "path": "第六章：安卓逆向/常见检测及绕过/Root检测的处理示例-1.md",
    "content": "# Root检测的处理示例-1\n\n以**化妆品监管app**的root检测示例：\n\n安装**Magisk + Shamiko**，通过magiskHide配置加入隐藏列表的进程。\n\n1、在magisk右上角开启zygisk  \n2、安装隐藏root的模块 Shamiko-v0.7.3-174-release  \n3、设置中开启magiskHide，并配置加入隐藏列表的进程\n\nShamiko下载地址：[https://pan.baidu.com/s/1WjzIlHriXEhQH6SEQ9SS9g?pwd=uj7u](https://pan.baidu.com/s/1WjzIlHriXEhQH6SEQ9SS9g?pwd=uj7u)\n\n![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/QvjnA3jKxvG42OXo/img/1191a56a-01a7-49b4-babf-7fa71cf01dca.png)\n\n安装配置后，可通过**化妆品监管app**测试Root是否成功隐藏。"
  },
  {
    "path": "第六章：安卓逆向/常见检测及绕过/设备环境检测apk.md",
    "content": "# 环境检测apk（推荐）\n\n## Ruru.apk\n\n一款体积小巧、功能强大的手机检测软件,通过它用户只需动动手指便可以对手机各个模块运行状况进行检测操作,一旦发现相应的异常数据便会进行及时提醒操作。\n\n## RiskDetector.apk\n\nRisk Detector检测软件具备强大的检测能力，不仅能够检测手机的基础信息和root情况，还能深入分析风控风险、软件使用情况以及游戏环境等。它通过多维度的检测，确保手机的每一个环节都处于安全状态。\n\n## Momo.apk\n\nMomo是一款检测root与系统环境的APP，可以检测你的设备是否被root以及系统环境是否存在异常。当你的系统环境存在异常或者未对Momo隐藏root时打开Momo，Momo就会提示“环境异常”，并且会在详情里显示具体存在哪些异常项。\n\n## Luna.apk\n\nLuna环境检测工具app是一款专门为了安卓设备设计出来的一款检测解决方案类型人，在这款软件之中主要是用于是识别设备的硬件信息，系统的状态以及安全的风险，兼容几乎所有的机型，可以对手机型号、版本以及处理器和内存等等手机底层的数据进行检测。\n\n## Hunter.apk\n\nHunter环境检测app是一款非常专业的系统监测类软件，通过这款软件应用能够很好的帮助用户完成各类监测需求，在这里更是具备了设备检测功能，能够带来不错的数据报告检测体验。\n\n## applistdetector.apk\n\napplistdetector应用列表检测器是一款面向安卓用户的环境与应用检测工具，用来快速识别设备上是否存在Magisk、Xposed、LSPosed、TWRP、XPrivacyLua 等可能被第三方 App 用来判定异常环境的迹象。应用将多种检测方式整合在同一页面，点击分组即可展开详细结果，并以清晰的状态图例呈现，便于安全自查、测试与排障。右下角 About 页面还提供源码链接与交流渠道入口，透明可查，适合开发者、安全从业者与进阶用户日常使用。"
  },
  {
    "path": "第六章：安卓逆向/抖音/xposedhook.java",
    "content": "package com.example.xuziqiang.nanotest;\n\nimport de.robv.android.xposed.XposedBridge;\nimport de.robv.android.xposed.XposedHelpers;\nimport de.robv.android.xposed.callbacks.XC_LoadPackage;\n\n\nimport android.text.TextUtils;\nimport android.content.Context;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport fi.iki.elonen.NanoHTTPD;\nimport java.net.URLDecoder;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.zip.GZIPOutputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.io.ByteArrayOutputStream;\nimport java.util.Base64;\n\nimport okhttp3.MediaType;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport java.io.IOException;\nimport java.net.Authenticator;\nimport java.net.InetSocketAddress;\nimport java.net.PasswordAuthentication;\nimport java.net.Proxy;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\n\npublic class AwemeSrv extends NanoHTTPD {\n    private static final String NULL_MD5_STRING = \"00000000000000000000000000000000\";\n    private XC_LoadPackage.LoadPackageParam lpp = null;\n    public  String sessionid=\"\";\n\n    public AwemeSrv() {\n        super(18989);\n    }\n\n    public void init(XC_LoadPackage.LoadPackageParam lpparam) {\n        this.lpp = lpparam;\n        try {\n            start();\n        } catch (Exception e) {\n            XposedBridge.log(\"[ERR]:NanoHTTPD start error! \" + e.toString());\n        }\n    }\n\n    public static byte[] xuzi(String str) {\n        int length = str.length();\n        byte[] bArr = new byte[(length / 2)];\n        for (int i = 0; i < length; i += 2) {\n            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));\n        }\n        return bArr;\n    }\n\n    public static String xuzi1(byte[] bArr) {\n        if (bArr == null) {\n            return null;\n        }\n        char[] charArray = \"0123456789abcdef\".toCharArray();\n        char[] cArr = new char[(bArr.length * 2)];\n        for (int i = 0; i < bArr.length; i++) {\n            int b2 = bArr[i] & 255;\n            int i2 = i * 2;\n            cArr[i2] = charArray[b2 >>> 4];\n            cArr[i2 + 1] = charArray[b2 & 15];\n        }\n        return new String(cArr);\n    }\n\n    public byte[] get_leviathan(int i,int time, byte[] s){\n        return (byte[]) XposedHelpers.callStaticMethod(XposedHelpers.findClass(\"com.ss.sys.ces.a\", lpp.classLoader), \"\" + \"\" + \"\", i, time, s);\n\n    }\n\n    public static String parseStrToMd5L32(byte[] str){\n        String reStr = null;\n        try {\n            MessageDigest md5 = MessageDigest.getInstance(\"MD5\");\n            byte[] bytes = md5.digest(str);\n            StringBuffer stringBuffer = new StringBuffer();\n            for (byte b : bytes){\n                int bt = b&0xff;\n                if (bt < 16){\n                    stringBuffer.append(0);\n                }\n                stringBuffer.append(Integer.toHexString(bt));\n            }\n            reStr = stringBuffer.toString();\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n        return reStr;\n    }\n\n    public byte[] get_ttencrypt(XC_LoadPackage.LoadPackageParam lpp2, byte[] data, int length) {\n        return (byte[]) XposedHelpers.callStaticMethod(XposedHelpers.findClass(\"com.bytedance.frameworks.encryptor.EncryptorUtil\", lpp2.classLoader), \"a\", data, length);\n    }\n\n    public byte[] get_formdata(byte[] data) throws Exception{\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8192);\n        GZIPOutputStream gZIPOutputStream = new GZIPOutputStream(byteArrayOutputStream);\n        gZIPOutputStream.write(data);\n        gZIPOutputStream.close();\n        byte[] bArr2 = byteArrayOutputStream.toByteArray();\n        return get_ttencrypt(this.lpp, bArr2, bArr2.length);\n    }\n\n    public  String get_stub(byte[] barr) throws Exception{\n        String reStr = parseStrToMd5L32(barr);\n        reStr = reStr.toUpperCase();\n        return reStr;\n    }\n\n    public String get_fed(String fed) throws Exception{\n        return  (String) XposedHelpers.callStaticMethod(XposedHelpers.findClass(\"com.ss.a.b.d\", lpp.classLoader), \"a\", fed);\n    }\n\n    public String get_device(String url, String formdata) throws Exception {\n        byte[] data = formdata.getBytes();\n        byte[] barr = get_formdata(data);\n        String stub = get_stub(barr);\n        int time = (int) (System.currentTimeMillis() / 1000);\n        long time1 = System.currentTimeMillis();\n\n        int indexOf = url.indexOf(\"?\");\n        String fed = url.substring(indexOf + 1);\n        String x = get_fed(fed);\n        byte[] s = xuzi(x + x + NULL_MD5_STRING + NULL_MD5_STRING);\n        int i = -1;\n        byte[] gon = get_leviathan(i, time, s);\n\n        String x_gon = xuzi1(gon);\n        JSONObject json_obj = new JSONObject();\n        json_obj.put(\"X-SS-STUB\", stub);\n        json_obj.put(\"X-SS-REQ-TICKET\", time1);\n        json_obj.put(\"X-Gorgon\", x_gon);\n        json_obj.put(\"X-Khronos\", time);\n        String isoString = new String(barr, \"ISO-8859-1\");\n        json_obj.put(\"form\", isoString);\n        return json_obj.toString();\n    }\n\n    private static String getUrl(String url, String stub, long time1, String x_gon, int time, byte[] barr) {\n        String s2 = new String(barr);\n        Authenticator.setDefault(new Authenticator() {\n            public PasswordAuthentication getPasswordAuthentication() {\n                return new PasswordAuthentication(ProxyUser, ProxyPass.toCharArray());\n            }\n        });\n\n        String doc = null;\n        try {\n            doc = Jsoup\n                    .connect(url)\n                    .ignoreContentType(true)\n                    .ignoreHttpErrors(true)\n                    .timeout(3000)\n                    .userAgent(\"okhttp/3.10.0.1\")\n                    .header(\"X-SS-STUB\", stub+\"\")\n                    .header(\"X-SS-QUERIES\", \"\")\n                    .header(\"X-SS-REQ-TICKET\", time1+\"\")\n                    .header(\"X-Gorgon\", x_gon+\"\")\n                    .header(\"X-Khronos\", time+\"\")\n                    .header(\"Content-Type\", \"application/octet-stream;tt-data=a\")\n                    .header(\"Host\", \"log.snssdk.com\")\n                    .requestBody(s2)\n//                    .data(s2)\n                    .post().text();\n\n            if (doc != null) {\n               return doc;\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        finally {\n            XposedBridge.log(\"X-SS-STUB \" + stub);\n            XposedBridge.log(\"x_gon \" + x_gon);\n            XposedBridge.log(\"url \" + url);\n            XposedBridge.log(\"s2 \" + s2);\n            return null;\n        }\n    }\n\n    public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {\n        String msg = \"\";\n        Map<String, String> parms = session.getParms();\n        if (parms.get(\"url\") == null && parms.get(\"formdata\") == null) {\n            String msg2 = msg + \"<html><body><h1>Aweme Server</h1>\\n\";\n            msg = msg2 + \"<form action'?' 'method='get'>\\n  URL: <input type='text' name='url'><br>\\n  FORMDATA: <input type='text' name='formdata'><br>\\n  <input type='submit' value='提交'>\\n</form>\";\n        } else {\n            try {\n                String url = URLDecoder.decode(parms.get(\"url\"), \"utf-8\");\n                String formdata = URLDecoder.decode(parms.get(\"formdata\"), \"utf-8\");\n                msg = msg + get_device(url, formdata);\n            } catch (Exception e) {\n                XposedBridge.log(e.toString());\n            }\n        }\n        return newFixedLengthResponse(msg);\n    }\n}\n"
  },
  {
    "path": "第十一章：反爬虫补充/11.1 css动态字体反爬/选哪儿网动态字体.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport requests\nimport re\n\nheaders = {\n   'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',\n   'origin': 'https://www.xuannaer.com',\n   'referer': 'https://www.xuannaer.com/',\n   'sec-fetch-dest': 'font',\n   'sec-fetch-mode': 'cors',\n   'sec-fetch-site': 'same-site'\n}\n\ndoc = requests.get('https://www.xuannaer.com/zhaopaigua',headers=headers).text\n\n# 这个链接会更新，注意下\nwoff = re.findall('https://img2.xuanzhi.com/static/new/fonts/\\w{16}/font.woff\\?\\d{11}',doc,re.S)[0]\n\nprint(woff)\nwoff_bytes = requests.get(woff,headers=headers,allow_redirects=True)\nwith open('zhaopaigua.woff','wb') as f:\n   f.write(woff_bytes.content)\n\nfrom fontTools.ttLib import TTFont\nfont = TTFont('zhaopaigua.woff')\nfont.saveXML('zhaopaigua.xml')\n\nf = open('zhaopaigua.xml','r',encoding='utf-8')\ndocument = f.read()\nf.close()\ncmap = re.findall('<map code=\"(.*?)\" name=\"(.*?)\"/>',document,re.S)\nitem = {}\nfor node in cmap:\n   item[node[1]] = chr(eval(node[0]))\n\nGlyphID = re.findall('<GlyphID id=\"(\\d+)\" name=\"(.*?)\"/>',document,re.S)[1:]\n\n# 只要数字 取0-9 前10个元素\nresult = {}\nfor li in GlyphID[:10]:\n   num = int(li[0])-1   # 正确的数字\n   result[item[li[1]]]=num\nprint(result)"
  },
  {
    "path": "第十一章：反爬虫补充/11.2 tls指纹识别/aiohttp_ja3.py",
    "content": "import random\nimport ssl\n# aiohttp 修改 ja3\n\nclass DESAdapter():\n    def __init__(self):\n        self.ORIGIN_CIPHERS = ('ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES')\n\n    def __call__(self):\n        CIPHERS = self.ORIGIN_CIPHERS.split(':')\n        random.shuffle(CIPHERS)\n        CIPHERS = ':'.join(CIPHERS)\n        CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'\n        context = ssl.create_default_context()\n        context.set_ciphers(CIPHERS)\n        return context\n\nimport aiohttp,asyncio\nasync def main():\n    async with aiohttp.ClientSession() as session:\n        for req in range(5):\n            async with session.get(\"https://ja3er.com/json\",ssl=Adapter()) as res:\n                data = await res.json()\n                print(data)\n\nif __name__ == '__main__':\n    Adapter = DESAdapter()\n    m = asyncio.get_event_loop()\n    m.run_until_complete(main())"
  },
  {
    "path": "第十一章：反爬虫补充/11.2 tls指纹识别/requests_jar3.py",
    "content": "from requests.adapters import HTTPAdapter\nfrom urllib3.util.ssl_ import create_urllib3_context\nimport random,requests\n\nclass DESAdapter(HTTPAdapter):\n    def __init__(self, *args, **kwargs):\n        self.CIPHERS = self.get_ciphers()\n        super().__init__(*args, **kwargs)\n\n    def get_ciphers(self):\n        ORIGIN_CIPHERS = ('ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'\n                          'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES')\n        CIPHERS = ORIGIN_CIPHERS.split(':')\n        random.shuffle(CIPHERS)\n        CIPHERS = ':'.join(CIPHERS)\n        CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'\n        return CIPHERS\n\n    def init_poolmanager(self, *args, **kwargs):\n        context = create_urllib3_context(ciphers=self.CIPHERS)\n        kwargs['ssl_context'] = context\n        return super(DESAdapter, self).init_poolmanager(*args, **kwargs)\n\n\nif __name__ == '__main__':\n    sess = requests.Session()\n    while 1:\n        sess.mount('https://ja3er.com', DESAdapter())\n        res = sess.get('https://ja3er.com/json').json()\n        print(res)"
  },
  {
    "path": "第十一章：反爬虫补充/11.2 tls指纹识别/scrapy_Ja3_download.py",
    "content": "# -*- coding: utf-8 -*-\nfrom typing import Optional\nimport random\nimport ssl\nfrom twisted.internet.defer import Deferred\nfrom scrapy import signals\nfrom scrapy.http import Request, Response, Headers\nfrom scrapy.spiders import Spider\nfrom scrapy.settings import Settings\nfrom scrapy.crawler import Crawler\nfrom scrapy.utils.defer import deferred_from_coro, deferred_f_from_coro_f\nfrom scrapy.responsetypes import responsetypes\nfrom scrapy.core.downloader.handlers.http import HTTPDownloadHandler\nimport aiohttp\n\n\nORIGIN_CIPHERS = ('ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'\n                  'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES')\n\n\nclass SSLFactory:\n    def __init__(self):\n        self.ciphers = ORIGIN_CIPHERS.split(\":\")\n\n    def __call__(self) -> ssl.SSLContext:\n        random.shuffle(self.ciphers)\n        ciphers = \":\".join(self.ciphers)\n        ciphers = ciphers + \":!aNULL:!eNULL:!MD5\"\n\n        context = ssl.create_default_context()\n        context.set_ciphers(ciphers)\n        return context\n\n\nsslgen = SSLFactory()\n\n\nclass Ja3DownloadHandler(HTTPDownloadHandler):\n    def __init__(self, settings: Settings, crawler: Optional[Crawler] = None):\n        super().__init__(settings, crawler)\n        #super().__init__(settings)\n        self.client = None\n        crawler.signals.connect(self._engine_started, signals.engine_started)\n\n    @deferred_f_from_coro_f\n    async def _engine_started(self, signal, sender):\n        client = aiohttp.ClientSession()\n        self.client = await client.__aenter__()\n\n    def download_request(self, request: Request, spider: Spider) -> Deferred:\n        if request.meta.get(\"ja3\"): # 注意大小写\n            return deferred_from_coro(self._download_request(request, spider))\n        return super().download_request(request, spider)  # 普通下载\n\n    async def _download_request(self, request: Request, spider: Spider) -> Response:\n        \"\"\"aiohttp下载逻辑\"\"\"\n        async with self.client.request(request.method,\n                                       request.url,\n                                       data=request.body,\n                                       headers=request.headers.to_unicode_dict(),\n                                       cookies=request.cookies,\n                                       ssl=sslgen()) as response:\n            headers = Headers(response.headers)\n            body = await response.read()\n            respcls = responsetypes.from_args(headers=headers,\n                                              url=str(response.url),\n                                              body=body)\n            return respcls(url=str(response.url),\n                           status=response.status,\n                           headers=headers,\n                           body=body,\n                           flags=[\"ja3\"],\n                           request=request,\n                           protocol=response.version)\n\n    @deferred_f_from_coro_f\n    async def close(self):\n        await self.client.__aexit__(None, None, None)\n        await super().close()\n"
  },
  {
    "path": "第十一章：反爬虫补充/11.3 http2/scrapy_http2_download.py",
    "content": "# -*- coding: utf-8 -*-\nfrom typing import Optional\n\nfrom twisted.internet.defer import Deferred\n\nfrom scrapy import signals\nfrom scrapy.http import Request, Response, Headers\nfrom scrapy.spiders import Spider\nfrom scrapy.settings import Settings\nfrom scrapy.crawler import Crawler\nfrom scrapy.utils.defer import deferred_from_coro, deferred_f_from_coro_f\nfrom scrapy.responsetypes import responsetypes\nfrom scrapy.core.downloader.handlers.http import HTTPDownloadHandler\nimport httpx\n\n\nclass HttpxDownloadHandler(HTTPDownloadHandler):\n    def __init__(self, settings: Settings, crawler: Optional[Crawler] = None):\n        super().__init__(settings, crawler)\n        self.client = None\n        crawler.signals.connect(self._engine_started, signals.engine_started)\n\n    @deferred_f_from_coro_f\n    async def _engine_started(self, signal, sender):\n        client = httpx.AsyncClient(http2=True)\n        self.client = await client.__aenter__()\n\n    def download_request(self, request: Request, spider: Spider) -> Deferred:\n        if request.meta.get(\"h2\"):\n            return deferred_from_coro(self._download_request(request, spider))\n        return super().download_request(request, spider)  # 普通下载\n\n    async def _download_request(self, request: Request, spider: Spider) -> Response:\n        \"\"\"httpx下载逻辑\"\"\"\n        response = await self.client.request(request.method,\n                                             request.url,\n                                             content=request.body,\n                                             headers=request.headers.to_unicode_dict(),\n                                             cookies=request.cookies)\n        headers = Headers(response.headers)\n        respcls = responsetypes.from_args(headers=headers,\n                                          url=response.url,\n                                          body=response.content)\n        return respcls(url=str(response.url),\n                       status=response.status_code,\n                       headers=headers,\n                       body=response.content,\n                       flags=[\"httpx\"],\n                       request=request,\n                       protocol=response.http_version)\n\n    @deferred_f_from_coro_f\n    async def close(self):\n        await self.client.__aexit__()\n        await super().close()"
  },
  {
    "path": "第十章：验证码识别技术/10.2.1.1 邮箱滑块验证码.py",
    "content": "from selenium import webdriver\nfrom io import BytesIO\nimport cv2,numpy as np, random, requests, time\nfrom selenium.webdriver import ActionChains\nimport warnings\nfrom PIL import Image\nwarnings.filterwarnings(\"ignore\",category=DeprecationWarning)\n\n'''识别缺口位置、计算偏移值'''\nclass SlideCrack(object):\n    def __init__(self, gap, bg, out=None):\n        \"\"\"\n        init code\n        :param gap: 缺口图片\n        :param bg: 背景图片\n        :param out: 输出图片\n        \"\"\"\n        self.gap = gap\n        self.bg = bg\n        self.out = out\n\n    @staticmethod\n    def clear_white(img):\n        # 清除图片的空白区域，这里主要清除滑块的空白\n        img = cv2.imdecode(np.frombuffer(img,np.uint8), cv2.IMREAD_UNCHANGED)\n        rows, cols, channel = img.shape\n        min_x = 255\n        min_y = 255\n        max_x = 0\n        max_y = 0\n        for x in range(1, rows):\n            for y in range(1, cols):\n                t = set(img[x, y])\n                if len(t) >= 2:\n                    if x <= min_x:\n                        min_x = x\n                    elif x >= max_x:\n                        max_x = x\n\n                    if y <= min_y:\n                        min_y = y\n                    elif y >= max_y:\n                        max_y = y\n        img1 = img[min_x:max_x, min_y: max_y]\n        return img1\n\n    def template_match(self, tpl, target):\n        th, tw = tpl.shape[:2]\n        result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)\n        # 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置\n        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)\n        tl = max_loc\n        # br = (tl[0] + tw, tl[1] + th)\n        # 绘制矩形边框，将匹配区域标注出来\n        # target：目标图像\n        # tl：矩形定点\n        # br：矩形的宽高\n        # (0,0,255)：矩形边框颜色\n        # 1：矩形边框大小\n        # cv2.rectangle(target, tl, br, (0, 0, 255), 2)\n        # if self.out:\n        #     cv2.imwrite(self.out, target)\n        return tl[0]\n\n    @staticmethod\n    def image_edge_detection(img):\n        edges = cv2.Canny(img, 100, 200)\n        return edges\n\n    def discern(self):\n        img1 = self.clear_white(self.gap)\n        img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)\n        slide = self.image_edge_detection(img1)\n        back = cv2.cvtColor(np.asarray(Image.open(BytesIO(self.bg))), cv2.COLOR_RGB2GRAY)\n        back = self.image_edge_detection(back)\n        slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)\n        back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)\n        x = self.template_match(slide_pic, back_pic) # 滑块偏移值\n        # 输出横坐标, 即 滑块在图片上的位置\n        return x\n\n\ndef get_distance(gap, bg):\n    \"\"\"\n    计算滑动距离\n    \"\"\"\n    with open(gap,'rb') as f:\n        gap = f.read()\n    with open(bg,'rb') as f:\n        bg = f.read()\n    sc = SlideCrack(gap, bg, \"image/r.png\")\n    distance = int(sc.discern() // 2.4)\n    return distance\n\n\n'''模拟验证行为'''\ndef main():\n    driver = webdriver.Chrome(executable_path=r'chromedriver.exe')\n    driver.get('https://mail.qq.com')\n    time.sleep(1)\n    driver.switch_to.frame(\"login_frame\")\n    time.sleep(1)\n    driver.find_element_by_id('switcher_plogin').click()\n\n    username = '1234567{}@qq.com'.format(random.randint(0, 99))\n    driver.find_element_by_id(\"u\").send_keys(username)\n    driver.find_element_by_id(\"p\").send_keys('wwwwwwwww')\n    time.sleep(1)\n    driver.find_element_by_id(\"login_button\").click()\n    time.sleep(1)\n\n    driver.switch_to.frame(driver.find_element_by_id('tcaptcha_iframe'))\n    time.sleep(1)\n    src_big = driver.find_element_by_id('slideBg').get_attribute('src')\n    time.sleep(1)\n    src_small = driver.find_element_by_id('slideBlock').get_attribute('src')\n    img_big = requests.get(src_big).content\n    img_small = requests.get(src_small).content\n    with open('image/yanzhengtu.jpg', 'wb') as f:\n        f.write(img_big)\n    with open('image/huakuai.png', 'wb') as f:\n        f.write(img_small)\n\n    y = get_distance('image/huakuai.png','image/yanzhengtu.jpg')\n    time.sleep(2)\n    huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')\n    action = ActionChains(driver)\n    action.click_and_hold(huakuai).perform()\n    action.move_by_offset(y-30, 0).perform()\n    action.release(on_element=huakuai).perform()\n    time.sleep(3)\n    driver.close()\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "第十章：验证码识别技术/10.2.1.2 邮箱滑块验证码.py",
    "content": "# -*- coding: utf-8 -*-\nimport re\nfrom selenium import webdriver\nimport cv2, numpy as np, random, requests, time\nfrom selenium.webdriver import ActionChains\nimport warnings\nfrom PIL import Image\nwarnings.filterwarnings(\"ignore\",category=DeprecationWarning)\nfrom io import BytesIO\n\nhuakuai_path = 'huakuai.png'\nyanzheng_path = 'yanzhengtu.jpg'\n\n\n'''识别缺口位置、计算偏移值'''\nclass SlideCrack(object):\n    def __init__(self, gap, bg, out=None):\n        \"\"\"\n        init code\n        :param gap: 缺口图片\n        :param bg: 背景图片\n        :param out: 输出图片\n        \"\"\"\n        self.gap = gap\n        self.bg = bg\n        self.out = out\n\n    @staticmethod\n    def clear_white(img):\n        # 清除图片的空白区域，这里主要清除滑块的空白\n        img = cv2.imdecode(np.frombuffer(img,np.uint8), cv2.IMREAD_UNCHANGED)\n        rows, cols, channel = img.shape\n        min_x = 255\n        min_y = 255\n        max_x = 0\n        max_y = 0\n        for x in range(1, rows):\n            for y in range(1, cols):\n                t = set(img[x, y])\n                if len(t) >= 2:\n                    if x <= min_x:\n                        min_x = x\n                    elif x >= max_x:\n                        max_x = x\n\n                    if y <= min_y:\n                        min_y = y\n                    elif y >= max_y:\n                        max_y = y\n        img1 = img[min_x:max_x, min_y: max_y]\n        return img1\n\n    def template_match(self, tpl, target):\n        th, tw = tpl.shape[:2]\n        result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)\n        # 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置\n        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)\n        tl = max_loc\n        # br = (tl[0] + tw, tl[1] + th)\n        # 绘制矩形边框，将匹配区域标注出来\n        # target：目标图像\n        # tl：矩形定点\n        # br：矩形的宽高\n        # (0,0,255)：矩形边框颜色\n        # 1：矩形边框大小\n        # cv2.rectangle(target, tl, br, (0, 0, 255), 2)\n        # if self.out:\n        #     cv2.imwrite(self.out, target)\n        return tl[0]\n\n    @staticmethod\n    def image_edge_detection(img):\n        edges = cv2.Canny(img, 100, 200)\n        return edges\n\n    def discern(self):\n        img1 = self.clear_white(self.gap)\n        img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)\n        slide = self.image_edge_detection(img1)\n        back = cv2.cvtColor(np.asarray(Image.open(BytesIO(self.bg))), cv2.COLOR_RGB2GRAY)\n        back = self.image_edge_detection(back)\n        slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)\n        back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)\n        x = self.template_match(slide_pic, back_pic) # 滑块偏移值\n        # 输出横坐标, 即 滑块在图片上的位置\n        return x\n\n\ndef get_distance(gap, bg):\n    \"\"\"\n    计算滑动距离\n    \"\"\"\n    with open(gap,'rb') as f:\n        gap = f.read()\n    with open(bg,'rb') as f:\n        bg = f.read()\n    sc = SlideCrack(gap, bg, \"33.png\")\n    distance = int(sc.discern() // 2.4)\n    return distance\n\n\n\n'''selenium模拟登陆 获取滑块'''\ndef main():\n    driver = webdriver.Chrome(executable_path= r'chromedriver.exe')\n    driver.get('https://mail.qq.com')\n    time.sleep(2)\n    driver.switch_to.frame(\"login_frame\")\n    try:\n        driver.find_element_by_id('switcher_plogin').click()\n    except:\n        pass\n    username = '1234567{}@qq.com'.format(random.randint(0, 99))\n    driver.find_element_by_id(\"u\").send_keys(username)\n    driver.find_element_by_id(\"p\").send_keys('wwwwwwwww')\n    time.sleep(2)\n    driver.find_element_by_id(\"login_button\").click()\n    time.sleep(2)\n    frame = driver.find_element_by_id('tcaptcha_iframe_dy')\n    driver.switch_to.frame(frame)\n    time.sleep(1)\n    if driver.find_element_by_id('slideBgWrap'):\n        time.sleep(0.5)\n    src_big = driver.find_element_by_id('slideBg').get_attribute('style')\n    src_big = 'https://t.captcha.qq.com'+''.join(re.findall('(/cap_union_new_getcapbysig\\?.*?)\"\\);',src_big,re.S))\n\n    src_small = driver.find_element_by_xpath('//*[@id=\"tcOperation\"]/div[8]').get_attribute('style')\n    src_small = 'https://t.captcha.qq.com'+''.join(re.findall('(/cap_union_new_getcapbysig\\?.*?)\"\\);',src_small,re.S))\n    img_big = requests.get(src_big).content\n    img_small = requests.get(src_small).content\n    with open(yanzheng_path, 'wb') as f:\n        f.write(img_big)\n    with open(huakuai_path, 'wb') as f:\n        f.write(img_small)\n\n    # 切割图片 提取滑块\n    from PIL import Image\n    img = Image.open(huakuai_path)\n    region = img.crop((162, 514, 250, 588))  ## 0,0表示要裁剪的位置的左上角坐标，50,50表示右下角。\n    region.save(huakuai_path)\n    y = get_distance(huakuai_path,yanzheng_path)\n\n    huakuai = driver.find_element_by_xpath('//*[@id=\"tcOperation\"]/div[6]')\n    action = ActionChains(driver)\n    action.click_and_hold(huakuai).perform()\n\n    action.move_by_offset(y-30, 0).perform()\n    action.release(on_element=huakuai).perform()\n    time.sleep(3)\n    driver.close()\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "第十章：验证码识别技术/10.2.2 数美滑块验证码.py",
    "content": "\"\"\"\n数美滑块验证码验证\n\"\"\"\n\nimport base64\nimport json\nimport random\nimport re\nimport time\nfrom io import BytesIO\nimport cv2\nimport numpy as np\nimport requests\nfrom pyDes import des, ECB\n\nCAPTCHA_DISPLAY_WIDTH = 310\nCAPTCHA_DISPLAY_HEIGHT = 155\n\np = {}\n\n\ndef pad(b):\n    \"\"\"\n    块填充\n    \"\"\"\n    block_size = 8\n    while len(b) % block_size:\n        b += b'\\0'\n    return b\n\n\ndef split_args(s):\n    \"\"\"\n    分割js参数\n    \"\"\"\n    r = []\n    a = ''\n    i = 0\n    while i < len(s):\n        c = s[i]\n        if c == ',' and (a[0] != '\\'' or len(a) >= 2 and a[-1] == '\\''):\n            r.append(a)\n            a = ''\n        elif c:\n            a += c\n        i += 1\n    r.append(a)\n    return r\n\n\ndef find_arg_names(script):\n    \"\"\"\n    通过js解析出参数名\n    \"\"\"\n    names = {}\n    a = []\n    for r in re.findall(r'function\\((.*?)\\)', script):\n        if len(r.split(',')) > 100:\n            a = split_args(r)\n            break\n\n    r = re.search(r';\\)(.*?)\\(}', script[::-1]).group(1)\n    v = split_args(r[::-1])\n\n    d = r'{%s}' % ''.join([((',' if i else '') + '\\'k{}\\':([_x0-9a-z]*)'.format(i + 1)) for i in range(15)])\n\n    k = []\n    r = re.search(d, script)\n    for i in range(15):\n        k.append(r.group(i + 1))\n\n    n = int(v[a.index(re.search(r'arguments;.*?,(.*?)\\);', script).group(1))], base=16)\n\n    for i in range(n // 2):\n        v[i], v[n - 1 - i] = v[n - 1 - i], v[i]\n\n    for i, b in enumerate(k):\n        t = v[a.index(b)].strip('\\'')\n        names['k{}'.format(i + 1)] = t if len(t) > 2 else t[::-1]\n\n    return names\n\n\ndef get_encrypt_content(message, key, flag):\n    \"\"\"\n    接口参数的加密、解密\n    \"\"\"\n    des_obj = des(key.encode(), mode=ECB)\n    if flag:\n        content = pad(str(message).replace(' ', '').encode())\n        return base64.b64encode(des_obj.encrypt(content)).decode('utf-8')\n    else:\n        return des_obj.decrypt(base64.b64decode(message)).decode('utf-8')\n\n\ndef get_random_ge(distance):\n    \"\"\"\n    生成随机的轨迹\n    \"\"\"\n    ge = []\n\n    y = 0\n    v = 0\n    t = 1\n    current = 0\n    mid = distance * 3 / 4\n    exceed = 20\n    z = t\n\n    ge.append([0, 0, 1])\n\n    while current < (distance + exceed):\n        if current < mid / 2:\n            a = 15\n        elif current < mid:\n            a = 20\n        else:\n            a = -30\n        a /= 2\n        v0 = v\n        s = v0 * t + 0.5 * a * (t * t)\n        current += int(s)\n        v = v0 + a * t\n\n        y += random.randint(-5, 5)\n        z += 100 + random.randint(0, 10)\n\n        ge.append([min(current, (distance + exceed)), y, z])\n\n    while exceed > 0:\n        exceed -= random.randint(0, 5)\n        y += random.randint(-5, 5)\n        z += 100 + random.randint(0, 10)\n        ge.append([min(current, (distance + exceed)), y, z])\n\n    return ge\n\n\ndef make_mouse_action_args(distance):\n    \"\"\"\n    生成鼠标行为相关的参数\n    \"\"\"\n    ge = get_random_ge(distance)\n    args = {\n        p['k']['k5']: round(distance / CAPTCHA_DISPLAY_WIDTH, 2),\n        p['k']['k6']: get_random_ge(distance),\n        p['k']['k7']: ge[-1][-1] + random.randint(0, 100),\n        p['k']['k8']: CAPTCHA_DISPLAY_WIDTH,\n        p['k']['k9']: CAPTCHA_DISPLAY_HEIGHT,\n        p['k']['k11']: 1,\n        p['k']['k12']: 0,\n        p['k']['k13']: -1,\n        'act.os': 'android'\n    }\n    return args\n\n\ndef get_distance(fg, bg):\n    \"\"\"\n    计算滑动距离\n    \"\"\"\n    target = cv2.imdecode(np.asarray(bytearray(fg.read()), dtype=np.uint8), 0)\n    template = cv2.imdecode(np.asarray(bytearray(bg.read()), dtype=np.uint8), 0)\n    result = cv2.matchTemplate(target, template, cv2.TM_CCORR_NORMED)\n    _, distance = np.unravel_index(result.argmax(), result.shape)\n    return distance\n\n\ndef update_protocol(protocol_num, js_uri):\n    \"\"\"\n    更新协议\n    \"\"\"\n    global p\n    r = requests.get(js_uri, verify=False)\n    names = find_arg_names(r.text)\n    p = {\n        'i': protocol_num,\n        'k': names\n    }\n\n\ndef conf_captcha(organization):\n    \"\"\"\n    获取验证码设置\n    \"\"\"\n    url = 'https://captcha.fengkongcloud.com/ca/v1/conf'\n\n    args = {\n        'organization': organization,\n        'model': 'slide',\n        'sdkver': '1.1.3',\n        'rversion': '1.0.3',\n        'appId': 'default',\n        'lang': 'zh-cn',\n        'channel': 'YingYongBao',\n        'callback': 'sm_{}'.format(int(time.time() * 1000))\n    }\n\n    r = requests.get(url, params=args, verify=False)\n    resp = json.loads(re.search(r'{}\\((.*)\\)'.format(args['callback']), r.text).group(1))\n    return resp\n\n\ndef register_captcha(organization):\n    \"\"\"\n    注册验证码\n    \"\"\"\n    url = 'https://captcha.fengkongcloud.com/ca/v1/register'\n\n    args = {\n        'organization': organization,\n        'channel': 'YingYongBao',\n        'lang': 'zh-cn',\n        'model': 'slide',\n        'appId': 'default',\n        'sdkver': '1.1.3',\n        'data': '{}',\n        'rversion': '1.0.3',\n        'callback': 'sm_{}'.format(int(time.time() * 1000))\n    }\n\n    r = requests.get(url, params=args, verify=False)\n    resp = json.loads(re.search(r'{}\\((.*)\\)'.format(args['callback']), r.text).group(1))\n\n    return resp\n\n\ndef verify_captcha(organization, rid, key, distance):\n    \"\"\"\n    提交验证\n    \"\"\"\n    url = 'https://captcha.fengkongcloud.com/ca/v2/fverify'\n    args = {\n        'organization': organization,\n        p['k']['k1']: 'default',\n        p['k']['k2']: 'YingYongBao',\n        p['k']['k3']: 'zh-cn',\n        'rid': rid,\n        'rversion': '1.0.3',\n        'sdkver': '1.1.3',\n        'protocol': p['i'],\n        'ostype': 'web',\n        'callback': 'sm_{}'.format(int(time.time() * 1000))\n    }\n\n    args.update(make_mouse_action_args(distance))\n\n    key = get_encrypt_content(key, 'sshummei', 0)\n\n    for k, v in args.items():\n        if len(k) == 2:\n            args[k] = get_encrypt_content(v, key, 1)\n    print(args)\n    r = requests.get(url, params=args, verify=False)\n    resp = json.loads(re.search(r'{}\\((.*)\\)'.format(args['callback']), r.text).group(1))\n\n    return resp\n\n\ndef get_verify(organization):\n    \"\"\"\n    进行验证\n    \"\"\"\n    resp = conf_captcha(organization)\n    protocol_num = re.search(r'build/v1.0.3-(.*?)/captcha-sdk.min.js', resp['detail']['js']).group(1)\n\n    if not p.get('id') or protocol_num != p['i']:\n        update_protocol(protocol_num, ''.join(['https://', resp['detail']['domains'][0], resp['detail']['js']]))\n\n    resp = register_captcha(organization)\n\n    rid = resp['detail']['rid']\n    key = resp['detail']['k']\n\n    domain = resp['detail']['domains'][0]\n    fg_uri = resp['detail']['fg']\n    bg_uri = resp['detail']['bg']\n\n    fg_url = ''.join(['http://', domain, fg_uri])\n    bg_url = ''.join(['http://', domain, bg_uri])\n\n    r = requests.get(fg_url, verify=False)\n    fg = BytesIO(r.content)\n\n    r = requests.get(bg_url, verify=False)\n    bg = BytesIO(r.content)\n\n    distance = get_distance(fg, bg)\n    print(distance)\n    r = verify_captcha(organization, rid, key, int(distance / 600 * 310))\n\n    return rid, r\n\n\ndef test():\n    # 表示小红书\n    organization = 'eR46sBuqF0fdw7KWFLYa'\n\n    # rid是验证过程中响应的标示，r是最后提交验证返回的响应\n    rid, r = get_verify(organization)\n    print(rid, r)\n\n    # riskLevel为PASS说明验证通过\n    if r['riskLevel'] == 'PASS':\n        # 这里需要提交rid\n        # 具体可抓包查看，接口：/api/sns/v1/system_service/slide_captcha_check\n        pass\n\n\nif __name__ == '__main__':\n    test()\n\n"
  },
  {
    "path": "第四章：自动化工具的应用/4.2.4 Pyppeteer拦截器/test.js",
    "content": "var request = require('request');\nconst puppeteer = require(\"puppeteer-extra\");\nconst StealthPlugin = require(\"puppeteer-extra-plugin-stealth\");\npuppeteer.use(StealthPlugin());\n\nvar apage;\nvar message_js = \"js content\";\npuppeteer.launch({\n     userDataDir: \"data\",\n     ignoreDefaultArgs: [\"--enable-automation\"],\n     headless: false,\n}).then(browser => {\n    browser.newPage().then((page) => {\n        apage = page;\n        page.setRequestInterception(true).then(() => {\n            page.on('request',async (req) => {\n                if (req.url().indexOf(\"https://www.lx.js\") != -1) {\n                    req.respond({\n                            status:200,\n                            headers:{},\n                            body:message_js\n                        })\n                }\n                else if (req.url().indexOf(\"https://www.lx.png\") != -1) {\n                    req.abort()\n                }\n                page.on('response', async response => {\n                    if (response.url().indexOf(\"https://www.lx.json/\") != -1) {\n                        let message = response.text();\n                            message.then(res =>{\n                                   console.log(res)\n                            })\n                            .catch(err =>{\n                                console.log(err)\n                            })\n                    }\n                })\n                req.continue();\n          });\n        })\n        page.goto(\"https://www.lx.com\")\n\n    }, {waitUntil: \"networkidle0\"}).then(() => {\n    })\n});"
  },
  {
    "path": "第四章：自动化工具的应用/4.2.4 Pyppeteer拦截器/test.py",
    "content": "import asyncio\nfrom pyppeteer import launch\n\nasync def main():\n    browser = await launch()\n    page = await browser.newPage()\n    # 设置 request 拦截器\n    await page.setRequestInterception(True)\n    page.on('request', lambda req: asyncio.ensure_future(intercept_request(req)))\n    # 设置 response 拦截器\n    page.on('response', lambda rep: asyncio.ensure_future(intercept_response(rep)))\n    await page.goto('https://www.baidu.com')\n    await browser.close()\n\n# 请求拦截器\nasync def intercept_request(Request):\n    if Request.url=='':\n        # 跳转url\n        await Request.continue_({\"url\": \"\"})\n    elif Request.url =='':\n        # 停止请求  \n        await Request.abort()\n    elif Request.url =='':\n        # 用给定的响应内容完成请求\n        await Request.respond({\"status\":\"\",\"body\":\"\"})\n    else:\n        # 保持请求\n        await Request.continue_()\n\n# 响应拦截器\nasync def intercept_response(Response):\n    print(Response.url)\n    if Response.url==\"https://www.baidu.com\":\n        response = await Response.text()\n        ...\n\nasyncio.get_event_loop().run_until_complete(main())"
  },
  {
    "path": "第四章：自动化工具的应用/4.3.5 cefpython3爬虫实战/cefpython_demo.py",
    "content": "import sys\nimport threading\nfrom cefpython3 import cefpython as cef\n\n# 代码转自 https://blog.csdn.net/jianshen_5465/article/details/118699364\n# 代码转自 https://segmentfault.com/a/1190000021672729?utm_source=tag-newest\n\nsys.excepthook = cef.ExceptHook\n\nclass ClientHandler(object):\n    r\"\"\" 自定义客户端 Handler \"\"\"\n    def __init__(self, chromeObject):\n        self.chrome = chromeObject\n\n    def GetViewRect(self, rect_out, **kwargs):\n        r\"\"\" 渲染接口 \"\"\"\n        # [x, y, width, height]\n        rect_out.extend([0, 0, self.chrome.width, self.chrome.height])\n        return True\n\n    def OnConsoleMessage(self, browser, message, **kwargs):\n        r\"\"\" 浏览器控制台接口 \"\"\"\n        self.chrome.console.append(message)\n\n    def OnLoadError(self, browser, frame, error_code, failed_url, **_):\n        self.chrome.ready = error_code\n        self.chrome._getReadyLock.acquire()\n        self.chrome._getReadyLock.notify()\n        self.chrome._getReadyLock.release()\n\n    def OnLoadingStateChange(self, browser, is_loading, **kwargs):\n        r\"\"\" 加载接口，当浏览器加载状态变化时调用 \"\"\"\n        if is_loading:\n            # 加载中\n            self.chrome.ready = False\n        else:\n            # 加载完成\n            self.chrome.ready = True\n            self.chrome._getReadyLock.acquire()\n            self.chrome._getReadyLock.notify()\n            self.chrome._getReadyLock.release()\n\n\nclass Client(object):\n    def __init__(self, width=1920, height=1080, headless=False):\n        self.width = width\n        self.height = height\n        self.headless = headless\n        self.console = []\n        self.browser = None\n        self.source = None\n        self.domArray = None\n        self.windowParams = None\n        self.ready = True\n        self._getSourceLock = threading.Condition()\n        self._getDOMLock = threading.Condition()\n        self._getReadyLock = threading.Condition()\n        self._handler = ClientHandler(self)\n\n        settings,switches = {},{}\n        if self.headless:\n            settings['windowless_rendering_enabled'] = True\n        cef.Initialize(settings=settings, switches=switches)\n\n    def __getattr__(self, name):\n        r\"\"\" 将所有未知的属性和方法传递给 CEF 浏览器 \"\"\"\n        return getattr(self.browser, name)\n\n    def getBrowser(self):\n        if self.browser:\n            return self.browser\n        # 创建浏览器实例\n        if self.headless:\n            parent_handle = 0\n            wininfo = cef.WindowInfo()\n            wininfo.SetAsOffscreen(parent_handle)\n            self.browser = cef.CreateBrowserSync(window_info=wininfo)\n        else:\n            self.browser = cef.CreateBrowserSync()\n\n        self.browser.SetClientHandler(self._handler)\n        self.browser.SendFocusEvent(True)\n        self.browser.WasResized()  # 在 headless 模式下应至少调用一次这个方法\n\n        return self\n\n    def LoadUrl(self, url, synchronous=False):\n        r\"\"\" 将 URL 传递给浏览器 \"\"\"\n        self.ready = False\n        self.browser.LoadUrl(url)\n        if synchronous:  # 同步方式\n            self._getReadyLock.acquire()\n            if not self.ready:\n                self._getReadyLock.wait()\n            self._getReadyLock.release()\n\n    def getSource(self, synchronous=False):\n        r\"\"\" 返回 main frame 的 html 源码，  \"\"\"\n        self.source = None\n        self.browser.GetMainFrame().GetSource(self)\n\n        if synchronous:\n            self._getSourceLock.acquire()\n            if not self.source:\n                # 等待 Visit 函数准备好 source 的通知\n                self._getSourceLock.wait()\n            self._getSourceLock.release()\n        return self.source\n\n    def Visit(self, value):\n        r\"StringVisitor 接口\"\n        self.source = value\n        self._getSourceLock.acquire()\n        self._getSourceLock.notify()\n        self._getSourceLock.release()\n\ndef BrowserThread(browser):\n    r\"\"\" 线程入口函数 \"\"\"\n    browser.ready = False\n    browser.LoadUrl(url, True) # True 为同步调用\n    with open('source.html', mode='w', encoding='utf8') as srcfp:\n        source = browser.getSource(True) # 同步获取\n        assert(source)\n        srcfp.write(source)\n    browser.CloseBrowser()\n\n\nif __name__ == '__main__':\n    url = 'http://www.baidu.com'\n    browser = Client(width=640, height=480).getBrowser()\n    browserThread = threading.Thread(target=BrowserThread, args=(browser,))\n    browserThread.start()\n    cef.MessageLoop()\n    browserThread.join()\n    browser = None\n    cef.Shutdown()\n"
  },
  {
    "path": "第四章：自动化工具的应用/4.7.3 autojs指数查询案例/main.js",
    "content": "// toast('Hello, Auto.js');\napp.launchApp('微信');\n\n//返回到首页\nfunction goToHomePage(){    \n    let k = 0;\n    while(k < 30){\n        k = k + 1;        \n        if(text(\"微信\").depth(10).exists()){\n            //要支持的动作\n            toast('已到首页');  \n            break;\n        }else{\n            back();\n            sleep(1000*0.2);\n        }\n    }\n}\n\n// goToHomePage()\n// exit();\n\n//前往公众号搜索\nfunction goToSearchPage(){\n    //搜索按钮\n    var it = className(\"android.widget.ImageView\").depth(17).findOne();\n    var b = it.bounds();\n    click(b.centerX(), b.centerY());\n    sleep(500);\n    text('公众号').click();\n    sleep(1000);    \n    text('公众号').click();\n}\n\n//获取界面上的搜索结果\nfunction getSearchResult(saveArray){\n    sleep(500);\n    let tList = depth(18).find();//从第 18 级开始取元素\n\n    for(let i=0;tList && i<tList.length;i++){\n        let item = {title:'',desc:'',idx:0};\n        if(tList[i].childCount() > 0){\n            let indexInParent = tList[i].indexInParent();// 搜索出来第几个  索引\n            // toastLog('索引:' + indexInParent);sleep(1000*0.5);\n\n            let cell = tList[i].child(0);// 19\n            if(cell && cell.childCount() > 2){\n                cell = cell.child(2);//20\n                let title = '';\n                let desc = '';\n                if(cell.childCount() >= 3){\n                    title = cell.child(1).text();//21\n                    desc = cell.child(2).text();//21    \n                }else{\n                    title = cell.child(0).text();//21\n                    desc = cell.child(1).text();//21    \n                }\n                // toastLog(title);    \n                // sleep(1000*2);\n                // toastLog(desc);    \n                // sleep(1000*2);\n\n                item.idx = indexInParent;\n                item.title = title;\n                item.desc = desc;\n\n            }else if(cell && cell.childCount() > 1){\n                cell = cell.child(1);//20\n                let title = cell.child(0).text();//21\n                let desc = cell.child(1).text();//21\n                // toastLog(title);    \n                // sleep(1000*2);\n                // toastLog(desc);    \n                // sleep(1000*2);\n\n                item.idx = indexInParent;\n                item.title = title;\n                item.desc = desc;\n\n            }else{\n                // toastLog(cell);\n            }            \n        }\n\n        //往数组里面添加索引结果\n        if(item.idx != 0){\n            if(saveArray.length > 0){\n                if(item.idx > saveArray[saveArray.length - 1].idx){\n                    saveArray.push(item);\n                }\n            }else{\n                saveArray.push(item);\n            }\n        }\n\n    }\n    \n}\n\n//滑动搜索结果\nfunction swapSearchResult(){\n    scrollDown();\n}\n\nfunction searchForKey(tkey){\n    sleep(1000*1.5);\n    //设置输入框里面的文字\n    id('m7').findOne().setText(tkey);\n\n    //点击键盘上面的'搜索'按钮\n    click(device.width - 8, device.height - 8);\n\n    var saveArray = [];\n    var rounds = 200;\n    for(var i=0;i<rounds;i++){\n        try {\n            getSearchResult(saveArray);            \n        } catch (error) {\n            console.log('查行记录异常');\n            console.error(error);\n        }\n        try {\n            swapSearchResult();         \n        } catch (error) {\n            console.log('翻页异常');\n            // console.error(error);\n        }\n        sleep(1000*0.2);\n    //  log('testmemem');\n        if(text(\"没有更多的搜索结果\").exists()){\n            toast('搜索结束');        \n            console.log('查找结果', JSON.stringify(saveArray));\n            break;\n        }\n    }\n    console.log('查找结果', JSON.stringify(saveArray));\n    toast(JSON.stringify(saveArray));\n\n    //TODO. 保存本地  或者 保存到云服务器\n}\n\n//跳转到指数页面 \nfunction goToZhiShuPage(){\n    var it = className(\"android.widget.ImageView\").depth(17).findOne();\n    var b = it.bounds();\n    click(b.centerX(), b.centerY());\n    sleep(1500);\n\n    //跳转到 微信指数 小程序    \n    id('m7').findOne().setText('微信指数');\n    sleep(1000);\n\n    var wxzs = text('微信指数').depth(14).findOne();\n    var bb = wxzs.bounds();\n    click(bb.centerX(), bb.centerY());\n}\n\n//根据关键字查 指数\nfunction getZhiShuForKey(tkey){\n    sleep(1000*1.5);\n    var wxzs = text('搜索').findOne();\n    var bb = wxzs.bounds();\n    click(bb.centerX(), bb.centerY());\n    \n    className('android.widget.EditText').findOne().setText(tkey);\n    sleep(1000);\n\n    //点击键盘上面的'搜索'按钮\n    click(device.width - 16, device.height - 16);\n    sleep(1000*2);\n\n    //获取关键字和指数\n    let findData = {keyword:tkey, //关键字\n        dataKey:'',//时间戳，显示在界面上的时间\n         zhishu:''//指数值\n        };\n\n    //TODO. 可以通过 xxx日统计 的正则表达式来搜索到具备该文本的控件，然后通过它的上级的上级的下级的下级，这样去查找指数\n    try {\n        //此处没调通\n        findData.dataKey = className('android.view.View').findOne().text();\n    } catch (error) {\n        toast(error);\n        exit();\n    }\n\n    // try {\n    //     findData.zhishu = className('android.view.View').depth(22).indexInParent(1).findOne().text();\n    // } catch (error) {\n    //     toast(error);\n    //     exit();\n    // }    \n\n    toast('日期' + findData.dataKey + ', 指数' + findData.zhishu);\n\n    //TODO. 保存本地  或者 保存到云服务器\n}\n\n\n// ---------  查找关键字逻辑 -------\nif(1){\n    goToHomePage();\n    goToSearchPage();\n    searchForKey('起名');\n    sleep(1000);\n    goToHomePage();    \n}\n\n// ---------  查找小程序“微信指数”逻辑 ------\n\nif(1){\n    goToHomePage();\n    goToZhiShuPage();\n    getZhiShuForKey('起名');\n    sleep(1000);\n    // goToHomePage();\n\n}"
  },
  {
    "path": "第四章：自动化工具的应用/4.7.3 autojs指数查询案例/test.js",
    "content": "app.launchApp('微信');\n\n//跳转到首页\nfunction goToHomePage(){\n    let k = 0;\n    while(k < 30){\n        k = k + 1;\n        if(text(\"微信\").depth(10).exists()){\n            toast('到首页');\n            break;\n        }else{\n            back();\n            sleep(1000*0.2);\n        }\n    }\n}\n\n//跳转到指数页面\nfunction goToZhiShuPage(){\n    var it = className(\"android.widget.ImageView\").depth(17).findOne();\n    var b = it.bounds();\n    click(b.centerX(), b.centerY());\n    sleep(1500);\n\n    //跳转到 微信指数 小程序\n    id('m7').findOne().setText('微信指数');\n    sleep(1000);\n\n    var wxzs = text('微信指数').depth(14).findOne();\n    var bb = wxzs.bounds();\n    click(bb.centerX(), bb.centerY());\n}\n\n//根据关键字查询\nfunction getZhiShuForKey(tkey){\n    sleep(1000*1.5);\n    var wxzs = text('搜索').findOne();\n    var bb = wxzs.bounds();\n    click(bb.centerX(), bb.centerY());\n\n    className('android.widget.EditText').findOne().setText(tkey);\n    sleep(1000);\n\n    //点击键盘上面的'搜索'按钮\n    click(device.width - 16, device.height - 16);\n    sleep(1000*2);\n\n    //获取关键字和指数\n    let findData = {keyword:tkey, //关键字\n        dataKey:'',     //时间戳，显示在界面上的时间\n         zhishu:''      //指数值\n        };\n\n    try {\n        findData.dataKey = className('android.view.View').findOne().text();\n    } catch (error) {\n        toast(error);\n        exit();\n    }\n    toast('日期' + findData.dataKey + ', 指数' + findData.zhishu);\n}\n\n// “微信指数”\nif(1){\n    goToHomePage();\n    goToZhiShuPage();\n    getZhiShuForKey('Lx');\n    sleep(1000);\n}"
  },
  {
    "path": "附录(一些经验)/readme.md",
    "content": "我觉得附录才是对大家帮助最大的东西，可惜出版社开源节流，没有印在书中。\n\n因为这里面是我自身经验的总结，比如检索技巧和面试之谈。\n\n如果你看到了这里，一定不要错过！\n\n"
  },
  {
    "path": "附录(一些经验)/关于AI逆向.md",
    "content": "当AI从辅助工具升级为逆向执行者，以后可能无需人工编写代码、分析汇编，即可完成静态解析+动态调试+算法复现全流程。\n\n我们作为指挥者把控方向，要有不被AI误导的能力。\n\n\n# AI逆向JS-动态前瞻\n\n## Js-reverse-mcp\n\n[https://github.com/zhizhuodemao/js-reverse-mcp](https://github.com/zhizhuodemao/js-reverse-mcp)\n\n[https://blog.csdn.net/2503\\_90751789/article/details/156801378](https://blog.csdn.net/2503_90751789/article/details/156801378)\n\n一个改进自chrome-devtools-mcp，专属于js逆向的 MCP 服务器，让 AI 助手（如 Claude、Cursor、Copilot）能够断点调试和分析网页中的 JavaScript 代码。\n\n**功能特点**\n\n*   脚本分析: 列出所有加载的 JS 脚本，搜索代码，获取源码\n    \n*   断点调试: 设置/移除断点，支持条件断点，支持在压缩代码中精确定位\n    \n*   函数追踪: Hook 任意函数（包括模块内部函数），监控调用和返回值\n    \n*   执行控制: 暂停/恢复执行，单步调试（step over/into/out）\n    \n*   运行时检查: 在断点处求值表达式，检查作用域变量\n    \n*   网络分析: 查看请求发起的调用栈，设置 XHR 断点\n    \n*   事件监控: 监控 DOM 事件，检查存储数据\n    \n\n## AI\\_JS\\_DEBUGGER\n\n[https://github.com/Valerian7/AI\\_JS\\_DEBUGGER](https://github.com/Valerian7/AI_JS_DEBUGGER)\n\n[https://www.bilibili.com/video/BV1kPXGYVEkj](https://www.bilibili.com/video/BV1kPXGYVEkj)\n\n项目是基于Chrome开发者协议(CDP)的AI自动化JavaScript逆向分析工具，通过AI自动调试前端JS，自动分析加解密算法、密钥等，自动生成分析报告以及mitmproxy脚本。\n\n**功能特点**\n\n*   支持固定js文件断点、XHR请求断点\n    \n*   XHR回溯，XHR模式下自动回溯顶层调用堆栈并自动断点\n    \n*   根据调用堆栈、js片段、作用域等断点调试信息自动调试\n    \n*   使用js hook获取AES、RSA等常见加密密钥/密文/明文\n    \n*   自动分析加解密算法、密钥、生成密钥方式等\n    \n*   生成分析报告以及mitmproxy脚本\n    \n*   web界面操作，多个自定义参数配置，简单高效\n\n\n# AI逆向app-动态前瞻\n## 关键工具（MCP生态工具链）\n- 静态分析：APKLab（反编译 APK）、IDA-MCP（SO 层代码解析）；\n- 动态调试：ADB-MCP（安装 APK 到设备）、FRIDA-MCP（Hook 关键函数）；\n- AI 能力：自动识别调用链、解析加密逻辑、生成 Hook 脚本与请求复现代码，支持多 AI 交叉验证（如 CLAUDE CODE）。\n\n\n## 执行流程\n- 抓包与准备：获取接口参数，如app_sign为核心分析目标；\n\n- Java 层调用链解析：AI 自动定位签名生成的业务通路 ——如从A.process()构造请求头，到A.appSign()发起调用，最终通过 JNI 反射调用A.gNative()（native方法）；\n\n- So 层算法拆解：使用 IDA-MCP 分析libA.so，AI 识别关键函数（如Java_gNative），明确签名“密钥 + 盐 + 参数处理 + 算法”逻辑；\n\n- 动态 Hook 验证：通过 FRIDA-MCP 注入脚本，获取运行时关键数据（如未登录态密钥、盐前缀），验证静态分析的不确定性（如参数排序、URL 参与形式）；\n\n- 算法复现与请求验证：AI 根据分析结果生成 Python 脚本，实现app_sign签名的自动化生成，复现接口请求并验证通过。\n"
  },
  {
    "path": "附录(一些经验)/检索技巧.md",
    "content": "## 爬虫工程师应该掌握的检索技巧\n\n一般来说我们要做的事情前人已经完成过，其实不需要自己动手去逆向，找到前人的代码合理更改能极大程度地提高工作效率，我分享一下互联网中的信息检索技巧。\n\n![image](https://user-images.githubusercontent.com/45314745/171538214-e80b534a-bbaa-4c4a-a1cd-3cf47231b8c2.png)\n\n我在搜代码的时候，一般先会搜项目名，比如xx爬虫，找不到的话就会根据加密参数的名称、接口的关键词到Code中去搜。\n\n比如某个参数叫做x-gorgon，就可以在Code中搜索关键词x-gorgon或者xgorgon，然后选择你想看的编程语言，再Sort中选择Recently indexed，按最近更新来检索。\n\n比如接口的链接中有一个关键词UserByScreenName，那就搜索/UserByScreenName，然后选择语言和排序。\n\n![image](https://user-images.githubusercontent.com/45314745/171538280-430613f5-8e2c-498e-b9e0-60cef7c76c7e.png)\n\n这样检索大概率能找到前人已经完成的代码，你在此基础上开发能节省非常多的时间，同时多阅读别人的代码能让自己的编码技术提升得很快。\n\n当然也不是要大家无脑检索，花十多分钟找不到的话就自己动手开发吧。\n\n另外也不要过度依赖开源库，尽管能快速完成任务很好，但是找到了代码后自己跟着流程复现一遍才是最重要的。\n\n\n## Csdn的检索技巧\nCsdn也是一个非常庞大的代码平台，我们需要合理的检索才能找到自己想要的东西。\n\n现在搜索框中有高级检索，可以筛选搜索类型和发布时间，这样能有效检索。\n\n![image](https://user-images.githubusercontent.com/45314745/171538392-b4abb724-f416-410f-9af0-4e9917ee875b.png)\n\n## 经验分享\n\n百度、谷歌、微信搜一搜这种搜索引擎的技巧就不多说了，相信大家使用的也非常熟练。\n\n不过有时候我们检索数据并不是为了找代码，而是找数据源。\n\n我在近两年遇到的某些数据采集需求，并没有明确的采集目标，数据源需要自己去检索。\n\n比如说找多少年的文献数据、找某国家某地区的企业数据、找一些高端人才数据。\n\n这些内容没有一个明确的数据聚合网站，只能通过搜索引擎去查资源。你需要熟练使用搜索引擎，细心观察，比如可能在小众站点或者暗网中。\n\n这其实已经脱离了爬虫工程师的业务范畴，但是一个合格的开发者也应该具备全网检索的能力，所以大家平时要注重积累，最好是搭建一个自己的备忘录，或者把一些东西记录到博客中。\n"
  },
  {
    "path": "附录(一些经验)/面试之谈.md",
    "content": "## 总结了一些面试经验分享给大家\n\n其实我本身并没有换几次工作，但是参加的面试次数可以称得上是不胜枚举，因为只想找一个自己喜欢的工作环境和生活节奏，所以会给自己获取更多的选择。\n\n建议大家每年参与几次面试或者旁听他人面试，可以看一看最新的行业发展和岗位需求，以致于更好的提升自己。\n\n\n### 面试前你需要提前准备好：\n- 一份赏心悦目的简历。\n- 一个内容丰富的博客。\n- 一些体现技术的项目。\n- 一段清晰的自我介绍。\n\n\n\n```diff\n+ 现在技术类职位需求很多，但是求职者的数量更多，记得当年一个HR让我把简历发私人邮箱，他说一天内收到的简历超过了某直聘的上限。\n- 如何让HR筛选到你的简历多看两眼是什么重要的，所以简历结构需要清晰明了，能让人一眼就确定是符合岗位需求的人。\n\n+ 个人博客是需要花时间运营的，但也并不是每次都需要长篇大论，只要能记录下来自己的经验或者技术点就好，更多的用途是让自己在以后的复盘中可以快速总结。\n- 当然高质量的个人博客能给面试加更多分，毕竟简历内容有限，技术的知识点也是有限的，当面试官根据你的博客提问时，想必你能回答的更加得心应手。\n\n+ 之前做过的项目一定要整理清晰，当被问到如何做某项目时，最好能把项目架构、项目开发难点、问题解决方法等流畅地讲出来。\n比如说到采集某APP的数据时，通过逆向分析解决了某些加密或者某种风控。\n在逆向的过程中对该APP的架构也进行了分析，发现该APP采用okhttp请求框架，ffmpeg音视频处理库、robust热更新、bspatch增量更新、某些sdk、某种消息传输协议等。\n这些开源库或者框架我们并不需要去掌握多少，大致知道是什么用途的就可以，这样的项目描述无疑能给面试官增加N点好感度。\n\n+ 一段清晰的自我介绍是很重要的，自我介绍能快速体现出一个人的个人能力和素质水平，而第一印象一旦形成就很难改变。\n所以我们需要简洁明了地介绍自己的履历和最近负责的项目，当然可以提前准备好稿子，在面试前多背两次。\n```\n"
  }
]